Solved

Allowing separate classes to interact

Posted on 2006-11-05
37
305 Views
Last Modified: 2010-03-31
The first question is, is this possible i.e. suppose I had two classes - a male class and a female class running at the same time, and i wanted them to interact, like if a command was issued in the male then a variable would change in the female.

The separate programs would update each other while running at the same time.

If this is possible then what would be the easiest way to do it - please tell me know  where to start researching or give any hints.

I am making a program that demonstrates AI.

Thanks anyone
John
0
Comment
Question by:john8932
  • 20
  • 15
  • 2
37 Comments
 
LVL 24

Expert Comment

by:sciuriware
ID: 17879247
Are you running 2 programs? Then have them communicate through pipes or sockets.
Are you running 2 threads in a single program? Then have them communicate through static data.

Never say "I have 2 classes ... and I want them to interact" :
classes do nothing in JAVA,
it's the methods that 'do' and the variables and objects that are 'done'.

;JOOP!
0
 

Author Comment

by:john8932
ID: 17879476
At the moment a single thread for each program - otherwise too complex and not enough time.

So I need to get the methods in the different classes interacting.

Can you give an example of pipes or sockets please.

Cheers
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17879686
1) Single thread in a JAVA program is impossible; even a "Hello World" program has already 7 threads. Just for understanding.
2) Methods are always in classes and the interaction is on the data level.
3) The simplest way to create pipes is to have program A start program B:

In A:
...........................
         Process p = Runtime.getRuntime().exec(commandVector, null, dir); // commandVector is a String[] describing B.
         inputStream is = p.getInputStream(); // You can get standard input from B, use a thread!
         outputStream is = p.getOutputStream(); // You can write standard to B's standard input, use a thread!
The effeciency depends on your needs. Highest is unformatted binary data in defined chunks,
that's a matter of smart programming.

;JOOP!
0
 
LVL 1

Expert Comment

by:Sabora
ID: 17879795
produce in one app a ServerSocket, in the other a normal Socket. So you can make them communicate:

This is a little programm that illustrates how to use the sockets (you have to start it twice!):

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.ConnectException;
import java.net.ServerSocket;
import java.net.Socket;

public class Test {
   public static void main(String[] args) throws Exception {
      Socket socket;
      String output;
      try {
         socket = new Socket("localhost", 1977); // throws Exception below, if no connection is possible
         output = "Test client ";
      } catch(ConnectException ce) {
         // no connection was possible, so make it server
         socket = new ServerSocket(1977).accept();

         output = "Test server ";
      }
      BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      for(int num = 0; num < 16; num++) {
         socket.getOutputStream().write((output + num + "\n").getBytes());
         socket.getOutputStream().flush();
         String outputStr = in.readLine();
         System.out.println(outputStr);
      }
      socket.close();
   }
}
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17879831
Agreed, but use threads to avoid deadlocks.

;JOOP!
0
 
LVL 1

Expert Comment

by:Sabora
ID: 17879891
Ok, this time with ALL the comments...

public class Test {
   public static void main(String[] args) throws Exception {
      Socket socket;
      String output;
      try {
         socket = new Socket("localhost", 1977); // throws Exception below, if no connection is possible
         output = "Test client ";
      } catch(ConnectException ce) {
         // no connection was possible, so make app server
         socket = new ServerSocket(1977).accept();
         // be aware that accept is blocking!
         output = "Test server ";
      }
      // for convenience use...
      BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      for(int num = 0; num < 16; num++) {
         socket.getOutputStream().write((output + num + "\n").getBytes());
         // makes sure that we immediately send information
         // this is useful using files, seems not be necessary using sockets
         // socket.getOutputStream().flush();
         
         // this is blocking, too!
         System.out.println(in.readLine());
      }
      socket.close();
   }
}
0
 

Author Comment

by:john8932
ID: 17881034
Ok thanks for the replies.

I think the sockets idea will be the easiest to implement.

I will do it by sending strings:
 -If string equals update male then update male and vice versa, etc etc.

Like so:

public void connect(String update) throws Exception
    {
          Socket socket;
          String output;
          try
          {
                  socket = new Socket("localhost", 1977); // throws Exception below, if no connection is possible
                output = "Test client ";
          }
          catch(ConnectException ce)
          {
               // no connection was possible, so make app server
               socket = new ServerSocket(1977).accept();
               // be aware that accept is blocking!
               output = "Test server ";
              }
              // for convenience use...

              BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            for(int num = 0; num < 2; num++)
            {
                String command = socket.getInputStream();

                  if(command.equals("updateMale"))
                  {
                        malePartnerExercise++;
                        malePartnerFood--;
                        malePartnerBoredom++;
                  }

                  if(update.equals("updateFemale"))
                  {
                          socket.getOutputStream().write(("updateFemale").getBytes());
                  }
            }
              socket.close();
    }

At the moment it does not compile because of this line:

String command = socket.getInputStream();

I need to convert the string from a socketinput- please tell me how I can do this.

Cheers
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17881478
InputStream command = socket.getInputStream(); // Is not a String.

;JOOP!
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17881515
replace it by:

String command =  in.readLine();

;JOOP!
0
 

Author Comment

by:john8932
ID: 17882793
Ok I think im getting somewhere now, cheers.

I have not got them mating yet although once I get the connect() method worknig at the right times they will.

Basicly for them to mate the connect method should be running in each program/class.

Any ideas on how to do this?

Maybe when a "mate" command is issued it tells the connect() method in the other program to run therefore a connection is made and they mate i.e. change variables.

Cannot get this going tho.

public void connect(String update) throws Exception
      {
            Socket socket = null;

            try
            {
                System.out.println("Connection made");
                socket = new Socket("localhost", 1977); // throws Exception below, if no connection is possible

                  socket.getOutputStream().write(("connect").getBytes());
            }
            catch(ConnectException ce)
            {
                  System.out.println("No connection made");
                  display(exercise, food, boredom, energy, volatility);
                // no connection was possible, so make app server
                //socket = new ServerSocket(1977).accept();
                // be aware that accept is blocking!
            }
            // for convenience use...

            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            String command = in.readLine();

            if(command.equals("connect"))
            {
                  if(command.equals("updateFemale")) // incoming
                  {
                        System.out.println("Mating");

                        exercise++;
                        food--;
                        boredom++;

                        display(exercise, food, boredom, energy, volatility);
                  }
            }

            if(update.equals("updateMale"))
            {
                  socket.getOutputStream().write(("updateMale").getBytes());
            }

            socket.close();
      }

0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17883071
Create in each a listener thread that reads all incoming messages and stores them in a Vector (thread safe!).
Your other running code (thread?) can then without any problem:
1) see if there is something in the "inbox",
2) take messages out the box, even not in the order that they came in.

;JOOP!
0
 

Author Comment

by:john8932
ID: 17883196
Ok what would this look like:
      Thread backgroundThread = new Thread(new Runnable() // reads all incoming messages and stores them in a Vector
      {
            public void run()
            {
               while(true)
               {
                     try
                     {
                           BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                           command = in.readLine();
                     }
                     catch(Exception e)
                     {
                     }
               }
            }
      });

and then this to call it:

backgroundThread.start();

Whats a vector by the way?

Cheers
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17883313
    Thread backgroundThread = new Thread(new Runnable() // reads all incoming messages and stores them in a Vector
should be:
     Thread backgroundThread = new Thread(new Runnable()) // reads all incoming messages and stores them in a Vector

A Vector is a kind of array / list that automatically extends when you add objects (to the end) and shrinks as you
remove objects (from the head). See the JAVADOC for all details.
It is impossible that a thread filling a Vector and another thread removing from a Vector corrupt the Vector.

Now, move the line:
                      BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
to before the while and add:
                      public Vector commands = new Vector();
before the 'run()', then change:
                       command = in.readLine();
into:
                   String line = in.readLine();
                   if(line == null)
                   {
                         break; // out of the while
                   }
                   commands.add(new String(line + '\n'));
consequently:
                 catch(Exception e)
should be:
                 catch(IOException e)
and please don't ignore it, do something.

finally, after the while loop:
            close(i);

now,
            backgroundThread.commands
is a Vector that contains all lines read, unless some already were processed.

This is not exactly the way I did it, but it is a start.


;JOOP!
0
 

Author Comment

by:john8932
ID: 17883406
Okay cool, like this?

Thread backgroundThread = new Thread(new Runnable() // reads all incoming messages and stores them in a Vector
      {
            public Vector commands = new Vector();
            public void run()
            {
               BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

               while(true)
               {
                     try
                     {
                           String line = in.readLine();
                           if(line == null)
                           {
                                 break; // out of the while
                           }
                   commands.add(new String(line + '\n'));
                     }
                     catch(IOException e)
                     {
                     }
               }
               close(i);
            }
      });
Whats that I for please?
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17883451
Still:
    Thread backgroundThread = new Thread(new Runnable() // reads all incoming messages and stores them in a Vector
should be:
     Thread backgroundThread = new Thread(new Runnable()) // reads all incoming messages and stores them in a Vector
                                                                                        /\
and:
                 catch(IOException e)
                  {                                     // No code?
                  }
correction:
             close(i);
should be of course:
             close(in);


;JOOP!
0
 

Author Comment

by:john8932
ID: 17883530
           catch(IOException e)
                  {
System.out.println("IO error")
                  }
             }
             close(i);
          }
     });
     /\

This is the ending/closing bracket.

Does not like the close(in); i.e. does not compile
AIPet.java:364: cannot find symbol
symbol: method close(java.io.BufferedReader)
                          close(in);

Please tell me how I need to use the vector and that should be it.

0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17883585
Sorry, sorry it's getting late here.

Your }); is correct.

    close(in);  must be    in.close();

Btw.: prepare that:
                   System.out.println("IO error");         // don't forget the ;
is not seen unless debugged in ECLIPSE,
so make it do something better in the end.

A remark:
I never use this kind of "spontaneous" classes, because it's too difficult
to access their data and methods from another thread.
So, I place the code in a real, separate class and I make the reference 'global'.
All my globals are always blank (package access) statics in a class called <myprogram>Adm
A usefull habit.

;JOOP!
0
 

Author Comment

by:john8932
ID: 17883656
Dont worry about it :)

And I changed it to in.close();

Ive made the variables global i.e. attiributes.

      Thread backgroundThread = new Thread(new Runnable() // reads all incoming messages and stores them in a Vector
      {
            public Vector commands = new Vector();
            public void run()
            {
               BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

               while(true)
               {
                     try
                     {
                           String line = in.readLine();
                           if(line == null)
                           {
                                 break; // out of the while
                           }
                   commands.add(new String(line + '\n'));
                     }
                     catch(IOException ioe)
                     {
                           System.err.println("Caught Exception: " + ioe.getMessage());
                     }
               }
               in.close();      
            }
      });

Still not compiling though.

Saying I need to:

AIPet.java:344: unreported exception java.io.IOException; must be caught or declared to be thrown
                   BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()
                                                                                                     ^
AIPet.java:362: unreported exception java.io.IOException; must be caught or declared to be thrown
                   in.close();
                           ^

Cheers
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:john8932
ID: 17883664
Infact could these be global, to?

BufferedReader in

and

public Vector commands = new Vector();
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17884427
Change it to:
// in the data section of your class:

    public static Vector commands = null;

...................

    Thread backgroundThread = new Thread(new Runnable() // reads all incoming messages and stores them in a Vector
     {
          commands = new Vector();
          public void run()
          {
             try
             {
                  BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                  while(true)
                  {
                       String line = in.readLine();
                       if(line == null)
                       {
                            break; // out of the while
                       }
                       commands.add(new String(line + '\n'));
                  }
                  in.close();    
              }
              catch(IOException ioe)
              {
                   System.err.println("Caught Exception: " + ioe.getMessage());
              }
          }
     });

it's better to leave 'in' local.
I would prefer to keep 'commands' inside the thread, but then it should be a separate class
and not, like here, a "last-minute" class.

;JOOP! nearly sleeping.
0
 

Author Comment

by:john8932
ID: 17884566
I made this an attribute:

public static Vector commands = null;

But the compiler is still saying bad things i.e...

AIPet.java:343: <identifier> expected
            commands = new Vector();
                     ^
1 error

0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17884589
That's JAVA 5 stuff, if you are only using String's:

  public static Vector<String> commands = null;

and:

          commands = new Vector<String>();
 
;JOOP!
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17884619
If you don't know what kind of objects you're going to use in such a case:

  public static Vector<Object> commands = null;

and:

          commands = new Vector<Object>();
 
BUT!!!!!!!!!!!!!!!!!!!!! to what ore you going to cast what you remove from the Vector?
That's a thing to remember for later.

YAWN.
;JOOP!
0
 

Author Comment

by:john8932
ID: 17884640
Nope, still the same error.

Im just wondering when we do get the program compiling, how do we use the commands vector?

Cheers
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17884687
It compiles with me,

but maybe you didn't add:

import java.util.Vector;

at the top of the page ....


;JOOP!
0
 

Author Comment

by:john8932
ID: 17884976
Nope import java.util.Vector; is there.

This is annoying - One little compile error when we are so almost there.

Please can I see what you are compiling so i can compare.
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17887244
Again, what's exactly the error message. I never compile from the commandline
but by ECLIPSE.

;JOOP!
0
 

Author Comment

by:john8932
ID: 17889233
AIPet.java:344: <identifier> expected
            commands = new Vector<Object>();
                             ^
1 error
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17889582
where is:
  public static Vector<Object> commands = null;


Can you check this out: this little snippet compiles correctly:

// BEGIN OF SNIPPET
import java.util.Vector;

/**
 * This class serves as a testbank for bug derobation and doesn't rely on own packages.
 */

public class Bugs
{
   public static Vector<String> commands = null;
   /**
    * Program entry point.
    *
    * @param commandLine program command line vector.
    */
   public static void main(String[] commandLine)
   {
      String h = "Hi";
     
      commands = new Vector<String>();
      commands.add(h);
   }
}
// END OF SNIPPET

;JOOP!
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17889639
Then, suddenly ............ are you using JAVA 5 or JAVA 1.4?
That would turn everything around, then it would be:

// BEGIN OF SNIPPET
import java.util.Vector;

/**
 * This class serves as a testbank for bug derobation and doesn't rely on own packages.
 */

public class Bugs
{
   public static Vector commands = null;
   /**
    * Program entry point.
    *
    * @param commandLine program command line vector.
    */
   public static void main(String[] commandLine)
   {
      String h = "Hi";
     
      commands = new Vector();
      commands.add(h);
   }
}
// END OF SNIPPET

And because of this retrieval would become:

         String results = (String)commands.get(0);

;JOOP!
0
 

Author Comment

by:john8932
ID: 17889729
I do not get an error with the code you sent me.

Maybe I get the error as the:

commands = new Vector<String>();

Is in a thread kind if method - dont know what you call this.

I moved that line to here:

public void run()
          {
                  commands = new Vector<String>();
            
and it compiles fine - is it okay here?

I suppose the last question is: how do I read from a vector i.e. how do I get the connect method carrying out actions according to the vector?

Cheers
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17889813
I already wrote it above, so here is a more complete version:

String result = "";

     if(!commands.isEmpty())
     {
           result = commands.remove(0);  // Take the 1st object out
     }

Now the code should treat "" as a (temporary) end of input.

Depends on how you want to work. You could also "wait" for data:

     while(commands.isEmpty())      // Endless?
     {
           // Sleep some miliseconds
     }
     result = commands.remove(0);  // Always something


;JOOP!
0
 

Author Comment

by:john8932
ID: 17891375
When a vector is added to, does it work like a stack i.e. is the last object added always index 0. So if I added 1 then object index 0 would be 1, if i then add, then object index 0 would be 2 etc etc.

If it is like that I can use this:

command = commands.get(0);

Ok suppose there is a command issued, like this:

command.equals("updateFemale");

It will work at last.

If in the code the while loop in the thread method has break and it breaks, will that thread be ended?

Sorry about my mistake a second ago with the code.

Please tell me what you think.
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17891462
>>> When a vector is added to, does it work like a stack i.e. is the last object added always index 0.
You can see it as a kind of array.
When you add 3 objects to an empty Vector, they get indices 0, 1 and 2

>>>If it is like that I can use this: command = commands.get(0);
No in this case you should remove the first object by  result = commands.remove(0);
while new objects are added at the end.
It is also possible to add, modify or remove objects on any other place if you know the index.
Removing the first object renumbers all other indices.

>>>Ok suppose there is a command issued, like this: command.equals("updateFemale"); It will work at last.
I don't understand this.

>>>If in the code the while loop in the thread method has break and it breaks, will that thread be ended?
No, a thread stops only when 'run()' returns and that's your choice.
If the Vector is part of the Thread object, it will 'live' as long as the Thread object.

By the way, it is probably better to make  Thread backgroundThread  static and to make the Vector
an instance local to the Thread object.
Then you can start another Thread without destroying the Vector as you create a new one.
Now the Vector is static and will be deleted with the creation of a new thread.
It's all the choice of the programmer acc.to the situation that must be mastered.

>>>Sorry about my mistake a second ago with the code.

Who doesn't make mistakes? Be glad you're not building airplanes; a little mistake and .............

;JOOP!
0
 
LVL 24

Accepted Solution

by:
sciuriware earned 125 total points
ID: 17891482
Can you please close this question, it's becoming too long and I have to stop for today.

Bye.
0
 

Author Comment

by:john8932
ID: 17891570
Ok sure.
Cheers for the help
0
 
LVL 24

Expert Comment

by:sciuriware
ID: 17895963
:)
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

After being asked a question last year, I went into one of my moods where I did some research and code just for the fun and learning of it all.  Subsequently, from this journey, I put together this article on "Range Searching Using Visual Basic.NET …
Introduction This article is the second of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers the basic installation and configuration of the test automation tools used by…
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
Viewers will learn about if statements in Java and their use The if statement: The condition required to create an if statement: Variations of if statements: An example using if statements:

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now