Passing object implementations over file/network instead of data alone - java

I was experimenting on command pattern and one use of it in wikipedia goes like this:
Networking
It is possible to send whole command objects across the network to be executed on the other machines, for example player actions in computer games.
I assume here sending objects means sending data within the fields of the object, right? And not the code within the execute() method?
I was experimenting through serialization & found a behaviour I couldn't explain. Here's the program:
public class Test {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("Commands"))) {
Command command = () -> {
System.out.println("MUHAHA!");
};
outputStream.writeObject(command);
}
try (ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("Commands"))) {
Command command = (Command) inputStream.readObject();
command.execute();
}
}
}
interface Command extends Serializable {
void execute();
}
Upon execution, I get the string MUHAHA!. So, the implementation of the execute() method is being saved in the file. However, if I comment out the first try{} block & then execute, it fails. The Commands file remains from the previous execution, but it fails to read & parse.
I get the following stack trace:
Exception in thread "main" java.io.IOException: unexpected exception type
at java.io.ObjectStreamClass.throwMiscException(Unknown Source)
at java.io.ObjectStreamClass.invokeReadResolve(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at random.Test.main(Test.java:18)
Caused by: java.lang.NoSuchMethodException: random.Test.$deserializeLambda$(java.lang.invoke.SerializedLambda)
at java.lang.Class.getDeclaredMethod(Unknown Source)
at java.lang.invoke.SerializedLambda$1.run(Unknown Source)
at java.lang.invoke.SerializedLambda$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.lang.invoke.SerializedLambda.readResolve(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
... 5 more
The NoSuchMethodException makes some sense to me, but why didn't it come the first time? Is it storing the first class created through lambda in some cache (or the Metaspace)?
In the end, is it possible to send an implementation across? I was hoping in the other end the code of the execute method will be written into some dynamically created Command implementation.

It is not storing the implementation in the file. To show that, separate your code into two classes: one that serializes and one that deserializes, and execute them in different environments where neither has the .class files of the other.

Related

How to choose an AWT-EventQueue thread, when there are several of them

I successfully injected my own Java code in a running Oracle Forms application, using DLL Injection and some jni trickery. (Windows 7, 32 bits, Oracle Forms 11, JRE Java 8)
I am able to traverse the tree of Components and to query and set values in some basic Java objects, such as those from class oracle.forms.ui.VTextField
I am stuck when trying to simulate user click on a oracle.apps.fnd.ui.Button
I tried 2 things :
call the simulatePush method of the AbstractButton class
call the activate method of the PushButton class
(the 2 classes are in the class hierarchy for Button)
Results were identical:
1. At first, it works fine: when the button is a "Search" button, the search is done and the results are displayed.
2. Then, it immediately breaks the application, with a pop-up saying FRM-92100 Your connection to the Server was interrupted.
From there, the Application is hung.
Update:
It seems that the error which cause a disconnection from the Server is:
java.lang.SecurityException: this KeyboardFocusManager is not
installed in the current thread's context at
java.awt.KeyboardFocusManager.checkCurrentKFMSecurity(Unknown Source)
at java.awt.KeyboardFocusManager.getGlobalFocusOwner(Unknown Source)
at
java.awt.KeyboardFocusManager.processSynchronousLightweightTransfer(Unknown
Source) at
sun.awt.windows.WComponentPeer.processSynchronousLightweightTransfer(Native
Method) at sun.awt.windows.WComponentPeer.requestFocus(Unknown
Source) at java.awt.Component.requestFocusHelper(Unknown Source) at
java.awt.Component.requestFocusHelper(Unknown Source) at
java.awt.Component.requestFocus(Unknown Source) at
oracle.forms.handler.UICommon.updateFocus(Unknown Source) at
oracle.forms.handler.UICommon.setFVP(Unknown Source) at
oracle.forms.handler.UICommon.setFVP(Unknown Source) at
oracle.forms.handler.UICommon.onUpdate(Unknown Source) at
oracle.forms.handler.ComponentItem.onUpdate(Unknown Source) at
oracle.forms.handler.JavaContainer.onUpdate(Unknown Source) at
oracle.forms.handler.UICommon.onUpdate(Unknown Source) at
oracle.forms.engine.Runform.onUpdateHandler(Unknown Source) at
oracle.forms.engine.Runform.processMessage(Unknown Source) at
oracle.forms.engine.Runform.processSet(Unknown Source) at
oracle.forms.engine.Runform.onMessageReal(Unknown Source) at
oracle.forms.engine.Runform.onMessage(Unknown Source) at
oracle.forms.engine.Runform.processEventEnd(Unknown Source) at
oracle.ewt.lwAWT.LWComponent.redispatchEvent(Unknown Source) at
oracle.ewt.lwAWT.LWComponent.processEvent(Unknown Source) at
oracle.ewt.button.PushButton.activate(Unknown Source) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at
java.lang.reflect.Method.invoke(Unknown Source) at
CustomAWT.run(CustomAWT.java:34) at
java.awt.event.InvocationEvent.dispatch(Unknown Source) at
java.awt.EventQueue.dispatchEventImpl(Unknown Source) at
java.awt.EventQueue.access$400(Unknown Source) at
java.awt.EventQueue$2.run(Unknown Source) at
java.awt.EventQueue$2.run(Unknown Source) at
java.security.AccessController.doPrivileged(Native Method) at
java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown
Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at
java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown
Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at
java.awt.EventDispatchThread.run(Unknown Source)
My code is here: CustomAWT.run(CustomAWT.java:34) and is called with invokeLater. Problem is probably: when calling the oracle.ewt.button.PushButton.activate method, I am NOT in the right EDT.
Using "List Threads" in the Java Console, I got:
Dump thread list ...
Group main,ac=30,agc=2,pri=10
main,5,alive
traceMsgQueueThread,5,alive,daemon
Timer-0,5,alive
Java Plug-In Pipe Worker Thread (Client-Side),5,alive,daemon
AWT-Shutdown,5,alive
AWT-Windows,6,alive,daemon
AWT-EventQueue-0,6,alive
SysExecutionTheadCreator,5,alive,daemon
CacheMemoryCleanUpThread,5,alive,daemon
CacheCleanUpThread,5,alive,daemon
Browser Side Object Cleanup Thread,5,alive
JVM[id=0]-Heartbeat,5,alive,daemon
Windows Tray Icon Thread,5,alive
Thread-13,5,alive
Group Plugin Thread Group,ac=3,agc=0,pri=10
AWT-EventQueue-1,6,alive
TimerQueue,5,alive,daemon
ConsoleWriterThread,6,alive,daemon
Group http://xxxx.xxxx.xxxxx.xx:8001/OA_JAVA/-threadGroup,ac=13,agc=0,pri=4
Applet 1 LiveConnect Worker Thread,4,alive
AWT-EventQueue-2,4,alive
thread applet-oracle/apps/fnd/formsClient/FormsLauncher.class-1,4,alive
Applet 2 LiveConnect Worker Thread,4,alive
thread applet-oracle.forms.engine.Main-2,4,alive
Forms-StreamMessageReader,4,alive
Forms-StreamMessageWriter,4,alive
HeartBeat,4,alive
Busy indicator,1,alive,daemon
TaskScheduler timer,4,alive
CursorIdler,4,alive
Thread-14,4,alive
Flush Queue,4,alive
Done.
So, there is THREE AWT-EventQueue threads... Question is now: How to query/retrieve the right one, and how to make the Runnable passed to invokeLater to run in the "Good Thread" (I guess that the good one is the last one (AWT-EventQueue-2)
After a lot of experimentation and google searches with keywords like EventQueue and ThreadGroup I have finally found a solution (in the Works For Me category, mind you).
I use the sun.awt.AppContext class. Some documentation and sources here (grepcode.com)
Get a Collection of the running AppContext's using the getAppContexts method.
For each retrieved AppContext, get his ThreadGroup using the getThreadGroup method.
With the ThreadGroup object, Use the getName method.
When the name of the Thread Group starts with the http: address of your Forms Application, retrieve the Object property with key name sun.awt.AppContext.EVENT_QUEUE_KEY, using the get method of AppContext.
The retrieved object is an EventQueue. Create an java.awt.event.InvocationEvent object, passing your Runnable to the CTOR, and use the postEvent method of EventQueue.
Your run method will be executed in the right thread.
Remarks:
This answer is a specific, works for me, solution for an Oracle Forms Application launched via an Internet Explorer link, and running in a java.exe process. In that situation, the 3 Thread Groups are as shown in the question: main, Plugin Thread Group, and http://xxxx.xxxx.xxxxx.xx:8001/OA_JAVA/-threadGroup Your mileage may vary.
If you don't use full reflection, but instead do import sun.awt.AppContext, the compiler may emit warnings in the form warning: sun.awt.AppContext is Sun proprietary API and may be removed in a future release That's not very cool, but I will live with that, for the time being.
In the run method, I tested OK with the simulatePush method of oracle.ewt.lwAWT.AbstractButton.
The method emulated here is invokeLater. For invokeAndWait, more code is needed around the postEvent call. See some sources for the EventQueue class, as a starting point.
To get the correct EDT thread regardless of your thread group, you can use SunToolkit.targetToAppContext(Object target), and for the parameter you can feed it the AWT component you intend to act on. Example source.
Then get the EventQueue using EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext);
Finally, create a new InvocationEvent with your runnable and call postEvent on the EQ.
You should be able to extend VButton class
Your class definition should be something like:
public class AmazingButton extends VButton implements FocusListener
Then you need an init class like:
public void init(IHandler handler)
{
m_handler = handler;
super.init(handler);
addMouseListener(new ButtonMouseAdapter());
addFocusListener(this);
}
And then afterwards you need to implement the listeners and do some stuff in it:
public void focusGained(FocusEvent e)
{
if (e.getComponent() == this)
{
// put the focus on the component
e.getComponent().requestFocus();
bFocus = true ;
}
}
public void focusLost(FocusEvent e)
{
bFocus = false ;
}
/**
* Private class to handle user mouse actions
*/
class ButtonMouseAdapter extends MouseAdapter
{
/**
* User moved the mouse over the button
*/
public void mouseEntered(MouseEvent me)
{
bFocus=true ;
mouseON();
}
/**
* User moved the mouse out of the button
*/
public void mouseExited(MouseEvent me)
{
bFocus=false ;
mouseOFF();
}
/**
* User moved the mouse out of the button
*/
public void mousePressed(MouseEvent me)
{
bPressed = true ;
}
/**
* User moved the mouse out of the button
*/
public void mouseReleased(MouseEvent me)
{
bPressed = false ;
}
}
I hope this code works for you.
Regards
I successfully injected my own Java code in a running Oracle Forms application, using DLL Injection and some jni trickery.
That is the real problem here, IMO.
You are suffering from target fixation, which means that you, the programmer, has a fixed mental idea of what kind of solution they want and this blinds you to everything else. Target fixation has resulted in plane crashes, as even highly experienced and intelligent pilots ( in fact whole cockpits ! ) have become so fixated on one issue in one mindset that they let other disasters slip right by.
Get out of this frame of mind.
Your desired solution is not working out, so move on and try something else. Like the sensible option already presented to you by #nightfox79 and variations on that.
You are trying to circumvent a complex object class, when you should probably simply be extending the existing class you are trying to hack your way around. That's the whole basis of OOPs development.
DLL/JNI Trickery has no place in a sensible solution, IMO.
And I pity the person who has to maintain and repair any code solution based on a DLL/JNI hack. That way madness lies.
Your theory that invokeLater() is not running under the right EDT is probably wrong. invokeLater() will, according to the documentation, always queue the code you request onto the pending code list for the AWT Event handler, which is precisely where it should be. Trying to bypass that is almost certain to cause ghastly problems. The entire purpose of invokeLater() is to defer heavyweight processing in the EDT you invoke it from, and run it later on the exact same thread. It's a bug in invokeLater() if it does not, IMO.
If, however, you wish to check what thread code is running in then the only test I know of is to use this in your code ;
if (SwingUtilities.isEventDispatchThread())
{
System.err.println("Is running on EDT");
}
else
{
System.err.println("Is not running on EDT");
}

Why does calling this method on the EDT cause a compilation error?

I am trying to pop up a custom dialog box. When I try calling the method to do that on the EDT I get the following error:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Unresolved compilation problem:
at danind.com.gmail_coem.ui.CredentialEditor.promptPossibleDialog(CredentialEditor.java:29)
at danind.com.gmail_coem.ui.HomeScreen$ConfigureDatabase.<init>(HomeScreen.java:281)
at danind.com.gmail_coem.ui.HomeScreen.configureDatabase(HomeScreen.java:230)
at danind.com.gmail_coem.ui.HomeScreen.lambda$1(HomeScreen.java:105)
at danind.com.gmail_coem.ui.HomeScreen$$Lambda$7/2092062410.actionPerformed(Unknown Source)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$400(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
After cleaning up my project in Eclipse, and doing some isolation tests I figured out that calling the method on the EDT was what caused the problem. When I moved the method to the background thread it worked, but I don't want that since I want to create my dialog GUI on the EDT.
//Creates compilation error
private class ConfigureDatabase extends SwingWorker<Void, String[]>
{
private CredentialEditor instance;
public ConfigureDatabase()
{ //Runs on EDT
this.instance = CredentialEditor.promptPossibleDialog(true);
}
#Override
protected Void doInBackground()
{ //Runs in background thread
try(Database database = CredentialEditor.getCredentials(instance))
{
//code
}
}
}
vs
//Runs just fine, but dialog GUI is not on EDT
private class ConfigureDatabase extends SwingWorker<Void, String[]>
{
#Override
protected Void doInBackground()
{ //Runs in background thread
try(Database database = CredentialEditor.getCredentials(CredentialEditor.promptPossibleDialog(true)))
{
//code
}
}
}
The method in question:
public static CredentialEditor promptPossibleDialog(boolean reset)
{
if(reset || ConnectionPool.getInstance() == null)
{ //Checks to see if a dialog box needs to be created.
if(SwingUtilities.isEventDispatchThread())
{ //Checks to make sure the thread is on the EDT.
return new CredentialEditor();
}
else
{ //If it's not on the EDT throw an exception warning.
throw new IllegalStateException("Must run on EDT!");
}
}
return null; //If no dialog box needs to be created return nothing.
}
To be more detailed about the problem it seems simply just calling the method causes problems. It's not setting the instance variable or anything inside the method, it's just calling that static method in the EDT specifically. In fact, the stacktrace points to the line where it's simply stating the method, as in, the line where it says public static CredentialEditor promptPossibleDialog(boolean reset)
So what is causing the error and if I can't get around it how can I run my GUI code on the EDT even if the method for it is being called on a background thread?
Try running your dialog directly on EDT.
public ConfigureDatabase()
{
//some code
this.instance = CredentialEditor.promptPossibleDialog(true); //This is line 281
}
This means you are running the dialog in the worker thread, which is not a good idea. Worker Threads are mostly, afaik, for non interactive background tasks. if you must run a dialog from within a worker thread, you must separately start it of in the EDT like:
public ConfigureDatabase()
{
SwingUtilities.invokeLater(new Runnable() { //or if you must wait for its end, use invokeAndWait
public void run() {
CredentialEditor.promptPossibleDialog(true); //This is line 281
}
});
}
This should work. It would be more helpful if would provide a full SSCE, at first how you execute your Worker.
Also dialogs are for interacting with the user and bringing back a result. Saving the dialog in an instance is therefor not the best thing to do. instead store its result or rethink your design.
see here, an example:
Note: calling get on the Event Dispatch Thread blocks all events,
including repaints, from being processed until this SwingWorker is
complete.
When you want the SwingWorker to block on the Event Dispatch Thread we
recommend that you use a modal dialog.
For example:
class SwingWorkerCompletionWaiter extends PropertyChangeListener {
private JDialog dialog;
public SwingWorkerCompletionWaiter(JDialog dialog) {
this.dialog = dialog;
}
public void propertyChange(PropertyChangeEvent event) {
if ("state".equals(event.getPropertyName())
&& SwingWorker.StateValue.DONE == event.getNewValue()) {
dialog.setVisible(false);
dialog.dispose();
}
}
}
Run as:
JDialog dialog = new JDialog(owner, true);
swingWorker.addPropertyChangeListener(
new SwingWorkerCompletionWaiter(dialog));
swingWorker.execute();
//the dialog will be visible until the SwingWorker is done
dialog.setVisible(true);
Specified by: get in interface Future Returns: the computed result
Throws: InterruptedException - if the current thread was interrupted
while waiting ExecutionException - if the computation threw an
exception
You are stumbling over the Eclipse feature of allowing to run code even if it has compile errors, which does more harm than any good, imho. You may consider turning it off. However, what you have to understand is that there is no use in looking at the line number of the stack trace as that won’t necessarily tell you the line number of the compilation error but the line number where the exception has been generated at runtime.
There is no attempt to compile your code when it runs. Instead the compiler has generated code that will throw that exception unconditionally once the execution reaches the piece of code which Eclipse couldn’t compile. And so it hasn’t anything to do with the thread your code runs in. Since the spurious compiler error appears within CredentialEditor it’s unbelievable that modifications made at the caller shall change whether it compiles correctly or not. However since the code throws IllegalStateException when called in the background threads but you say that it works in your second scenario it seems that there are changes you didn’t tell us about.
On the other hand, the behavior doesn’t have to look logical if it’s caused by a bug. Normally, the exception contains the compiler error but the empty line in you stack trace perfectly matches the observed behavior that the IDE didn’t tell you about that error. So you hit a bug where there either a compiler error is assumed where none exists or that a compiler error exists for which the message is missing.
Hitting a compiler bug is not that surprising considering what you failed to mention, that you are using Java 8 and even actively use the new features. Eclipse’s Java 8 support is … well … has much room for improvements. Just check whether you are really using the most recent Eclipse version. If you are using or if the problem remains after updating I recommend you create a minimal example that reproduces the problem and doesn’t depend on any other (3rd party) classes and file a bug report to the Eclipse team.

Sending a serialized Android object using sockets throws an InvalidClassException

I'm trying to make an online drawing game. For that I'm using the Path class in Android and I need to send it to my Java server. To do that, I had tried to extend the Path class, as follows:
public class SerializedPath extends Path implements Serializable {
private static final long serialVersionUID = -5974912367682897467L;
}
To simplify things and to narrow down the problem, all I did was to send it with outputStream.writeObject(new SerializedPath) and then outputStream.flush() where outputStream is an instance of ObjectOutputStream. Over the server I simply read it using inputStream.readObject() where inputStream is an instance of ObjectInputStream. The exception I'm getting is:
java.io.InvalidClassException: com.droplay.drawingonline.path.SerializedPath; unable to create instance
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at com.droplay.drawingonline.Session.run(Session.java:71)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedSerializationConstructorAccessor1.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at java.io.ObjectStreamClass.newInstance(Unknown Source)
... 5 more
Caused by: java.lang.RuntimeException: Stub!
at android.graphics.Path.(Path.java:24)
... 8 more
Now, to isolate the problem, I had tried creating a new class that doesn't have any members and doesn't extend anything and it did work. The server didn't throw any exception and it worked like a charm. I made sure the packages names are the same, the names of the classes are the same, the server uses the same SDK files as my Android project and the files' code in both the Android app and the Java server are EXACTLY the same, but I keep getting this exception. The app doesn't throw any exception. It sends the object just fine. Please, what's wrong with my code? Thank you for helping! :)
Well I managed to solve it by sending the position of each click to the server, instead of a path class. But why didn't it work when I serialized it?

java.io.IOException: The pipe is being closed is thrown on Windows but works fine on Linux

I'm trying to run commands using Runtime.getRuntime.exec() in Java.
Runtime r = Runtime.getRuntime();
Process process = r.exec("telnet 172.16.221.87 ");
InputStream is = process.getInputStream();
OutputStream os = process.getOutputStream();
BufferedWriter br = new BufferedWriter(new OutputStreamWriter(os));
br.write("ditech\r\n");
br.flush(); // The exception is coming on last line that is br.flush();
When I run code in Linux, then its working fine. But when same code is run on Windows, it throws following error:
java.io.IOException: The pipe is being closed
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.flush(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlush(Unknown Source)
at sun.nio.cs.StreamEncoder.flush(Unknown Source)
at java.io.OutputStreamWriter.flush(Unknown Source)
at java.io.BufferedWriter.flush(Unknown Source)
at com.telnet.ConnectToTelnet.doTelnet(ConnectToTelnet.java:132)
at com.telnet.ConnectToTelnet.main(ConnectToTelnet.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
You need to read the process's output. It has almost certainly told you something that you've ignored by pressing ahead to the login phase. You need to either start two separate threads to read the stdout and stderr, or use the Process and ProcessBuilder classes, merge stderr and stdout, and use a single thread.
Have the thread just print the output for the moment. That will tell you exactly what the current problem is. More generally you should wait for the login: prompt before writing the username, wait for the password: prompt before writing the password, and so on for all the other things you're going to do in this Telnet session: and if you get anything unexpected you need to react accordingly.
Just blindly shovelling output at the processs is only going to lead to more puzzles like this one.

read an Object(customized) from ObjectInputStream

So, I don't know why the Client part of my project give me this type of error
Exception in thread "main" java.lang.ClassNotFoundException: Mining.FrequentPatternMiner
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at java.io.ObjectInputStream.resolveClass(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at JabberClient.main(JabberClient.java:81)
In the Server part, I cast the FrequentPatternMiner variable and then i give it to the ObjectOutputStream
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
FrequentPatternMiner fpMiner=new FrequentPatternMiner(dataTarget, minsup);
fpMiner.salva("FP_"+nameFile+"_minSup"+minsup+".dat");
System.out.println("Frequent Patterns \n"+fpMiner);
out.flush();
out.writeObject((Object)fpMiner);
In the Client part, i do this
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Object fpMiner=in.readObject();
(((ObjectInput)in).readObject());
System.out.println(fpMiner);
How would I fix my code? Can you help me?
The code is correct, but your premise isn't. You've said, that the class "FrequentPatternMiner must be unknown for the client". With that premise you can't serialize the class as you did, because serialization only transfers the data of the object and not it's implementation.
You might want to look into DataTransferObjects (which has to be known on both client and server) or use a simple array to transfer the object.
Example using a simple array as "DTO"
Server:
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
// The following line assumes that dataTarget and minsup are types
// that are serializable and known to the client
Object[] objArray = new Object[] { dataTarget, minsup };
out.flush();
out.writeObject(objArray);
Client:
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Object[] objArray = (Object[])in.readObject();
System.out.println(objArray);
// FrequentPatternMiner must still known to the client, if you need more than
// the constructor arguments (like methods of the FrequentPatternMiner) Object.
FrequentPatternMiner fpMiner=new FrequentPatternMiner(objArray[0], objArray[1]);
Further Idea
If you don't want that FrequentPatternMiner implementation/class is known to the client, you can try "Remoting" or "Remote Procedure Calls" (RPC). This is an advanced subject and there are a lot of libraries out there (and platforms) that provide this functionallity. They do basically this:
You need an Interface for the Class on the client (like interface IPatternMiner { void doMine() }
You connect server and client (depends on the library on how to do this) and obtain an instance of IPatternMiner
You call a method on the interface and the implementation gets executed on the server (with the parameters pased in from the client). Note that file operations write on the file system on the server
The problem you have is that FrequentPatternMiner is not on your classpath.
What you can do is ctrl+t on Eclipse and look for FrequentPatternMiner to know what is the jar containing this class. Then ensure that your project is referencing this class.
If you are using maven you can use mvm dependency:tree goal to know if your project contain this jar.
Casting to Object doesn't have any magical properties. Everything can be cast to Object. It doesn't change the fact that what is written to the object stream is a FrequentPatternMiner, and if that class isn't available at the receiver, this exception will result.
Solution: deploy the class.
Similarly, casting an ObjectInputStream to ObjectInput accomplishes precisely nothing.
You need to tyecast.
System.out.println((FrequentPatternMiner )fpMiner);
Else how would the client know class of the Object that is being deserialized. Note it is not necessary to typecast just for using it in sysout. It will print using Objects toString() method.
Though your Exception says
Exception in thread "main" java.lang.ClassNotFoundException
You need to add this class on the client side too. Lastly check that serialVersionUID is same for the class in server and client.

Categories

Resources