|
Code Clinic
includes questions on RMI, JavaBeansTM, writing a debugger,
displaying large text, and creating DNS-related cases
September 18, 1997
Guest-Speaker (SPK): SPK-rohaly amd SPK-jsmith
SPK-rohaly: Hi, I'm Tim Rohaly from MageLang Institute. Jerry Smith (also from MageLang) and I will be answering your questions today. We will take the questions in turn, so be patient--we will get to you!
srr: I have a question on displaying large text. I know that there is a 32K limit on text area in Windows95. How would I go about doing it in ScrollPane?
SPK-rohaly: You are basically asking about implementing your own TextArea. ScrollPane takes one component, so you could use the canvas to draw all the text into the canvas, using FontMetrics to determine the spacing and computing the word-wrap. You would need a data structure to hold your text and make it available for you.
I'm not sure that this is the right way to go. Why not just use TextArea, keep a data structure, and use setText() to choose which 32K to display?
srr: I suppose that would work, but would you recommend doing it your way when the size of the text can sometimes reach ~1MB?
SPK-rohaly: I would recommend doing it my way especially when you have a huge amount of text. You certainly don't want any component containing 1MB of text--it should only contain the portion that it needs. Then you manage your data structure to buffer between your huge 1MB store of text, and the tiny display component that the user sees and interacts with.
srr: Now a problem with RMI. I have a remote server (compiled under JDKTM 1.1.4) that takes an object and performs some database operation on the object. Everything goes fine until it gets to connection.createStatement(). It gives an unmarshal exception and creates a general protection failure. I compared the code to those I have written and compiled under JDK 1.1.3, and there is essentially no difference. But the code under 1.1.3 code works fine. Why?
SPK-rohaly: I just downloaded JDK 1.1.4 today. I don't see anything in the "changes" document that mentions JDBCTM--there are just bug fixes as far as I know.
Are you trying to return the Statement from your server to the client via RMI? If so, you can't do that.
srr: No, everything is being performed on the server. The only thing returned at the end is the object passed, which implements the serializable interface.
SPK-rohaly: I assume that means all references in your returned object to other objects are also to serializable, transient, or static objects.
There are two ways RMI passes objects--it passes the stub when the objects are remote, or it serializes them when they are fully serializable. All object references within the passed object must also be serializable or remote. Usually, failing to pay attention to the contained objects is the reason you get marshalling errors.
andlauer: Hello, I am trying to create DNS-related classes. Most of these classes have a constructor that creates an object by reading data from a stream of bytes.
The Answer is a subclass of Question, which is a subclass of Name. Therefore, I have implemented the Answer(stream), Question(stream), and Name(stream) methods.
Furthermore, A and NS are subclasses of Answer, but writing the A(stream) and NS(stream) is giving me a hard time.
I can only determine which class to use while I am reading an Answer (it contains a byte that determines the type of answer), but then it's too late to call the A and NS constructors. Thanks for any help.
SPK-rohaly: This sounds like a design problem. But doing things as you describe should be possible. Why do you cast your A or NS to an Answer, so you can manipulate it? Or make Answer a factory that returns a type A or NS, depending on the situation? I think you should carefully write down your objects and think about how you intend for them to interact, since it sounds like you are probably structuring your program the wrong way.
andlauer: A factory? Is that something like:
class Answer {
static Answer read(stream) {
... munch bytes ...
switch(type) {
case A:
return new A(x,y,z,stream)
case NS:
return new NS(x,y,z, stream)
default:
}
...
}
SPK-rohaly: Yes, that's the idea.
tswain: I have been doing all my graphics on a background image, and then stamping it into the display. Would you recommend using a canvas instead?
SPK-jsmith: tswain, yes, a canvas is useful for display, but you still have to build the output somewhere.
tswain: I would like write a server daemon that runs like a telenet interface. It must receive data, make decisions, dispatch images, sounds, and data, etc. Which interface(s) should I use? I see talk of RMI. I want to have the user access the server dispatched from an applet on my web page. I have read that this is the only way to break out of the sandbox model. Moreover, where can I find some good examples, and/or documentation of this?
SPK-jsmith: I'm not sure RMI is the way to go, but it is certainly possible. If you want something a little lower, take a look at one of several server-based demos at http://www.spectro.com -> "FTP Archive" -> "Java" There are multiple (demo) PrintServer implementations, one of which is an RMI solution.
tswain: I looked at the spectro.com code. You say RMI is slow, and I want 50+ connections. Slow is the last thing I want. If this is the case, I would not like to use RMI. You stated earlier that a web page can open a socket. Could this arrangment be accomodated?
(USER)
|
(WEB PAGE)--------------(SERVER)
Or perhaps:
(USER)<-----------------socket\
| \
V |
(WEB PAGE)---------socket-->(SERVER)
In other words, the user accesses the web page, and then the web page applet sends the user a socket to another remote server, which then sets up a link directly via PPP. Thus the web page would only be a conduit to link the user to the server. I was thinking that individual connections could be set up as well, thus omitting the server between individuals who wanted a private PPP link--in which case the server would be redundant. This server would have to run as a daemon. Is the spectro.com example valid for this type of arrangment?
SPK-jsmith: You can open a socket back to the machine that served the applet. The spectro.com examples are relevant to a limit. There is at least one that illustrates an applet; others are applications. Eliminating the server is difficult in cases where the intended peer-to-peer communication involves the use of applet-based connections.
tswain: Thanks! Lots of useful info to work with until the next clinic.
stevey: I'm writing a debugger, and I have a couple of questions about the sun.tools.debug package.
First, why isn't it part of the core classes? Aren't people expected to write debuggers?
SPK-rohaly: I think the short answer is that there was no intention at the beginning to provide a debugging API. SunTM just provided this set of classes for use by JDB. Having an API for debugging isn't a bad idea, but I haven't heard any talk about building that into the JDK anytime soon.
stevey: Is the RemoteDebugger API ever going to support method invocations on the target?
Are vendors supposed to include proprietary debugging hooks in their VMs? It seems like Sun just doesn't care much about the debugger being part of the Java Platform.
SPK-jsmith: I think at present it is a matter of priorities with any upcoming debugger-related work. As rohaly stated, there was no intention at the beginning to provide a debugging API.
stevey: OK, well, one last question about it: Is there any way to get the VM to do the debugging stuff without going through the RemoteDebugger API, e.g. using JNI or RMI?
SPK-jsmith: No, not that I know of.
stevey: My next few questions are about the compiler. Is there any way to configure Sun's compiler (sun.tools.javac.Main) to accept code from a buffer, and return the bytecodes in another buffer? (Rather than writing temp files?)
SPK-jsmith: stevey, I don't think you can depend on stability at this level from any vendor.
stevey: Is there any way to get the system temp directory?
Now that System.getenv() is deprecated, I don't see any way to do it.
SPK-jsmith: There is no portable way that I've seen.
alexhui: Have any of you seen an applet that does not look the same when it runs under Netscape in different platforms?
SPK-rohaly: What specifically do you mean? Applets are supposed to be visually different on different platforms, since they use the underlying OS windowing toolkit. It would be a problem if they behaved differently. Aside from implementation bugs, I think this works for the most part.
alexhui: I get really different behavior when my applet runs in Netscape on different platforms. My applet only draws some text on itself with some animination.
SPK-rohaly: I can't give you a good answer without the details, but in general an applet should behave the same on two different platforms, especially when run under the same browser.
Of course, if you are using different browser versions on the different platforms, you may see differences in implementations. And if you are doing multithreading, the platforms may have different threading models. But other than that, things should work the same.
CliffB: Can I use RMI over a modem connection? Does this question make any sense? I have been thinking of a project for a Java class that I am taking. I would like to set up a Java applet on a web page on my Internet provider. Then I would like to use RMI to communicate with a server application that would run on my PC, which would talk to a backend Access database. Is this feasible, or do I need to be on a network?
SPK-jsmith: If you connect via PPP, you are on a network. In terms of performance, it's difficult to second-guess the many confounding performance factors without simply trying it. I think your project does make sense, but you'll probably end up crafting your own security manager.
cwanek: I have a very simple question. I am trying to get ahold of my class name from within a class method. Though I do know my class name, I'd rather not hardcode it. I know I can't use Class.getClass().getName(); is there some alternative other than this:
package stuff.utils;
public class Foo
{
private static Fool myFool = new Fool(
"stuff.utils.Foo" );
// and the rest of the class.
}
I'd like to do something like this:
package stuff.utils;
public class Foo
{
private static Fool myFool = new Fool(
Class.getClass().getName() );
// and the rest of the class
}
SPK-rohaly: You could always have a class variable:
private static Class myclass = stuff.utils.Foo.class;
But other than that, I don't see how.
RJ0: I'm building an applet within two different windows, and I need to send msgs data from one to the other. The only example I could find uses JavaScriptTM inside an applet. Are there better ways? The example used JSObject, but I can't find that class in any SDK I have.
SPK-jsmith: Have you looked at AppletContext?
SPK-rohaly: RJO, if you mean separate applets in separate browser windows, there is no browser-independent way of doing this. With Netscape, you could use JavaScript and LiveConnect to communicate, but it doesn't work in IE. There is no good way to do this. I would examine your reasons for wanting to have separate applets--there might be a way to avoid your problem.
When Netscape integrates JavaBeansTM functionality into its browser using BeanConnect (I think that's the name), this sort of thing will be trivial. If the applets are on the same page, then there are two ways to communicate. You can use the getApplets() method of AppletContext to obtain references to the other applets on the page, or you can have a static (class) variable that will be shared by multiple instances of your applet on the same page.
RJ0: To add to my prior question, they are frames not separate browser sessions, I mean two framesets. No, I haven't examined AppletContext, but one of my partners dismissed that idea, I'm not sure why. Can you explain?
SPK-rohaly: Then the only way to do it is with a browser-dependent method. Remember, the browser is the applet container, and provides services to the applet-like graphics display. Unless the browser provides services for interapplet communication (like Netscape does), there is no way for Java to accomplish this.
AppletContext will only work for applets on the same page that have been loaded with the same ClassLoader. Since you have separate frames, it won't work.
stevey: Couldn't RJO's applets share data through a common server?
SPK-rohaly: stevey, sure, that's one way. I assumed he was interested in the mechanics of interapplet communication within the browser.
If he wanted to write a little server to run on his web server, he could have any applets pass data back and forth through his server. Possibilities then become endless--use sockets, use RMI, use HTTP, etc.
RJ0: For more clarification, I have a different applet in two different frames. Can an applet call an executable, or something to act as a transport layer?
SPK-rohaly: RJO, applets can't invoke native code, but they can open sockets back to the host they came from. Like stevey said, you can open up a socket and talk to your own server on your web host, or you can POST data via HTTP back to your web host, or you can use RMI (but only in 1.1-enabled browsers, which only includes HotJava and Netscape 4.02 with the JDK 1.1 patch). Does that make sense, or do you want me to go into more detail?
RJ0: The RMI makes perfect sense, the posting back is unclear. It must be IE and Netscape-compatible, but we are talking intranet, so I have greater control over the environment--i.e. the server-end. Where can I get a sample RMI and socket example?
SPK-rohaly: By posting back, I mean you can post data to a CGI program on your server. Your CGI program can then write the data to disk, or read the data from disk. So you can send a post to your server, along with a little bit of data that says what you want to do (read or write), then the applets can use the server's disk to pass messages back and forth. It's pretty gross, but it is browser-independent, since it relies only on the standard HTTP mechanisms.
SPK-jsmith: RJO, there are examples in the docs folder for the JDK. There are examples in Core Java (by Gary Cornell) and Client/Server Programming with Java and CORBA (by Robert Orfali and Dan Harkey). Also, there are several examples at http://www.spectro.com/ -> "FTP Archive" -> Java.
stevey: I've written a fairly full-featured icon/image editor, but I'm having problems with the DataTransfer stuff. Is it just me, or is there currently no standardized way to cut and paste images to the clipboard? Also, is there any way to set the cursor to a custom cursor shape?
SPK-jsmith: stevey, are you using the DataFlavor functionality?
stevey: Uh, yeah. But when I query the clipboard for its flavors, nothing comes up if there's an image there. (e.g. if I copied it from another app.)
SPK-jsmith: I haven't done this with the most recent releases, but previously there was no problem. I'm still looking for an example that I have.
stevey: While I'm waiting for my clipboard stuff, I guess I'll fire off a few small ones:
Can I set the mouse cursor to a custom cursor shape? Can I find out what object is under the mouse cursor, or query the system to find where the cursor position is? Are these things possible in Swing, if not AWT?
SPK-jsmith: I'm taking stevey's clipboard question offline and will have the results added to the transcript.
[Jerry Smith has since added the following code and comments to the transcript.]
stevey: [rephrased by moderator] I'd like to be able to copy and paste images from the system clipboard using the facilities of java.awt.datatransfer. Is this possible? Here is a code segment:
/**
* Called when the user selects "Paste".
*
* @author stevey
*/
protected void paste () {
Clipboard cb = Toolkit.getDefaultToolkit().
getSystemClipboard();
Transferable t = cb.getContents(this);
System.out.println ( "Data flavors on clipboard:" );
if ( t != null ) {
DataFlavor[] flavors = t.getTransferDataFlavors();
for ( int i = 0; i < flavors.length; i++ ) {
System.out.println ( flavors[i].getMimeType() );
System.out.println ( flavors[i].
getRepresentationClass() );
}
}
} // end of paste
On my system, if I do the following: start the icon editor, copy any graphic to the Windows clipboard, using any windows application, and select "paste," so that the method above is called--it comes up null. I want to be able to copy and paste images--is it even possible?
SPK-jsmith: Currently, the JDK doesn't support anything other than String and text for the system clipboard. I took this question offline because I thought I had an example of other data types/formats/flavors for Java-to-Java situations, but I do not.
Anyway, you can verify that the interface to the Windows system
clipboard only supports String/text with the following program, which
could be useful with future JDK releases. Simply copy something to
the system clipboard and then run this program:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
public class SystemClipboardFlavors extends Frame
implements ActionListener, WindowListener
{
List list;
Panel button_box;
Button dismiss;
public SystemClipboardFlavors(String title)
{
super(title);
addWindowListener(this);
setLayout(new BorderLayout());
list = new List(5, false);
add("Center", list);
button_box = new Panel();
button_box.setLayout(new FlowLayout(
FlowLayout.CENTER, 5, 5));
dismiss = new Button("Dismiss");
dismiss.addActionListener(this);
button_box.add(dismiss);
add("South", button_box);
}
public static void main(String[] args)
{
SystemClipboardFlavors scf =
new SystemClipboardFlavors(
"System Clipboard Flavors");
Clipboard cb = Toolkit.getDefaultToolkit().
getSystemClipboard();
Transferable t = cb.getContents(scf);
DataFlavor[] df = t.getTransferDataFlavors();
scf.fillList(df);
scf.pack();
Dimension d = scf.getPreferredSize();
if (d.width < 250)
d.width = 250;
scf.setSize(d.width, d.height);
scf.show();
}
public void fillList(DataFlavor[] df)
{
for (int i = 0; i < df.length; i++)
list.addItem(df[i].getHumanPresentableName());
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == dismiss)
System.exit(0);
}
public void windowClosing(WindowEvent e)
{
if (e.getID() == WindowEvent.WINDOW_CLOSING)
System.exit(0);
}
public void windowClosed(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
}
To answer your other question, you can set the mouse cursor on a component-by-component basis; see java.awt.Cursor. You don't have the type of freedom with a portable GUI toolkit that you have with, for example, X/Motif/UNIX, where you essentially control the entire desktop. If the object under the mouse is an AWT Component-based object, you can use basic event handling--e.g., tracking enter and leave events.
stevey: I have a command-line application that reads lines of user input from System.in and processes them. When I hit Ctrl-C, it kills the app. Is there any way to detect that Ctrl-C is hit, and not let the app die? Or coming from a different angle, is it possible to detect that the system is being asked to shut down and prevent it?
SPK-rohaly: No, you cannot trap Ctrl-C. If you program with Threads, you can certainly catch ThreadDeath and handle it. But Ctrl-C doesn't throw a ThreadDeath.
stevey: Does Sun have plans to make cursor control more flexible, e.g. bumping the mouse, using custom cursor bitmaps, etc.?
SPK-rohaly: I have heard people ask for it, but I know of know current plans to significantly augment the currently available cursor options. It's not in Swing, for instance.
stevey: You know, if there were a simple, predefined "invisible" or "hidden" cursor, so apps could hide the cursor temporarily, it would solve the problem for custom cursors. The app could simply do its own drawing wherever the cursor moved to "fake" a cursor. I hope someone at Sun is listening.
SPK-jsmith: Yes, but, again, portability is an issue. From one perspective, applications do not control the cursor, only its current appearance within their boundaries.
stevey: Is it possible to do "back up" user input? For example, if they've typed in "the quick brown fox jumped over the lazy dog," and then they hit a key (such as Ctrl-W), can my application delete the word "dog" and put the cursor after lazy? (I'm talking about in a command-line application, by the way).
SPK-rohaly: If you want to do "backup" user input like this, then you must implement it yourself. Create a KeyListener that maintains a stack of keys typed in, and look for your special trigger (like Ctrl-W), which you then use to pop keys off the stack. You will manipulate the text in the TextComponent by using setText and replaceText. But this functionality is up to you. So yes, it's possible, if you want it.
SuriMaddhula: Where can I find the source code for Swing? Also is it possible to import the JFC components into third-party IDE's and use them as Beans. If it is possible, how would you go about doing that?
SPK-rohaly: SuriMadd, the new Swing 0.4.1 release has source code included in it! The 0.3 and prior releases don't have it.
SuriMaddhula: So is it possible to import the JFC components as Beans into third-party IDEs? Do you have any suggestions regarding how to go about it? It would be greatly appreciated.
SPK-rohaly: SuriMadd, Sure, all JFC and AWT components are JavaBeans, so it is no problem importing these into IDEs that support Beans.
With an IDE like the BeanBox, what should work is to JAR up the classes for Swing with a manifest file that designates the components as Beans. With some other IDEs, you can just import them directly from the menu bar. For example, JBuilder from Borland lets you do this.
SuriMaddhula: What do I try to import. Can you give me a simple example of how I can do this?
SPK-rohaly: It really depends on the IDE. For the BeanBox, there is a menu option to "Load JAR." This lets you load any Beans from that JAR into the BeanBox. There is a really good tutorial on Beans (written by my coworkers at MageLang) at http://developer.java.sun.com/developer/onlineTraining/newbeans/index.html Exercise 5 of that tutorial walks you through packaging a Bean to bring into the BeanBox.
kdlitwak: I have a question unrelated to browsers. I have a Java application, call it MyApp. I want the functionailty of another application, call it TheirApp. I have the source for TheirApp. I want to be able to use TheirApp from MytApp, without having to rewrite TheirApp as a dialog. TheirApp extends JPanel and includes a Frame. Here's my problem. If I exit from TheirApp, SYstem.exit(0) closes MyApp as well. If I change System.exit(0) to theirAPpFrame.dispose(), this still causes my application to close. Is there a simple change I can make to the WindowAdapter class for TheirApp to correctly handle choosing exit from TheirApp's menu, but leave my application running; or do I have to seriously rewrite TheirApp to be able to use it without it closing my application? What I'm trying to get is the functionality, and I need it quite often. At some point I need to have MyApp and TheirApp tightly coupled. I don't want to create and destroy threads every single time I need to use TheirApp. Any suggestions? Thanks.
SPK-rohaly: kdlitwak, the only way to do this is to ensure that TheirApp doesn't call System.exit() should just call return. Then you can simply run TheirApp.main() in its own thread.
Why don't you want to create a thread? If it is the overhead of creating the lightweight process that disturbs you, allocate a pool of threads at program start time, then use them to run TheirApp. You can then recycle these threads when needed. The Jigsaw browser from CERN is a good example of how you handle multiple sessions like this.
kdlitwak: Rohaly, thanks. Where can I find CERN?
SPK-rohaly: kdlitwak, www.cern.ch My bookmark for Jigsaw actually says: www.w3.org/Jigsaw/ But it is a CERN project, and can be found on CERN's site as well.
rowehrli: I'm trying to do DNS queries from Java, but haven't had the best of luck. My primary interest is in returning hostnames from IPs. When I use InetAddr's getHostName() method and pass it an IP, it returns the IP back to me as the hostname. Am I missing something obvious or what?
SPK-rohaly: InetAddress.getByName("204.160.241.195") will give you the hostname. (It's java.sun.com/jdc, in case you're wondering :-)
ericeisenhower: I am trying to create a distributed app using RMI. RMI does not seem to work with the latest Netscape Navigator with JDK 1.1 (hangs), and Microsoft's Internet Explorer does not seem to have it in the works. JavaSoft has been fairly quiet about the future of RMI.
I want a browser-based, distributed app today, and don't see any good choices. I noticed that RMI creates a socket for each object. What happens to the server when it has open a couple hundred thousand open sockets?
SPK-rohaly: Sun is not quiet about the future of RMI. They are working to integrate it more closely into CORBA by making IIOP an available transport protocol, and they are working to add RMI features to the CORBA spec. Here is a brief note posted to the RMI mailing list a few weeks ago: "Recently there was a posting to this alias suggesting, yet again, that Sun is not fully committed to RMI. Postings such as this are not responsible. Let me tell you the facts: Sun has no plans to phase out RMI. Not by the end of 1998. Not ever. RMI is a key and core part of Java. Anyone who tells you otherwise is simply not informed, or has a motive in fanning a flame of disinformation. Dave Spenhoff Director, Product Marketing JavaSoft Sun Microsystrems, Inc." This is certainly not the only time I have seen an authoritative statement from Sun about RMI. Go to java.sun.com and look through the RMI materials--there is a lot of good stuff there. As far as the sockets go--how would you do it? Having a TCP socket means reliability. So yes, there is an open socket for each remote object used. Are you really going to have hundreds of thousands of remote objects used at a time? You ought to rethink your app if that is the case. The distributed garbage collection in RMI will free up the server memory and drop the sockets of those objects that are no longer in use. There is a timeout in RMI, so objects that aren't used in 10 minutes (currently) get collected. Why would you ever need hundreds of thousands of remote objects simultaneously? To find out about the RMI mailing list, send email to listserv@javasoft.com and include "help" in the body of the message. I don't have the URL for all the RMI info at Sun's web site--I seem to recall they may have recently taken it off to overhaul it. Try the products and APIs, down near the bottom, there are some RMI links you can follow.
ericeisenhower: Good news about RMI. Unless I am missing it, the JavaSoft web server is fairly bereft of information regarding RMI. All I could find were reference pages about RMI and JDK 1.0.2 from 1996, and the javadoc pages. I also got info on how to join the RMI mailing list. That would probably be the best help.
dgau: I am trying to replace all occurences of "-" in a string with "_." I saw the replace(char,char) command in the String class. How do I get "-" and "_" to be char? I tried casting and some other things, but they don't seem to work.
SPK-rohaly: Specify a character literal with single quotes, like `-' or `_.'
Well, that's about it. Thank you all for coming. We will have another Code Clinic next week--keep your eyes on java.sun.com/jdc for a schedule of all the live discussions and events.
|