My goal is running some process in VirtualMachine using Java. First of all, I have a part of code for create and connect to VB, but i have exception(NullPointer in main Thread) in 21 and 89 lines. I searching some answer to fix this problem, and read that problem look as I haven't Oracle VB. But in my computer i have it , version equals to imported.
So if you have an experience in using this API, or can help me, please, describe in detail how i can fix it. So, my code:
import org.virtualbox_5_1.*;
import org.virtualbox_5_1.ISession;
import org.virtualbox_5_1.IProgress;
import java.util.List;
import java.util.Arrays;
public class Events_5_1 {
static VirtualBoxManager mgr;
static Thread listener;
public static void main(String[] args) {
String vmName = Long.toString(System.currentTimeMillis()); // Берем рандомное значение имени VirtualMachine
System.out.println("Creating VirtualBox instance");
mgr = VirtualBoxManager.createInstance(null);
try {
listener = new EventWorker();
listener.start();
try {
//Создаем пустую машину и сохраняем на диск
IMachine vm = mgr.getVBox().createMachine(null, vmName, null, "Other", null);//тестить , разобраться с параметрами
vm.saveSettings();
mgr.getVBox().registerMachine(vm);
vm = mgr.getVBox().findMachine(vmName);
ISession session = mgr.getSessionObject();
IProgress p = vm.launchVMProcess(session, "headless", null); // Вместо headless - ставим процесс ??
p.waitForCompletion(-1);
try {
if (p.getResultCode() != 0) {
throw new RuntimeException(p.getErrorInfo().getText());
} else {
p = session.getConsole().powerDown();
p.waitForCompletion(-1);
if (p.getResultCode() != 0) {
throw new RuntimeException(p.getErrorInfo().getText());
} else {
}
}
} finally {
session.unlockMachine();
while (!SessionState.Unlocked.equals(vm.getSessionState())) {
try {
System.out.println("Waiting for session unlocked");
Thread.sleep(1000L);
} catch (InterruptedException e) {
System.err.println("Interrupted while vaiting for session unlocked");
}
}
System.out.println("Deleting machine");
vm.deleteConfig(vm.unregister(CleanupMode.DetachAllReturnHardDisksOnly));
}
} finally {
listener.interrupt();
try {
listener.join(5000);
} catch (InterruptedException e) {
System.err.println("Inerrupted while vaiting for EventWorker stop");
}
if (listener.isAlive()) {
System.err.println("Event worked did not stop in a timely fashion");
} else {
System.out.println("event worker stoped");
}
}
} finally {
mgr.disconnect();
mgr.cleanup();
System.out.println("Disconecting from VirtualBox");
}
}
static class EventWorker extends Thread {
IEventListener el;
#Override
public void run() {
System.out.println("EventWorker started");
el = mgr.getVBox().getEventSource().createListener();
//TODO: connect gradle, mvnrepository.com idea connect datasource postgre
List<VBoxEventType> types = Arrays.asList(VBoxEventType.OnSessionStateChanged, VBoxEventType.OnMachineStateChanged,
VBoxEventType.OnMachineRegistered);
mgr.getVBox().getEventSource().registerListener(el, types, false);
try{
while(!isInterrupted()){
mgr.waitForEvents(0);
IEvent rawEvent = mgr.getVBox().getEventSource().getEvent(el , 1000);
if(rawEvent==null) continue;
try{
System.out.println("Got event type "+rawEvent.getType());
if(VBoxEventType.OnSessionStateChanged.equals(rawEvent.getType())){
ISessionStateChangedEvent event = ISessionStateChangedEvent.queryInterface(rawEvent);
System.out.println("Machine "+event.getState()+" for machine "+event.getMachineId());
}
if(VBoxEventType.OnMachineRegistered.equals((rawEvent.getType()))){
IMachineRegisteredEvent event = IMachineRegisteredEvent.queryInterface(rawEvent);
System.out.println("Machine "+event.getMachineId()+" has been "+(event.getRegistered() ? "registered":"unregistered"));
}
if(VBoxEventType.OnMachineStateChanged.equals(rawEvent.getType())){
IMachineStateChangedEvent event = IMachineStateChangedEvent.queryInterface(rawEvent);
System.out.println("Machine "+event.getMachineId()+" state changed to "+event.getState());
}
}finally {
mgr.getVBox().getEventSource().eventProcessed(el,rawEvent);
}
}
}catch(Throwable t){
t.printStackTrace();
}finally {
mgr.getVBox().getEventSource().unregisterListener(el);
System.out.println("EventWorker finished");
}
}
}
}
If you are to plain copy/paste adapt my code, you should at least stick to the code structure and flow.
You've moved code around for some reasons and variables are not initialized timely, which is why you get NPEs.
Here is the working version for VirtualBox 5.1.x
Related
I read a couple questions related to pausing main and both gave answers I didn't understand, and frankly I don't think are applicable.
I have a JFrame that makes use of a database I'm setting up in my driver class.
The JFrame will launch and the window opens; however when I try to make use of the database it fails; because back in main the program just keeps running and shuts down the connection, and closes it.
I tried just removing the connection.close() code just to see if my database methods work in the JFrame, and they do, so I just need to learn how to halt main while my JFrame is running.
public static void main(String[] args) {
File dbPropertiesFile = new File(DbConstants.DB_PROPERTIES_FILENAME);
if (!dbPropertiesFile.exists()) {
showUsage();
System.exit(-1);
}
try {
new Lab9(dbPropertiesFile).run(args);
} catch (Exception e) {
LOG.error(e.getMessage());
e.printStackTrace();
} finally {
shutdown();
}
}
private static void configureLogging() {
ConfigurationSource source;
try {
source = new ConfigurationSource(new FileInputStream(LOG4J_CONFIG_FILENAME));
Configurator.initialize(null, source);
} catch (IOException e) {
System.out.println(
String.format("Can't find the log4j logging configuration file %s.", LOG4J_CONFIG_FILENAME));
}
}
private static void shutdown() {
LOG.info("Shutting down");
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
LOG.error(e.getMessage());
e.printStackTrace();
}
}
}
private static void showUsage() {
System.err.println(
String.format("Program cannot start because %s cannot be found.", DbConstants.DB_PROPERTIES_FILENAME));
}
private Lab9(File file) throws IOException {
properties = new Properties();
properties.load(new FileInputStream(file));
database = new Database(properties);
}
/**
* Where the computer start making a lot of noise.
*
* #param args
* #throws Exception
*/
private void run(String[] args) throws Exception {
LOG.info("Running");
LOG.info("Loading database properties from: " + DbConstants.DB_PROPERTIES_FILENAME + ".");
LOG.info(properties.getProperty("db.driver"));
LOG.info("Driver loaded");
LOG.info("DB URL = " + properties.getProperty("db.url"));
LOG.info("DB USER = " + properties.getProperty("db.user"));
LOG.info("DB PASSWORD = " + properties.getProperty("db.password"));
connect();
Statement statement = connection.createStatement();
try {
// If the user enters the -drop switch
if (args[0].equalsIgnoreCase(DROP_COMMAND)) {
LOG.info("Table " + CustomerDao.TABLE_NAME + "is being DROPPED!");
customerDao.drop();
LOG.info("Table has been DROPPED!");
}
// Check to see if the table is already made; if its not then make it, and fill
// it.
if (Database.tableExists(CustomerDao.TABLE_NAME) == false) {
createTables(statement);
LOG.info("Created the table: " + CustomerDao.TABLE_NAME + ".");
LOG.info("Inserting Customer objects into table: " + CustomerDao.TABLE_NAME + ".");
insertCustomers();
LOG.info("Inserted customer info into table from file: [" + CUSTOMER_DATA + "].");
}
createUI();
// I NEED MAIN
// TO STOP
// AROUND HERE!
}catch(SQLException e){
e.printStackTrace();
LOG.error(e.getMessage());
}finally{
connection.close();
}
}
public static void createUI() {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
DatabaseControlFrame frame = new DatabaseControlFrame(customerDao);
frame.setVisible(true);
// OR MAYBE I NEED MAIN
// TO STOP
// AROUND HERE!
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void connect() throws SQLException {
connection = database.getConnection();
customerDao = new CustomerDao(database);
}
}
Any ideas? I tried using a while(frame.isVisilbe()){ wait(600) }; But the compiler had a spas when I tried to use wait().
You'll note I'm passing a customerDAO object to my JFrame constructor; but I'm beginning to wonder could I make a connection inside the JFrame so that when main's connection closes; my JFrame's doesn't? Is that a good idea? Is that even possible I'm not super SQL savvy I'm going to need to study up on it more.
You could use Thread.sleep() - I've found that useful with JFrame before, though I'm not 100% sure it would fit what you're looking for. If you want it to wait indefinitely, put it in a while loop:
while(//condition)
{
Thread.sleep(500); //pauses for .5 sec, then loops back to check condition
}
JFrame event handler runs on a different thread than main thread, so you need to shutdown on that thread.
Here is a example, Using JDBC with GUI API.
This example call connection.close() on received window-closing-event.
public class MyFrame extends JFrame {
public MyFrame() {
// ...
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(final WindowEvent e) {
shutdown();
System.exit(0);
}
});
}
// ...
}
I am trying a program with many phidget rfid readers. This test code works fine and I can load up all the readers and have it worked.
Vector phidgetList = manager.getPhidgets();
Enumeration phidgetListEnum = phidgetList.elements();
int count=phidgets.size();
while(phidgetListEnum.hasMoreElements()) {
Phidget phidgetElement = (Phidget) phidgetListEnum
.nextElement();
if (!phidgets.containsKey(phidgetElement.getSerialNumber())) {
RFIDTracking rfi = (RFIDTracking) ct.getTracking("rfid")
.clone();
rfi.setName("rfid clone " + count++);
rfi.detect();
rfi.setCode(phidgetElement.getSerialNumber());
phidgets.put(phidgetElement.getSerialNumber(), rfi);
Thread t = new Thread(rfi);
t.start();
}
}
The problem is when I tried to detect the new readers attached or detached from the system. I used this code
Manager manager;
manager = new Manager();
try {
manager.addAttachListener(new AttachListener() {
public void attached(AttachEvent ae)
{
try
{
System.out.println("attached" + ((RFIDPhidget)ae.getSource()).getSerialNumber());
}
catch (PhidgetException ex) { }
}
});
manager.open();
} catch (PhidgetException exception) {
System.err.println(exception.getErrorNumber()+ exception.getDescription());
}
// Allow the Phidgets time to attach
Thread.sleep(1000);
This code could not detect any reader attachment. I found there is no waitForAttachment(time) in the manager. May I know how to solve this. Thank you in advanced
It's Phidget, but not RFIDPhidget. There is no WaitForAttachment in the manager class because it is not necessary. The previous code works fine, but the wait time must be a little bit longer and the program won't terminate before something is attached.
Manager manager;
manager = new Manager();
try {
manager.addAttachListener(new AttachListener() {
public void attached(AttachEvent ae)
{
try
{
System.out.println("attached" + ((Phidget)ae.getSource()).getSerialNumber());
} catch (PhidgetException ex) { }
}
});
manager.open();
} catch (PhidgetException exception) {
System.err.println(exception.getErrorNumber()+ exception.getDescription());
}
// Allow the Phidgets time to attach
Thread.sleep(1000);
I'm trying to implement a mechanism that deletes cached files when the objects that hold them die, and decided to use PhantomReferences to get notified on garbage collection of an object. The problem is I keep experiencing weird behavior of the ReferenceQueue. When I change something in my code it suddenly doesn't fetch objects anymore. So I tried to make this example for testing, and ran into the same problem:
public class DeathNotificationObject {
private static ReferenceQueue<DeathNotificationObject>
refQueue = new ReferenceQueue<DeathNotificationObject>();
static {
Thread deathThread = new Thread("Death notification") {
#Override
public void run() {
try {
while (true) {
refQueue.remove();
System.out.println("I'm dying!");
}
} catch (Throwable t) {
t.printStackTrace();
}
}
};
deathThread.setDaemon(true);
deathThread.start();
}
public DeathNotificationObject() {
System.out.println("I'm born.");
new PhantomReference<DeathNotificationObject>(this, refQueue);
}
public static void main(String[] args) {
for (int i = 0 ; i < 10 ; i++) {
new DeathNotificationObject();
}
try {
System.gc();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The output is:
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
Needless to say, changing the sleep time, calling gc multiple times etc. didn't work.
UPDATE
As suggested, I called Reference.enqueue() of my reference, which solved the problem.
The weird thing, is that I have some code that works perfectly (just tested it), although it never calls enqueue. Is it possible that putting the Reference into a Map somehow magically enqueued the reference?
public class ElementCachedImage {
private static Map<PhantomReference<ElementCachedImage>, File>
refMap = new HashMap<PhantomReference<ElementCachedImage>, File>();
private static ReferenceQueue<ElementCachedImage>
refQue = new ReferenceQueue<ElementCachedImage>();
static {
Thread cleanUpThread = new Thread("Image Temporary Files cleanup") {
#Override
public void run() {
try {
while (true) {
Reference<? extends ElementCachedImage> phanRef =
refQue.remove();
File f = refMap.remove(phanRef);
Calendar c = Calendar.getInstance();
c.setTimeInMillis(f.lastModified());
_log.debug("Deleting unused file: " + f + " created at " + c.getTime());
f.delete();
}
} catch (Throwable t) {
_log.error(t);
}
}
};
cleanUpThread.setDaemon(true);
cleanUpThread.start();
}
ImageWrapper img = null;
private static Logger _log = Logger.getLogger(ElementCachedImage.class);
public boolean copyToFile(File dest) {
try {
FileUtils.copyFile(img.getFile(), dest);
} catch (IOException e) {
_log.error(e);
return false;
}
return true;
}
public ElementCachedImage(BufferedImage bi) {
if (bi == null) throw new NullPointerException();
img = new ImageWrapper(bi);
PhantomReference<ElementCachedImage> pref =
new PhantomReference<ElementCachedImage>(this, refQue);
refMap.put(pref, img.getFile());
new Thread("Save image to file") {
#Override
public void run() {
synchronized(ElementCachedImage.this) {
if (img != null) {
img.saveToFile();
img.getFile().deleteOnExit();
}
}
}
}.start();
}
}
Some filtered output:
2013-08-05 22:35:01,932 DEBUG Save image to file: <>\AppData\Local\Temp\tmp7..0.PNG
2013-08-05 22:35:03,379 DEBUG Deleting unused file: <>\AppData\Local\Temp\tmp7..0.PNG created at Mon Aug 05 22:35:02 IDT 2013
The answer is, that in your example the PhantomReference itself is unreachable and hence garbage collected before the referred object itself is garbage collected. So at the time the object is GCed there is no more Reference and the GC does not know that it should enqueue something somewhere.
This of course is some kind of head-to-head race :-)
This also explains (without looking to deep into your new code) why putting the reference into some reachable collection makes the example work.
Just for reference (pun intended) here is a modified version of your first example which works (on my machine :-) I just added a set holding all references.
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashSet;
import java.util.Set;
public class DeathNotificationObject {
private static ReferenceQueue<DeathNotificationObject> refQueue = new ReferenceQueue<DeathNotificationObject>();
private static Set<Reference<DeathNotificationObject>> refs = new HashSet<>();
static {
Thread deathThread = new Thread("Death notification") {
#Override
public void run() {
try {
while (true) {
Reference<? extends DeathNotificationObject> ref = refQueue.remove();
refs.remove(ref);
System.out.println("I'm dying!");
}
} catch (Throwable t) {
t.printStackTrace();
}
}
};
deathThread.setDaemon(true);
deathThread.start();
}
public DeathNotificationObject() {
System.out.println("I'm born.");
PhantomReference<DeathNotificationObject> ref = new PhantomReference<DeathNotificationObject>(this, refQueue);
refs.add(ref);
}
public static void main(String[] args) {
for (int i = 0 ; i < 10 ; i++) {
new DeathNotificationObject();
}
try {
System.gc();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Update
Calling enqueue by hand is possible in your example but not in real code. it gives plain wrong result. Let me show by calling enqueue in the constructor and using another main:
public DeathNotificationObject() {
System.out.println("I'm born.");
PhantomReference<DeathNotificationObject> ref = new PhantomReference<DeathNotificationObject>(this, refQueue);
ref.enqueue();
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0 ; i < 5 ; i++) {
DeathNotificationObject item = new DeathNotificationObject();
System.out.println("working with item "+item);
Thread.sleep(1000);
System.out.println("stopped working with item "+item);
// simulate release item
item = null;
}
try {
System.gc();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The output will be like this:
I'm born.
I'm dying!
working with item DeathNotificationObject#6908b095
stopped working with item DeathNotificationObject#6908b095
Which means that whatever you wanted to do with the reference queue would be done when the item is still alive.
I'm trying to start a JMXConnectorServer for management and debug purposes. But I don't want this service to prevent application from exiting normally when the last non-daemon thread is terminated.
In other words, I want the following program to terminate immediately:
public class Main {
public static void main(final String[] args) throws IOException {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
JMXServiceURL jmxUrl = new JMXServiceURL("rmi", null, 0);
JMXConnectorServer connectorServer =
JMXConnectorServerFactory.newJMXConnectorServer(jmxUrl, null, mbs);
connectorServer.start();
}
}
I play with similar issue and wrote this class:
public final class HardDaemonizer extends Thread {
private final Runnable target;
private final String newThreadName;
public HardDaemonizer(Runnable target, String name, String newThreadName) {
super(name == null ? "Daemonizer" : name);
setDaemon(true);
this.target = target;
this.newThreadName = newThreadName;
}
#Override
public void run() {
try {
List<Thread> tb = getSubThreads();
target.run();
List<Thread> ta = new java.util.ArrayList<>(getSubThreads());
ta.removeAll(tb);
for (Thread thread : ta) {
thread.setName(newThreadName);
}
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException ex) {
Logger.getLogger(HardDaemonizer.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static Thread daemonize(String daemonizerName, String newThreadName, Runnable target) {
HardDaemonizer daemonizer = new HardDaemonizer(target, daemonizerName, newThreadName);
daemonizer.start();
return daemonizer;
}
private static List<Thread> getSubThreads() {
ThreadGroup group = Thread.currentThread().getThreadGroup().getParent();
Thread[] threads = new Thread[group.activeCount()];
group.enumerate(threads);
return java.util.Arrays.asList(threads);
}
}
You can use it in this way:
HardDaemonizer.daemonize(null, "ConnectorServer", new Runnable(){
#Override
public void run() {
try {
connectorServer.start();
} catch (IOException ex) {
Logger.getLogger(Ralph.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
Be careful - it's tricky!
EDIT
Agh... It's not solution for you. It hard-daemonize connector thread only and this thread will be killed when jvm stops. Additionaly you can customize name of this thread.
Alternatively you can add flag completed and sleep in loop in daemonize method until connector server start up.
SIMPLIFIED
This is simplified daemonizer without tricky thread renaming:
public abstract class Daemonizer<T> extends Thread {
private final T target;
private boolean completed = false;
private Exception cause = null;
public Daemonizer(T target) {
super(Daemonizer.class.getSimpleName());
setDaemon(true);
this.target = target;
}
#Override
public void run() {
try {
act(target);
} catch (Exception ex) {
cause = ex;
}
completed = true;
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException ex) {
java.util.logging.Logger.getLogger(Daemonizer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
}
public abstract void act(final T target) throws Exception;
public static void daemonize(Daemonizer daemonizer) throws Exception {
daemonizer.start();
while (!daemonizer.completed) {
Thread.sleep(50);
}
if (daemonizer.cause != null) {
throw daemonizer.cause;
}
}
}
Usage:
Daemonizer.daemonize(new Daemonizer<JMXConnectorServer>(server) {
#Override
public void act(JMXConnectorServer server) throws Exception {
server.start();
}
});
Yeah, you will need to so a connectorServer.stop(); at some point.
Edit:
In reading your comments, it sounds like you should do something like:
connectorServer.start();
try {
// create thread-pool
ExecutorService threadPool = Executors...
// submit jobs to the thread-pool
...
threadPool.shutdown();
// wait for the submitted jobs to finish
threadPool.awaitTermination(Long.MAX_LONG, TimeUnit.SECONDS);
} finally {
connectorServer.stop();
}
#Nicholas' idea of the shutdown hook is a good one. Typically, however, I had my main thread wait on some sort of variable that is set from a shutdown() JMX operation. Something like:
public CountDownLatch shutdownLatch = new CountDownLatch(1);
...
// in main
connectorServer.start();
try {
// do the main-thread stuff
shutdownLatch.await();
} finally {
connectorServer.stop();
}
// in some JMX exposed operation
public void shutdown() {
Main.shutdownLatch.countDown();
}
As an aside, you could use my SimpleJMX package to manage your JMX server for you.
JmxServer jmxServer = new JmxServer(8000);
jmxServer.start();
try {
// register our lookupCache object defined below
jmxServer.register(lookupCache);
jmxServer.register(someOtherObject);
} finally {
jmxServer.stop();
}
From my experience, the JMXConnectorServer is only running in a user thread when you create it explicitly.
If you instead configure RMI access for the platform MBean server via system properties, the implicitly created JMX connector server will run as daemon process and not prevent the JMV shutdown. To do this, your code would shrink to the following
public class Main {
public static void main(final String[] args) throws IOException {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
}
}
but you'll need to set the following system properties:
-Dcom.sun.management.jmxremote.port=1919
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
You could add a JVM Shutdown Hook to stop the connector server.
===== UPDATE =====
Not sure why your shutdown hook doesn't work. Perhaps you can supply your sample code. Here's an example:
public static void main(String[] args) {
try {
log("Creating Connector Server");
final JMXConnectorServer jcs = JMXConnectorServerFactory.newJMXConnectorServer(new JMXServiceURL("rmi", "localhost", 12387), null, ManagementFactory.getPlatformMBeanServer());
Thread jcsStopper = new Thread("JCS-Stopper") {
public void run() {
if(jcs.isActive()) {
try {
jcs.stop();
log("Connector Server Stopped");
} catch (Exception e) {
log("Failed to stop JCS");
e.printStackTrace();
}
}
}
};
jcsStopper.setDaemon(false);
Runtime.getRuntime().addShutdownHook(jcsStopper);
log("Registered Server Stop Task");
jcs.start();
log("Server Started");
Thread.sleep(3000);
System.exit(0);
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
}
Output is:
[main]:Creating Connector Server
[main]:Registered Server Stop Task
[main]:Server Started
[JCS-Stopper]:Connector Server Stopped
String port = getProperty("com.sun.management.jmxremote.port");
if (port == null) {
port = String.valueOf(getAvailablePort());
System.setProperty("com.sun.management.jmxremote.port", port);
System.setProperty("com.sun.management.jmxremote.ssl", "false");
System.setProperty("com.sun.management.jmxremote.authenticate", "false");
sun.management.Agent.startAgent();
}
log.info(InetAddress.getLocalHost().getCanonicalHostName() + ":" + port);
This pertains to my earlier post "http://stackoverflow.com/questions/8788825/linux-udp-server-unreachable-from-window-7", which has been solved. Now I am moving to my original job of connecting AVD to Linux server.
I am using the following code for connecting to the server
import java.net.*;
class UDPClient {
public final static int DesitnationPort = 9999;
private int mCounter;
private DatagramSocket mClientSocket;
private InetAddress mServerIPAddress;
private byte[] mDataBuffer;
private DatagramPacket mSendPacket;
private DatagramPacket mReceivePacket;
//Constructor
public UDPClient() {
//Time to make the private data good one
mCounter =1;
try {
mServerIPAddress = InetAddress.getByName("192.168.2.2");
}
catch(UnknownHostException e)
{
System.out.println("Host cannot be resolved :( ");
}
System.out.println("Host has been resolved The IP is valid one ");
try {
mClientSocket = new DatagramSocket();
}
catch(SocketException e)
{
System.out.println("Socket could not be created :( ==> " + e.getMessage());
}
System.out.println("Socket has been created ");
String temp = "This is from the Client == To my Dear Sever :) counter = " + mCounter;
mDataBuffer = temp.getBytes();
mSendPacket = new DatagramPacket(mDataBuffer, mDataBuffer.length, mServerIPAddress, DesitnationPort);
System.out.println("Datagram has been made now ");
System.out.println("Data ==>"+ mSendPacket.getData());
System.out.println("Data ==>"+ mSendPacket.getPort());
System.out.println("Data ==>"+ mSendPacket.getSocketAddress());
System.out.println("Data ==>"+ mSendPacket.getLength());
}
public void SendDataToServer(){
try {
if(!mClientSocket.isClosed()) {
String temp = "This is from the Client == To my Dear Sever :) counter = " + mCounter;
mDataBuffer = temp.getBytes();
mSendPacket = new DatagramPacket(mDataBuffer, mDataBuffer.length, mServerIPAddress, DesitnationPort);
mClientSocket.send(mSendPacket);
System.out.println("Send the packet");
mCounter++;
}
else {
System.out.println("Socket is closed");
}
}
catch(Exception e)
{
System.out.println("Could not send the data :( ==> " + e.getMessage());
}
}
public void ReceiveDataFromServer() {
byte[] tembuff = new byte[1024];
mReceivePacket = new DatagramPacket(tembuff, tembuff.length);
try {
if(!mClientSocket.isClosed()) {
mClientSocket.receive(mReceivePacket);
}
else {
System.out.println("Socket is closed");
}
}
catch(Exception e)
{
System.out.println("Could not Receive the data :( ");
return;
}
String data = new String(mReceivePacket.getData());
System.out.println(" Received the Data => " + data);
}
}
This code works well when I simply use the class in java program like this :-
class TryingWithClient {
public static void main(String a[]) {
UDPClient mClient = new UDPClient();
while(true) {
System.out.println("While Starting");
mClient.SendDataToServer();
mClient.ReceiveDataFromServer();
}
}
}
When I use the same code in AVD project I get a Null pointer exception at the following line :-
public void SendDataToServer(){
try {
if(!mClientSocket.isClosed()){ //<==# this call Null exception occurs
After browsing internet & android development sites I came to conclusion that I am missing the GMS / GPS functionality which I added to my AVD. Still I am unable to get any clue about this.
Here is my code which calls the above UDPClient.
public class StreamingProjectActivity extends Activity {
/** Called when the activity is first created. */
//All buttons
//private static final String LOG_TAG = "StreamingTest";
private StreamButton mStreamButton = null;
private UDPClient mClient= null;
class StreamButton extends Button {
boolean mStartStreaming = true;
OnClickListener clicker = new OnClickListener() {
public void onClick(View v) {
onStream(mStartStreaming);
if (mStartStreaming) {
setText("Stop Streaming");
} else {
setText("Start recording");
}
mStartStreaming = !mStartStreaming;
}
};
public StreamButton(Context ctx) {
super(ctx);
setText("Start Streaming");
setOnClickListener(clicker);
}
}//class StreamButton Ends
#Override
public void onCreate(Bundle icicle) {
try {
mClient = new UDPClient();
System.out.println("==========> Client created sucessfully :) <====== ");
super.onCreate(icicle);
LinearLayout ll = new LinearLayout(this);
mStreamButton = new StreamButton(this);
ll.addView(mStreamButton,
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
0));
setContentView(ll);
System.out.println("Trying Step 2 now ");
}
catch(Exception e)
{
System.out.println("Activity could not be launched :( ");
}
}
//public StreamingTest()
public StreamingProjectActivity(){
System.out.println("Constructor ====>");
System.out.println("Constructor <====");
}//Constructor
private void onStream(boolean start) {
if (start)
{
mClient.SendDataToServer();
mClient.ReceiveDataFromServer();
try
{
Thread.sleep(4000);
}catch (InterruptedException ie)
{
System.out.println(ie.getMessage());
}
}
}//onStream
}
Kindly help.
Ok, first of all: never ever print a catched exception with System.out.println("some msg " + e.getMessage()); Please use Log.e(TAG, "my message", e); for that. So you will actually see a stack trace.
Second: I bet that this code throws an error (check if you see the print in your LogCat output):
try {
mClientSocket = new DatagramSocket();
} catch(SocketException e) {
System.out.println("Socket could not be created :( ==> " + e.getMessage());
}
That is the only reason that mClientSocket still might be null. As this call might go wrong, you should consider checking for null before you check if the socket is closed.
The problem in my earlier solution was that I was mixing the GUI & network operations in the same thread which is called "StricMode.ThreadPolicy" (although, my problem is only part of what is mentioned in the jargon).
I was getting these exceptions "android.os.NetworkOnMainThreadException & android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099) " which I could make out only after I applied WarrenFaith's suggestion (Thanks Warren).
These are thrown only on violation of "StricMode".
Solution : Simply separate the UI work from the network. I had to write the following code for this :
enum ClientThreadStates {
eUndefined,
eStopped,
eRunning,
eIdle,
eSendToServer,
eReadFromServer
}
public class ClientThread extends Thread {
private UDPClient mClient= null;
private ClientThreadStates mStateOfTheThread = ClientThreadStates.eUndefined;
private static String mLOG_TAG;
public ClientThread(String s){
mLOG_TAG = s;
mStateOfTheThread = ClientThreadStates.eStopped;
mClient = new UDPClient(s);
start();
}//constructor
public void SetState(ClientThreadStates paramState) {
mStateOfTheThread = paramState;
}
public ClientThreadStates GetState() {
return mStateOfTheThread;
}
private void Action(ClientThreadStates s) {
synchronized(s) {
switch(mStateOfTheThread) {
case eRunning: //fall
case eIdle: break;
case eSendToServer: mClient.SendDataToServer(); break;
case eReadFromServer: mClient.ReceiveDataFromServer(); break;
}
try {
mStateOfTheThread.wait();
}
catch( InterruptedException e ){
Log.e(mLOG_TAG, "Got Exception at wait <==", e);
}
}
}
public void run() {
mStateOfTheThread = ClientThreadStates.eRunning;
System.out.println("In Thread.run .. The State is " + mStateOfTheThread);
while(ClientThreadStates.eStopped.compareTo(mStateOfTheThread) < 0){ //state >stopped
Action(mStateOfTheThread);
}//while
}//run
}//class ClientThread
Finally synchronize on the two threads on the state like this :
private void onStream(boolean start) {
ClientThreadStates State = mClientThread.GetState();
synchronized(State) {
if (start) {
mClientThread.SetState(ClientThreadStates.eSendToServer);
}
else {
mClientThread.SetState(ClientThreadStates.eReadFromServer);
}
try {
State.notify();
}
catch( IllegalMonitorStateException e ) {
Log.e(LOG_TAG, "Got Exception # notify <==", e);
}
}
}//onStream
}//StreamingProjectActivity
Now the code runs perfectly.
Thanks.
Ashutosh