Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
David Van Couvering (JIRA) wrote: > > Is it OK for NetworkServerControl to call System.exit, or does that need to > throw an exception as well? > >The technique I usually do for a utility that I want callable by another class >as well as executable from the command line is for the main() routine to >delegate to another public method which throws exceptions and doesn't call >System.exit(). Then the main() routine catches any exceptions and calls >System.exit(1) if there is an exception or System.exit(0) if there isn't one. >Then classes call the other public method and main() is only used from the >command-line. > > The execute() method which is the one with the System.exit is only called by NetworkServerControl.main() so I guess it is the exit even from main that is causing a problem with eclipse. For the exit(0), I guess we could just return. For the exit(1) case I am not entirely sure what is appropriate.Maybe main should just throw the exception then we get an error exit but the calling program won't exit completely. Rajesh filed the original case when he had a problem with eclipse exiting completely when he tried to use the main method from within eclipse. Rajesh could you confirm that that is the case? Kathey
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
We could add an argument that indicates whether or not the main program should call System.exit() or just return. It's very valuable to have a non-zero exit status when calling a command from the command-line, for better scriptability... e.g. "-noSysExit" But I think what would be better is if applications like Eclipse don't call main() but call the execute() method, which only throws an exception. This same issue exists for all the Derby tools, and it would be good if we had a policy that didn't require a "-noSysExit" option on every command. I can add an execute() method to NetworkServerControl so it's on the same class as the main() method. David Kathey Marsden wrote: David Van Couvering (JIRA) wrote: Is it OK for NetworkServerControl to call System.exit, or does that need to throw an exception as well? The technique I usually do for a utility that I want callable by another class as well as executable from the command line is for the main() routine to delegate to another public method which throws exceptions and doesn't call System.exit(). Then the main() routine catches any exceptions and calls System.exit(1) if there is an exception or System.exit(0) if there isn't one. Then classes call the other public method and main() is only used from the command-line. The execute() method which is the one with the System.exit is only called by NetworkServerControl.main() so I guess it is the exit even from main that is causing a problem with eclipse. For the exit(0), I guess we could just return. For the exit(1) case I am not entirely sure what is appropriate.Maybe main should just throw the exception then we get an error exit but the calling program won't exit completely. Rajesh filed the original case when he had a problem with eclipse exiting completely when he tried to use the main method from within eclipse. Rajesh could you confirm that that is the case? Kathey
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
David Van Couvering wrote: > We could add an argument that indicates whether or not the main > program should call System.exit() or just return. It's very valuable > to have a non-zero exit status when calling a command from the > command-line, for better scriptability... > > e.g. "-noSysExit" > > But I think what would be better is if applications like Eclipse don't > call main() but call the execute() method, which only throws an > exception. This same issue exists for all the Derby tools, and it > would be good if we had a policy that didn't require a "-noSysExit" > option on every command. > > I can add an execute() method to NetworkServerControl so it's on the > same class as the main() method. What do you think about main throwing an exception? If we can do that then it might avoid changing the public API or doc. I don't know if that is a commonly accepted practice or not. I tried this. public static void main(String[] args) throws Exception { conntype = null; if (args.length < 1 || args[0].equals("throw")) throw new Exception ("main throws exception"); else if (args[0].equals("exit0")) System.exit(0); else if (args[0].equals("exit1")) System.exit(1); else if (args[0].equals("return")) return; } $ java MainException throw Exception in thread "main" java.lang.Exception: main throws exception at MainException.main(MainException.java:20) $ echo $? 1 $ java MainException return $ echo $? 0 $ java MainException exit1 $ echo $? 1 $ java MainException exit0 $ echo $? 0
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
Well, that's enlightening, I wasn't aware that an exception thrown by main caused an exit status of 1. That definitely sounds like the right approach. If it's not a commonly accepted practice, it should be :) David Kathey Marsden wrote: David Van Couvering wrote: We could add an argument that indicates whether or not the main program should call System.exit() or just return. It's very valuable to have a non-zero exit status when calling a command from the command-line, for better scriptability... e.g. "-noSysExit" But I think what would be better is if applications like Eclipse don't call main() but call the execute() method, which only throws an exception. This same issue exists for all the Derby tools, and it would be good if we had a policy that didn't require a "-noSysExit" option on every command. I can add an execute() method to NetworkServerControl so it's on the same class as the main() method. What do you think about main throwing an exception? If we can do that then it might avoid changing the public API or doc. I don't know if that is a commonly accepted practice or not. I tried this. public static void main(String[] args) throws Exception { conntype = null; if (args.length < 1 || args[0].equals("throw")) throw new Exception ("main throws exception"); else if (args[0].equals("exit0")) System.exit(0); else if (args[0].equals("exit1")) System.exit(1); else if (args[0].equals("return")) return; } $ java MainException throw Exception in thread "main" java.lang.Exception: main throws exception at MainException.main(MainException.java:20) $ echo $? 1 $ java MainException return $ echo $? 0 $ java MainException exit1 $ echo $? 1 $ java MainException exit0 $ echo $? 0
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
David Van Couvering wrote: > Well, that's enlightening, I wasn't aware that an exception thrown by > main caused an exit status of 1. That definitely sounds like the right > approach. If it's not a commonly accepted practice, it should be :) Sounds good, the rule for the emebedded engine was always: "remember pure Java, embedded, pure Java & embedded". :-) Never make assumptions that your Java program is controlling the JVM and has the right to call methods like System.exit, then multiple Java "main" programs can hook up together without problems. Dan.
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
Kathey Marsden wrote: David Van Couvering wrote: We could add an argument that indicates whether or not the main program should call System.exit() or just return. It's very valuable to have a non-zero exit status when calling a command from the command-line, for better scriptability... e.g. "-noSysExit" But I think what would be better is if applications like Eclipse don't call main() but call the execute() method, which only throws an exception. This same issue exists for all the Derby tools, and it would be good if we had a policy that didn't require a "-noSysExit" option on every command. I can add an execute() method to NetworkServerControl so it's on the same class as the main() method. What do you think about main throwing an exception? If we can do that then it might avoid changing the public API or doc. I don't know if that is a commonly accepted practice or not. I tried this. I have a couple of issues. Firstly, I don't believe the behaviour of the JVM is defined so you don't know what is going to happen to the info from the Exception. Also running this under a GUI (e.g. using javaw) may result in loss of that info all together as there may not be a console. A bigger issue for me is that main is a static entry point that takes command line arguments. This is OK for something called from an external command line but makes little sense for something being embedded in another tool. I would prefer to see the public API as a JavaBean with properties and a single noarg execute method (perhaps by implementing Runnable or Callable). That way the user can instantitate it, initialize the arguments in a typesafe way, and then execute it. The command line interface then becomes a thin wrapper whose main method creates the bean and sets the properties by parsing the arguments. -- Jeremy
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
Wow, and I thought this was a simple fix :) If Jeremy is right, and the exit status is not defined by J2SE when an exception is thrown, then this is a problem. I'll look into this (I have to get on the road right now). I also have always been uncomfortable calling main() from another program, and appreciate it when the class provides another interface. I like Jeremy's idea of a JavaBean interface, although I don't understand why it needs to implement Runnable or Callable, is that just so it uses a standard mechanism for a no-arg execute method? Thanks, David Jeremy Boynes wrote: Kathey Marsden wrote: David Van Couvering wrote: We could add an argument that indicates whether or not the main program should call System.exit() or just return. It's very valuable to have a non-zero exit status when calling a command from the command-line, for better scriptability... e.g. "-noSysExit" But I think what would be better is if applications like Eclipse don't call main() but call the execute() method, which only throws an exception. This same issue exists for all the Derby tools, and it would be good if we had a policy that didn't require a "-noSysExit" option on every command. I can add an execute() method to NetworkServerControl so it's on the same class as the main() method. What do you think about main throwing an exception? If we can do that then it might avoid changing the public API or doc. I don't know if that is a commonly accepted practice or not. I tried this. I have a couple of issues. Firstly, I don't believe the behaviour of the JVM is defined so you don't know what is going to happen to the info from the Exception. Also running this under a GUI (e.g. using javaw) may result in loss of that info all together as there may not be a console. A bigger issue for me is that main is a static entry point that takes command line arguments. This is OK for something called from an external command line but makes little sense for something being embedded in another tool. I would prefer to see the public API as a JavaBean with properties and a single noarg execute method (perhaps by implementing Runnable or Callable). That way the user can instantitate it, initialize the arguments in a typesafe way, and then execute it. The command line interface then becomes a thin wrapper whose main method creates the bean and sets the properties by parsing the arguments. -- Jeremy
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
David Van Couvering wrote: I like Jeremy's idea of a JavaBean interface, although I don't understand why it needs to implement Runnable or Callable, is that just so it uses a standard mechanism for a no-arg execute method? Yes. -- Jeremy
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
> David Van Couvering wrote: > >> I like Jeremy's idea of a JavaBean interface > I guess things are always more complicated than you think. When Rajesh brought the Eclipse issue up, I had suggested that he use the NetworkServerControl.API, for example NetworkServerControl.start() and NetworkServerControl.shutdown() and I think he had said that there was some sort of problem with that but found some other workaround. So, would using the JavaBean interface mean that main would continue to call System.exit()? If so, I don't know if it solves the original problem or addresses Dan's concern that we not make assumptions about how we are being called. Kathey
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
OK, I have searched everywhere but can find no reference to confirm or deny that an exception on main guarantees a return status of 1 and no exception a return status of 0. The code samples and tutorials generally *don't* have main() throwing an exception, and any questions about exit status always refer people to using System.exit() I also found a code sample that allows a calling application to prevent a VM exit. What you do is define a security manager that can catch a ignore a System.exit() call from the application you are embedding and turn it into an exception. I have an email out to our J2SE folks asking if the exit behavior is standardized or depedent on the VM implementation. If it *isn't* standardized, and I suspect it's not, I suggest that we use System.exit(), and advise the Eclipse folks how to catch that using a security manager. That said, I also think we should have and document a pattern for our tools where there is a callable method that throws an exception which main() delegates to, as Jeremy suggests. Most embedding apps can just do that, rather than go through the hoops of writing a security manager. Thanks, David Kathey Marsden wrote: David Van Couvering wrote: I like Jeremy's idea of a JavaBean interface I guess things are always more complicated than you think. When Rajesh brought the Eclipse issue up, I had suggested that he use the NetworkServerControl.API, for example NetworkServerControl.start() and NetworkServerControl.shutdown() and I think he had said that there was some sort of problem with that but found some other workaround. So, would using the JavaBean interface mean that main would continue to call System.exit()? If so, I don't know if it solves the original problem or addresses Dan's concern that we not make assumptions about how we are being called. Kathey
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
Hi, all. I have done further investigation, and conversations I have had convince me that (a) System.exit() is the proper way to set an exit code and (b) embedding apps in general should not be calling main(), and (c) since we have a policy of always expecting to be embedded, tools should have a policy of providing a callable execute() method that doesn't do System.exit() but instead throws exceptions. Regarding Jeremy's suggestions: I wasn't sure, and I checked: Callable is new to JDK 1.5. Unless I am mistaken, we can't take advantage of new JDK 1.5 features at this time, am I right? In terms of Runnable, that would work, but I am a bit concerned because the real semantics of Runnable are that you can run it as a separate thread, and it could be confusing to overload it this meaning with our implied meaning that it can be embedded and executed. We could define our own interface that all our tools follow that has the very specific semantics of "this is a tool that you can embed, you need to call the execute() method to avoid the VM exiting". Also, the JavaBean approach assumes you create an instance of the beast, and I have noticed that many command-line classes have most of their code in static methods and use static variables (not that they should, but that's what they do). Also, it might actually be easier to set up an array of Strings rather than call a bunch of set methods, especially if you can create the array in-place, e.g. DB2jServerImpl.main(new String[] { "ping", "-p", "2000"} ); rather than DB2jServerImpl impl = new DB2jServerImpl() impl.setCommand("ping"); impl.setPort("2000"); impl.execute(); So, I would like to propose the following: - Define a new abstract class, e.g. org.apache.derby.tools.BaseTool, that looks something like this: public abstract class BaseTool { public abstract void execute(String[] args) throws Exception; /** * Basic main routine, can be overridden if needed */ public static void main(String[] args) { try { execute(args); } catch ( Exception e ) { e.printStackTrace(); System.exit(1); } System.exit(0); } } and then have our tools implement this, e.g. public class MyTool extends BaseTool { public void execute(String[] args) throws Exception { // yada yada } } and then applications can do MyTool.execute(new String{ "ping" }); Comments? David Jeremy Boynes wrote: David Van Couvering wrote: I like Jeremy's idea of a JavaBean interface, although I don't understand why it needs to implement Runnable or Callable, is that just so it uses a standard mechanism for a no-arg execute method? Yes. -- Jeremy
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
David Van Couvering wrote: > Hi, all. I have done further investigation, and conversations I have > had convince me that (a) System.exit() is the proper way to set an > exit code and (b) embedding apps in general should not be calling > main(), and (c) since we have a policy of always expecting to be > embedded, tools should have a policy of providing a callable execute() > method that doesn't do System.exit() but instead throws exceptions. > > > DB2jServerImpl.main(new String[] { "ping", "-p", "2000"} ); > > rather than > > DB2jServerImpl impl = new DB2jServerImpl() > impl.setCommand("ping"); > impl.setPort("2000"); > impl.execute(); > DB2jServerImpl is not a public class. NetworkServerControl is where the public api lives, so if we did use the JavaBean or execute approach the methods would live there. > So, I would like to propose the following: > > - Define a new abstract class, e.g. org.apache.derby.tools.BaseTool, > that looks something like this: > > public abstract class BaseTool > { I feel a little funny about NetworkServer being called a tool, but maybe it's ok for NetworkServerControl (a tool that controls the server?). > > public abstract void execute(String[] args) throws Exception; > > /** > * Basic main routine, can be overridden if needed > */ > public static void main(String[] args) > { > try > { > execute(args); > } > catch ( Exception e ) > { > e.printStackTrace(); > System.exit(1); > } > System.exit(0); > } > } > > and then have our tools implement this, e.g. > > public class MyTool extends BaseTool > { > public void execute(String[] args) throws Exception Should this be: public static void execute(String[] args) throws Exception? > { > // yada yada > } > } > > and then applications can do > > MyTool.execute(new String{ "ping" }); > > Comments? Well my comment is that I am glad I took this off the starter task list when I saw you picked it up. But I have a question. With regard to Network Server, would this just be an additional way to control network server if you would prefer to use execute instead of the existing NetworkServerControl API? If so, would one be preferred over the other? I asked Rajesh to respond regarding his original Eclipse requirements, but while the execute thing sounds interesting, I wonder how it addresses the Eclipse calling model? Maybe a static method is all that is needed and execute would suffice if it is a static method. Still also I wonder about what Dan said: Never make assumptions that your Java program is controlling the JVM and has the right to call methods like System.exit, then multiple Java "main" programs can hook up together without problems. I guess that is how I would like to see it in an ideal world. Maybe that is not possible, but I would like to hear a little bit more input before we make such a decision about the public API's. Thanks Kathey
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
Kathey Marsden wrote: David Van Couvering wrote: Hi, all. I have done further investigation, and conversations I have had convince me that (a) System.exit() is the proper way to set an exit code and (b) embedding apps in general should not be calling main(), and (c) since we have a policy of always expecting to be embedded, tools should have a policy of providing a callable execute() method that doesn't do System.exit() but instead throws exceptions. DB2jServerImpl.main(new String[] { "ping", "-p", "2000"} ); rather than DB2jServerImpl impl = new DB2jServerImpl() impl.setCommand("ping"); impl.setPort("2000"); impl.execute(); DB2jServerImpl is not a public class. NetworkServerControl is where the public api lives, so if we did use the JavaBean or execute approach the methods would live there. OK, point taken. So, I would like to propose the following: - Define a new abstract class, e.g. org.apache.derby.tools.BaseTool, that looks something like this: public abstract class BaseTool { I feel a little funny about NetworkServer being called a tool, but maybe it's ok for NetworkServerControl (a tool that controls the server?). Names are always a struggle. I was thinking the same thing, actually. On the drive home, I thought that perhaps BaseMain was a better name for the base class. It's "something that has a main routine." public abstract void execute(String[] args) throws Exception; /** * Basic main routine, can be overridden if needed */ public static void main(String[] args) { try { execute(args); } catch ( Exception e ) { e.printStackTrace(); System.exit(1); } System.exit(0); } } and then have our tools implement this, e.g. public class MyTool extends BaseTool { public void execute(String[] args) throws Exception Should this be: public static void execute(String[] args) throws Exception? Yes, sorry { // yada yada } } and then applications can do MyTool.execute(new String{ "ping" }); Comments? Well my comment is that I am glad I took this off the starter task list when I saw you picked it up. :) But I have a question. With regard to Network Server, would this just be an additional way to control network server if you would prefer to use execute instead of the existing NetworkServerControl API? If so, would one be preferred over the other? Well, I am still learning Derby, but I did have the same question. I assumed Eclipse had a reason for going this route. To be honest, I am concerned that we are trying to bend over backwards for the Eclipse folks when we should be telling them how to use this in the right way. I am going to push harder with the J2SE team to try and find an answer about the specified behavior for exit status when you return from main(), but in general it seems like a bad idea to call main() of a tool, and you shouldn't be that surprised if it does a System.exit() to set the exit status... I asked Rajesh to respond regarding his original Eclipse requirements, but while the execute thing sounds interesting, I wonder how it addresses the Eclipse calling model? Maybe a static method is all that is needed and execute would suffice if it is a static method. See above, I'd like to understand their requirements and why they aren't calling NetworkServerControl directly, which would solve their problems. Not that we still shouldn't fix this and have a general policy about embedding classes with main() methods. Still also I wonder about what Dan said: Never make assumptions that your Java program is controlling the JVM and has the right to call methods like System.exit, then multiple Java "main" programs can hook up together without problems. Yes, that's fair, but if we have a documented mechanism for embedding the programs using a different method, then we get the best of both worlds: we can control exit status if main() is called, and we can be embedded. This of course hinges on whether or not the exit status of a VM is defined when you throw an exception (or not) from main(). If it's well-defined, then we can just have main() throw Exception and be done with it. I guess that is how I would like to see it in an ideal world. Maybe that is not possible, but I would like to hear a little bit more input before we make such a decision about the public API's. I'll try to get an answer from the J2SE folks. In meanwhile I'll put this task on hold and go work on something else :) David Thanks Kathey
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
David Van Couvering wrote: Also, the JavaBean approach assumes you create an instance of the beast, and I have noticed that many command-line classes have most of their code in static methods and use static variables (not that they should, but that's what they do). Also, it might actually be easier to set up an array of Strings rather than call a bunch of set methods, especially if you can create the array in-place, e.g. DB2jServerImpl.main(new String[] { "ping", "-p", "2000"} ); rather than DB2jServerImpl impl = new DB2jServerImpl() impl.setCommand("ping"); impl.setPort("2000"); impl.execute(); My concern here is coming from confusion in the responsibilities between NetworkServerControl and DB2jServerImpl. For example, there are two ways to set the maxthreads: 1) new NetworkServerControl().setMaxThreads(100); 2) NetworkServerControl.main( new String[]{"maxthreads", "100"}); Ultimately these both end up calling DB2jServerImpl.netSetMaxThreads() DB2jServerImpl is doing three completely different things here: it is setting up the remote connection, it is driving the wire protocol to the remote server (see the impl of netSetMaxThreads), and it is responsible for parsing and verifying the command line arguments passed in. I think these concerns can be separated resulting in a simpler implementation that is easier to embed and use from other tools such as Eclipse. I would first suggest factoring out the connection setup and teardown - perhaps a NetworkServerConnection class with hostname and port properties (perhaps username, password or other credential) and an execute method that takes a command object e.g. public class NetworkServerConnection { public void connect() throws TransportException; public void close() throws TransportException; public Object execute(NetworkServerCommand cmd) throws TransportException, CommandException; } Each command (ping, maxthreads, etc) is represented by an object that implements NetworkServerCommand and which can be set up with the appropriate properties e.g. public class SetMaxThreadsCommand implements NetworkServerCommand { public void setMaxThreads(int threads); } Each command would know how to write itself to the wire; heck if you were prepared to break backward compatibility you could simplify things further by just using serialization. For command line support, NetworkServerControl.main parses the arguments, creates a NetworkServerConnection and the appropriate command and then submits it to the remote server. Basically it just contains implementation for handling the command line syntax. For embedded use, a tool can create and maintain a connection for as long as necessary, getting the connection parameters any way it wants (e.g. a host/user/password dialog). The commands can be created and submitted in response to UI events just like any others. Both the connection and the commands can use beaninfo to define their properties. Although there are more moving parts in this, I think overall it is a more maintainable solution as the concerns of connection, commands and UI have been clearly separated. -- Jeremy
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
David Van Couvering wrote: > I assumed Eclipse had a reason for going this route. To be honest, > I am concerned that we are trying to bend over backwards for the > Eclipse folks when we should be telling them how to use this in the > right way. > Actually I wanted to clarify here that the original request came not from Eclipse, but from the folks making the Derby plugin for Eclipse, which is a thing that actually exists so I assume that they found a workaround. I thought it would be nice (and easy) to avoid the exit from the main method and possibly helpful, so filed the bug in Jira and I thought someone might want to pick it up. So, you might find it is not worth the time to pursue if it is hard or messy which it looks like this might be. My concern is that you might be bending over backwards for exactly nobody. > > This of course hinges on whether or not the exit status of a VM is > defined when you throw an exception (or not) from main(). If it's > well-defined, then we can just have main() throw Exception and be done > with it. > agreed. > I'll try to get an answer from the J2SE folks. In meanwhile I'll put > this task on hold and go work on something else :) > Sounds like a good plan. Thanks for looking at this and thanks to all for catching the fact that throwing an Exception from main might not be a standard thing to do. If it is, that would be great and we could do the same sort of thing for ij and the other tools. If not, I think your idea of a standardized inteface is a good one if you or someone else thinks it is worth the effort. Kathey
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
> "David Van Couvering" wrote: > Subject: Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java I found an interesting article from our friends of the 'Blue' persuasion that discusses the JVMs use of hardware signals and how to use shutdown hooks that come into play when the JVM is shutting down for any reason. http://www-106.ibm.com/developerworks/ibm/library/i-signalhandling/ Not that it helps for the issue being discussed but it is closely related.
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
Whoa, I was just trying to fix the System.exit() problem :) I agree with you that there is a bit too many responsibilities for one object, and that parsing of arguments should be separated from execution of logic. However, I don't think that I should attack the separation of establishing a remote connection and driving the wire protocol as part of this bug. I think we should log a separate bug for that issue, I think it's a great thought for a more flexible design. For this bug, I could use it as an opportunity to take all command-line parsing *out* of DB2jServerImpl, that makes a lot of sense. DB2jServerImpl should only be called by NetworkServerControl anyway, and should present a more classic object abstraction and not have anything to do with argument parsing. BTW, it was my mistake to use DB2jServerImpl in the example below, it should have been NetworkServerControl. In this particular example, NetworkServerControl also has methods for each command, and the Derby docs explicitly document that this is how you work with the network server in embedded mode. So an embedding app shouldn't ever have to or need to call main() or any routine that just takes an array of args, and doesn't need the model I propose below. However, other Derby tools, however, like ij and dblook, don't have this command-based interface. They do need some kind of "execute" method that matches the way it is invoked from the command-line. As discussed, if the behavior of exit status when returning from main() is well defined by the Java spec, then we can just use main with no call to System.exit(). Otherwise, we should provide a separate execute() method for embedding applications. If we decide upon a separate execute() method, my question still is, what is the easier way to invoke this execute method, using an arg array, or by instantiating an instance and setting bean properties? I think this is an indepedent question from any separation of concern issues within the tool itself. I personally think an arg array is easier, but perhaps I'm missing an important architectural issue. Thanks, David Jeremy Boynes wrote: David Van Couvering wrote: Also, the JavaBean approach assumes you create an instance of the beast, and I have noticed that many command-line classes have most of their code in static methods and use static variables (not that they should, but that's what they do). Also, it might actually be easier to set up an array of Strings rather than call a bunch of set methods, especially if you can create the array in-place, e.g. DB2jServerImpl.main(new String[] { "ping", "-p", "2000"} ); rather than DB2jServerImpl impl = new DB2jServerImpl() impl.setCommand("ping"); impl.setPort("2000"); impl.execute(); My concern here is coming from confusion in the responsibilities between NetworkServerControl and DB2jServerImpl. For example, there are two ways to set the maxthreads: 1) new NetworkServerControl().setMaxThreads(100); 2) NetworkServerControl.main( new String[]{"maxthreads", "100"}); Ultimately these both end up calling DB2jServerImpl.netSetMaxThreads() DB2jServerImpl is doing three completely different things here: it is setting up the remote connection, it is driving the wire protocol to the remote server (see the impl of netSetMaxThreads), and it is responsible for parsing and verifying the command line arguments passed in. I think these concerns can be separated resulting in a simpler implementation that is easier to embed and use from other tools such as Eclipse. I would first suggest factoring out the connection setup and teardown - perhaps a NetworkServerConnection class with hostname and port properties (perhaps username, password or other credential) and an execute method that takes a command object e.g. public class NetworkServerConnection { public void connect() throws TransportException; public void close() throws TransportException; public Object execute(NetworkServerCommand cmd) throws TransportException, CommandException; } Each command (ping, maxthreads, etc) is represented by an object that implements NetworkServerCommand and which can be set up with the appropriate properties e.g. public class SetMaxThreadsCommand implements NetworkServerCommand { public void setMaxThreads(int threads); } Each command would know how to write itself to the wire; heck if you were prepared to break backward compatibility you could simplify things further by just using serialization. For command line support, NetworkServerControl.main parses the arguments, creates a NetworkServerConnection and the appropriate command and then submits it to the remote server. Basically it just contains implementation for handling the command line syntax. For embedded use, a tool can create and maintain a connection for as long as necessary, getting the connection parameters any way it wants (e.g. a host/user/password dialog). The commands can be created and s
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
David Van Couvering wrote: Whoa, I was just trying to fix the System.exit() problem :) I agree with you that there is a bit too many responsibilities for one object, and that parsing of arguments should be separated from execution of logic. However, I don't think that I should attack the separation of establishing a remote connection and driving the wire protocol as part of this bug. I think we should log a separate bug for that issue, I think it's a great thought for a more flexible design. I tend to agree. KISS for now and let's tackle the bigger issue when it has had a bit more thought. However, other Derby tools, however, like ij and dblook, don't have this command-based interface. They do need some kind of "execute" method that matches the way it is invoked from the command-line. As discussed, if the behavior of exit status when returning from main() is well defined by the Java spec, then we can just use main with no call to System.exit(). Otherwise, we should provide a separate execute() method for embedding applications. ij seems wierd to me as I would expect an app just to use raw JDBC - perhaps commands to execute a script would be useful. If we decide upon a separate execute() method, my question still is, what is the easier way to invoke this execute method, using an arg array, or by instantiating an instance and setting bean properties? I think this is an indepedent question from any separation of concern issues within the tool itself. I personally think an arg array is easier, but perhaps I'm missing an important architectural issue. What I don't like with the arg array is the lack of context and type safety. For example, I find cmd.execute(new String[]{"-p", "1567", "-h", "localhost" }) less meaningful than cmd.setPort(1567); cmd.setHost("localhost"); cmd.execute(); and probably harder to implement when you add in error checking. -- Jeremy
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
Jeremy Boynes skrev: What I don't like with the arg array is the lack of context and type safety. For example, I find cmd.execute(new String[]{"-p", "1567", "-h", "localhost" }) less meaningful than cmd.setPort(1567); cmd.setHost("localhost"); cmd.execute(); and probably harder to implement when you add in error checking. I totally agree with you. Also, if you write cmd.setProt(1567); cmd.setHots("localhost"); cmd.execute(); you will get an error at compile time, whereas if you write cmd.execute(new String[] { "-P", "1567", "-H", "localhost" }); the best you can hope for is an exception at runtime. -- Øyvind Bakksjø Sun Microsystems, Web Services, Database Technology Group Haakon VII gt. 7b, N-7485 Trondheim, Norway Tel: x43419 / +47 73842119, Fax: +47 73842101
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
Firstly, I would like to say that I am so happy that this little bug brought such big thinkers to Network Server. David Van Couvering wrote: > > I agree with you that there is a bit too many responsibilities for one > object I think that this is highly prevalent issue with Network Server in general. For instance, I think clearly the parameter metadata needs to be separated out from DRDAStatement and the respnosibilities of DRDAConnThread are quite immense and probably need to be evaluated and delegated accordingly. I have lacked the time and confidence to go in and tear these things apart and put them back together. I hope you will consider sticking around Network Server for a while.It's seems to me you have been shopping around for a place to do some good and I think you could really make a big difference here.If so, I would like to facilitate in any way I can, but we should pick that up on a new thread #:) Thanks Kathey
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
These are good points. Are we OK with setPort(), setHost() and execute() being static methods, or do we feel creating a new instance is the way to go. I would vote for creating an instance, but I'm worried existing code has a heavy dependence on static methods and static variables. BTW, Jeremy, the main use of ij as an embedded class is the test harness. It uses ij to read scripts and print results. A significant part of our testing is done that way... and right now the harness calls ij.main(args)... The other annoying thing about ij as the tool used by the harness, while I'm on the subject, is that it depends heavily on properties for arguments -- things are specific as system properties or in a properties file. This makes it very hard to run different instances of ij with a different configuration. I was forced to generate a different properties file for each thread. ij also does connection pooling, so if you try to run say four different instances of ij and you want each instance to go against a different database, you get some very unexpected results. I learned this the hard way when I tried to use the test harness infrastructure to build a test that scales across multiple databases in the same VM. Basically not achievable with ij. I guess I should log a bug and stop whining... :) David [EMAIL PROTECTED] wrote: Jeremy Boynes skrev: What I don't like with the arg array is the lack of context and type safety. For example, I find cmd.execute(new String[]{"-p", "1567", "-h", "localhost" }) less meaningful than cmd.setPort(1567); cmd.setHost("localhost"); cmd.execute(); and probably harder to implement when you add in error checking. I totally agree with you. Also, if you write cmd.setProt(1567); cmd.setHots("localhost"); cmd.execute(); you will get an error at compile time, whereas if you write cmd.execute(new String[] { "-P", "1567", "-H", "localhost" }); the best you can hope for is an exception at runtime.
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
Hi, Kathey. My background is definitely on the networking/runtime side more than in database internals. I looked at the NetworkServer and was a little daunted. It didn't help that there was no client code to look at, but that has recently changed. I humbly request that I try to do some simple little patches (although look at my last attempt to find something simple :) ), I can focus on NetworkServer small patches, and start getting comfortable with the code. Perhaps we can do some email exchanges where you help me through the architecture of the NetworkServer, it was a little hard to follow. David Kathey Marsden wrote: Firstly, I would like to say that I am so happy that this little bug brought such big thinkers to Network Server. David Van Couvering wrote: I agree with you that there is a bit too many responsibilities for one object I think that this is highly prevalent issue with Network Server in general. For instance, I think clearly the parameter metadata needs to be separated out from DRDAStatement and the respnosibilities of DRDAConnThread are quite immense and probably need to be evaluated and delegated accordingly. I have lacked the time and confidence to go in and tear these things apart and put them back together. I hope you will consider sticking around Network Server for a while.It's seems to me you have been shopping around for a place to do some good and I think you could really make a big difference here.If so, I would like to facilitate in any way I can, but we should pick that up on a new thread #:) Thanks Kathey
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
Hi, all. I haven't heard peep from the J2SE folks (sorry, sometimes even we don't have any clout here inside Sun). So, given no evidence to the contrary, I will assume the exit status of the VM upon receiving an exception (or not) from main() is undefined. With that assumption, I think we have agreement on the following approach. Please comment if you think I've gone off-target here... === - static main() routine uses System.exit(), throws no exceptions - static main() delegates to a NON-STATIC execute() routine which *does* throw exceptions. The execute() method has no parameters. All arguments are set via property methods. - applications wishing to embed a class with a main() routine should call execute(), and NOT main Here is an example of what I am thinking of doing: public interface Executable { public void execute() throws Exception; } ... public class MyTool implements Executable { public static void main(String args) { try { MyTool me = new MyTool(); // properties get set in this routine processArgs(args, me); me.execute(); } catch ( Exception e ) { e.printStackTrace(); System.exit(1); } System.exit(0); } } === An embedding application: try { MyTool tool = new MyTool(); tool.setCommand("ping"); tool.setPort(3234); tool.execute(); } catch ( Exception e ) { ... } I will also fix DB2jServerImpl to not do the argument processing and push that up to NetworkServercontrol. There may be an opportunity to refactor argument processing into a common utility, and perhaps to borrow existing third-party code. I'll keep you informed on that aspect as needed. Thanks, David Craig Russell (JIRA) wrote: [ http://issues.apache.org/jira/browse/DERBY-214?page=comments#action_64106 ] Craig Russell commented on DERBY-214: - Hi, I agree that main() should only be used from the command line, and is the only place in the code where System.exit() should be called. The main() method could simply delegate to another method that takes the String args[] parameter. For the purposes of this message, I'll just call it "execute". All of the utility programs should use the same method name for the "execute" method so it's easy to remember how to invoke it. The "execute" then does the parsing of the args. There are lots of Apache commons arg parsers that could be used in the "execute", but that's just a bit off topic. Execute should throw exceptions, not ever call System.exit. Since the execute method has the same parameters as main, it's easy to remember how to invoke it. The second issue is whether the execute method should be static or not. For consistency, I think that non-static would be the way to go. If we offer different methods of executing, then it would be nice to have all of them behave the same in terms of static vs. non-static. The third issue is where the processing of environment variables should be done. It might be best if the constructor of an instance of the utility class processed the environment variables. That way, regardless of whether main() or a program called the constructor the behavior would be the same. The fourth issue is whether for ease of use, aother convenience methods could be used. One that takes a single String is desirable. This method, also called execute, could simply parse the input String into a String[] and call the other execute method. An alternative method would take a Map of parameter names and values with the obvious semantics. I see a few alternatives 1. ij.execute(new String[] {"{"-p", "1567", "-h", "localhost" }); 2. ij.setPort(1567); ij.setHost("localhost");ij.execute(); 3. ij.execute("-p 1567 -h localhost"); 4. Map map = new HashMap(); map.put("-p", "1567"); map.put("-h", "localhost"); ij.execute(Map map); I can see value in all of these techniques depending on what you have on the caller side of the interface. Regards, Craig Remove System.exit() calls from the DB2jServerImpl.java --- Key: DERBY-214 URL: http://issues.apache.org/jira/browse/DERBY-214 Project: Derby Type: Bug Components: Network Server Versions: 10.1.0.0 Reporter: Kathey Marsden Assignee: David Van Couvering The System.exit() calls needs to be removed from the DB2jServerImpl.java as this results in the entire application (example - Eclipse which is running the Network Server inside it) getting shut down.
Re: [jira] Commented: (DERBY-214) Remove System.exit() calls from the DB2jServerImpl.java
David Van Couvering (JIRA) wrote: >What I am going to do for this is simply move the System.exit() from >NetworkServerImpl to NetworkServerControl, and then I will open two separate >items: one to relocate argument processing to NetworkServerControl, and >another to adjust the other tools that don't already have a documented public >interface to follow a calling model we all agree on. > > > Sounds like an excellent plan. +1