text:
Dynamic Loading/Reloading of Classes and Dynamic Method Invocation, Part 1
Java Programming Notes # 1494
- Preface
- Preview
- General Background Information
- Discussion and Sample Code
- Run the Program
- Summary
- What's Next?
- References
- Complete Program Listing
In my opinion, one of the most complex topics in all of Java involves dynamic loading, unloading, and reloading of classes. Not far behind in terms of syntactical complexity is the dynamic invocation of methods using reflection.
In this lesson, I will teach you how to write a program that modifies its fundamental behavior at runtime by dynamically modifying, compiling, loading, and reloading classes. I will also teach you how to use reflection for dynamic method invocation.
A practical example
Whenever possible, I like to demonstrate Java programming concepts by writing a small but useful program that incorporates those concepts to advantage. I thought long and hard before finally coming up with an idea for a small but useful program that clearly demonstrates the benefits of dynamic class loading.
I settled on a program that writes, compiles, loads and executes new Java code on the fly with no requirement to stop and restart the program to incorporate the new code. The new code is code that was completely unknown to me when I wrote the program. The new code may also be code that is unknown to the user when she starts the program running.
A plotting program
Stated briefly, the program allows a user to enter chunks (multiple statements) of Java code into a text field during runtime. (The reason for doing this will be explained in detail later.) Having entered a new chunk of code, the user clicks a button, which causes the new code to be compiled, loaded, and executed as the body of a method. The results produced by executing the method are then plotted in a Cartesian coordinate system as shown in Figure 1. The user can repeat this process for as long as she has new chunks of code to evaluate with no requirement to stop and restart the program along the way.
From very simple to very complex
The chunk of Java code can be as simple or as complex as may be needed to satisfy the user's needs. For example, the chunk of code could be as simple as the following equation of a straight line.
y = 6*x+5;
On the other hand, the chunk of code could be as complex as or more complex than the following which includes the definition and use of a local inner class along with the getTime instance method from the Date class and the static sqrt method from the Math class.
final double z = 65;class LocalClass{public long p = new java.util.Date().getTime();public double method( double data){return sqrt(p/(data*z*1.0E09));}}LocalClass q = new LocalClass();y = q.method(18.6)*x;
(Line breaks were manually inserted into the example given above to force it to fit into this narrow publication format.)
Viewing tip
You may find it useful to open another copy of this lesson in a separate browser window. That will make it easier for you to scroll back and forth among the different listings and figures while you are reading about them.
Supplementary material
I recommend that you also study the other lessons in my extensive collection of online Java tutorials. You will find those lessons published at Gamelan.com. However, as of the date of this writing, Gamelan doesn't maintain a consolidated index of my Java tutorial lessons, and sometimes they are difficult to locate there. You will find a consolidated index at www.DickBaldwin.com.
I also encourage you to review the material in the lessons listed in the References section of this document.
I claim no special expertise in the complex areas of class loaders or dynamic method invocation. In fact, I find much of what I read on the web about these topics to be confusing and often contradictory. However, I have learned enough about these topics to put them to work. As an example, I will present and explain a very useful program that might be called an equation solver at the low end, and might be called an interactive code exerciser at the high end. I will share the knowledge that I have gained on these topics with you in this two-part lesson.
A screen shot of the program GUI
I will begin by showing you a screen shot that illustrates the program in operation. Then I will briefly explain the operation of the program. After that, I will explain the program code in detail.
A screen shot of the program GUI is shown in Figure 1.
Figure 1
Dynamic class loading and method invocation
This program, which is named Reload02, demonstrates the use of dynamic class loading and dynamic method invocation. When the program executes, it defines, writes, compiles, loads, instantiates, and invokes methods on an object of a new class that is designed automatically according to input from the user.
A plotting program
As you can see from Figure 1, this is a plotting program. It is designed to automatically create and load a new class file named Reload02a.class, to instantiate a new instance (object) of the class, and to plot the behavior of three instance methods belonging to the object. The user can repeat this cycle indefinitely, entering specifications for the new classes into the text fields at the top of the GUI, with no requirement to stop and restart the program.
Three methods
The three methods are named f1, f2, and f3. The behavior of each of the three methods is specified in text form by the user who enters the specifying text into three corresponding text fields at the top of Figure 1.
Creating and loading a new class
By modifying the text, checking the check box near the top, and clicking the button near the bottom, the user can cause a new class to be created, compiled, and loaded. The new class contains three methods with behavior matching the text entered by the user.
Plotting the behavior of the methods
The behavior of each of the three methods is then plotted on a common set of Cartesian coordinates. Once the methods are defined and plotted for the first time, the user can modify the plotting parameters in the text fields at the bottom of Figure 1 and cause the methods to be plotted again and again with different plotting parameters.
Zooming in
For example, Figure 2 shows the result of adjusting the plotting parameters so as to zoom in on the region near the origin of the graph shown in Figure 1.
Figure 2
The user can replot the graph as many times as may be needed using different plotting parameters for each new graph.
New method specifications
When the user is satisfied with the plots of those three methods, she can modify the text in the text fields near the top and start over with three new methods. It is important to note that, due to dynamic reloading of the class, this does not require the termination and/or restarting of the program.
Modifying the text specification for one or more of the three methods, checking the checkbox, and clicking the Graph button causes a new class to be defined, written, compiled, loaded, and instantiated, and causes the three methods belonging to the object of the new class to be executed and plotted. The new class is designed automatically according to the input provided in the text fields by the user.
Plotting format
As you can see in Figure 1 and Figure 2, the three methods named f1, f2, and f3 are plotted in black, red, and blue respectively. A coordinate system with axes, tic marks, and labels is plotted in green.
The labels on the axes correspond to the values at the extreme edges of the plotting surface. As shown in Figure 1, the initial plotting range extends from -151 to +151 on each dimension. This causes points plotted within the range from -150 to +150 inclusive to be visible inside the plotting surface.
As shown in Figure 2, the plotting range on the positive or negative side of either dimension can easily be changed by the user.
The overall default size of the GUI is 475 pixels wide by 430 pixels tall. This size was chosen to satisfy the size requirements of my publisher. You may want to expand the overall size of the GUI in order to be able to view more detail.
User input, graphic output
As discussed above and as shown in Figure 1 and Figure 2, the program provides three text fields near the top of the GUI into which the user can enter text expressions written in java syntax. These expressions are evaluated to produce the plots shown in the center of the GUI. For example, when the following equation is entered into one of the text fields, the check box is checked, and the Graph button is clicked, the value of y is plotted on the vertical axis as a function of x on the horizontal axis. (Note that the semicolon is required.)
y = 100.0*(cos(x/10.0)*sin(x/11.0));
In this case, the cos and sin methods of the Math class are used to evaluate the equation. (This produces the blue curve in Figure 1 and Figure 2.)
All computations are performed as type double. Then the results are converted to integer values for plotting.
From simple to complex
The text entered into the text fields can be as simple or as complex as is required to satisfy the user's needs. For example, a beginning algebra student might be interested in graphing the following three equations of a straight line and comparing the different graphs:
y = 10*x + 15;
y = -5*x - 0;
y = 3*x -50;
On the other hand, someone interested in understanding Digital Signal Processing (DSP), might be interested in the plotted form of the sinusoidal equation shown above. (As mentioned earlier, this is the blue curve in Figure 1 and Figure 2.)
Java programming and DSP
Someone having Java programming knowledge can enter more advanced text into the text fields, such as the complex chunk of Java code shown earlier.
For example, the following text will plot as a series of impulses, as shown in Figure 3.
if(x%10 == 0){y = 50;}else{y = -50;}
(This is another functional form that might be of great interest to someone interested in DSP because we frequently deal with impulse trains in DSP.)
Figure 3
Eliminating two of the three graphs
Note that two of the three graphs were effectively eliminated from Figure 3 by entering equations that caused the value for y to be a constant which was off the page.
Static import directive
The program uses a static import directive for the Math class requiring the use of J2SE 5.0 or later. Therefore, it is not necessary to qualify methods from the Math class with the name of the class as in Math.cos(...). As shown in Figure 2, all that is required is cos(...). Thus, all of the methods of the Math class are directly available to be included in the text specifications for the three methods.
Using other classes
If it is desired to use other classes from the Java API, it is necessary to fully qualify the references to those classes using their package name, as shown in the following text specification. (This example has no purpose other than to illustrate the syntax involved.)
y = (x * ((new java.util.Date().getTime())/ (new java.util.Date().getTime())));This is the text that is plotted in red in Figure 1 and Figure 2. (Note that a line break was manually inserted in the middle of the above equation to force it to fit into this narrow publication format.)
Design, write, compile, load, instantiate, evaluate, and plot a new class
As shown in the above figures, the three text fields used for entry of text specifications are located near the top of the GUI. In addition, a check box is also located near the top of the GUI. There is a Graph button at the bottom of the GUI.
If the check box is checked when the Graph button is clicked, a new class that matches the specifications that have been entered into the text fields is automatically designed, written, compiled, loaded and instantiated before the methods are evaluated and plotted.
If the check box is not checked...
If the check box has not been checked when the Graph button is clicked, a new class is not loaded. Rather, the methods in the existing class are simply re-plotted, potentially with different plotting parameters. (You can change the plotting parameters by changing the values in the text fields at the bottom of the GUI.)
Method specifications at startup
As shown in Figure 1, the program plots the following three text expressions by default at startup in order to provide a visual confirmation that the program is working, and also to illustrate the syntax that should be used to enter text specifications into the text fields:
y = (x*x*x + 40*x*x + 100*x -6000)/100;
y = (x * ((new java.util.Date().getTime())/ (new java.util.Date().getTime())));
y = 100.0*(cos(x/10.0)*sin(x/11.0));
(Note that a line break was manually entered into the second equation above to force it to fit into this narrow publication format.)
A simple cubic function
The first equation shown above is a simple cubic function with roots at x values of -20, -30, and +10.
Classes other than the Math class
The second equation illustrates how classes other than the Math class can be incorporated into the text specifications.
Methods of the Math class
The third equation illustrates how methods of the Math class can be incorporated into the text specifications.
Adjusting the plotting parameters
In addition to the text fields at the top of the GUI, this program also provides the following text fields and a button labeled Graph at the bottom of the GUI. The combination of these text fields and the button makes it possible for the user to adjust the plotting parameters and to replot the graph as many times with as many plotting-parameter settings as may be needed.
- xMin = minimum x-axis value
- xMax = maximum x-axis value
- yMin = minimum y-axis value
- yMax = maximum y-axis value
- xTicInt = tic interval on x-axis
- yTicInt = tic interval on y-axis
- xCalcInc = calculation interval (should normally be set to 1.0)
The user can modify any of these parameters and then click the Graph button to cause the three methods to be re-plotted according to the new parameters.
Output on the command-line screen
In addition to the output shown in the GUI in Figure 1, the program also produces status output on the command-line screen as shown in Figure 4.
Figure 4
In order to plot new and different equations, it is only necessary to:
- Enter the new specifications into the text fields at the top of the GUI
- Check the check box at the top of the GUI, and
- Click the Graph button.
Possible compilation problems
This will cause a new class containing three methods that represent the text specifications in the three text fields to be compiled and loaded. If the new class is compiled and loaded successfully, the new graphs will appear on the GUI fairly quickly. If the compilation process fails to return within five seconds, the compilation process will be aborted and a "Compilation timeout error" will be declared on the command-line screen as shown in Figure 4.
It is also possible that the compilation process could return within five seconds with a compilation error. In either case, a "Probable compile error" will be declared on the command-line screen.
If at first you don't succeed, try, try again
However, the program does not terminate as a result of a probable compile error. You can fix the problem in the text specification and try again by checking the checkbox and clicking the Graph button.
How do you know how to fix the problem?
The source code for the new class file named Reload02a.java is deposited in a subdirectory (of the current directory) named Temp.
In the event of a compiler error, the command-line screen shown in Figure 4 does not provide any diagnostic information. Therefore, it isn't of much help in fixing the problem. In that case, it might be a good idea to manually recompile the source-code file named Reload02a.java in the subdirectory named Temp using the javac.exe program from Sun before attempting to repair the text specification in the text field shown in Figure 1.
In that instance, the source code should not compile successfully, but useful diagnostic information should be produced. My approach at that point would probably be to repair the source code file in order to get a good compilation. Having determined the nature of the problem with the specification, I would then repair the text specification in the text field of Figure 1, check the check box, and click the Graph button again.
Two programs in Part 1
I will present and explain two programs in Part 1 of this lesson. The first program is named Reload01. The purpose of this program is simply to illustrate the methodology for dynamically compiling and loading a new class, instantiating an object of the new class, and invoking a method belonging to that object. This program has no particular use other than to illustrate the concepts listed above.
The second program that I will present and explain in Part 1 of this lesson is named Reload02. This program will incorporate the three concepts listed above into the plotting program described earlier.
Three ways to do the job
There are at least three ways to make use of a class that has been dynamically loaded. Both of the programs presented in Part 1 of this lesson will use the invoke method of the Method class (reflection) to dynamically invoke methods belonging to objects of the newly-loaded class.
Part 2 of this lesson will demonstrate the second approach for accomplishing the same results using interfaces while avoiding the complexities of reflection. Part 2 will also describe, but probably will not demonstrate the third approach.
General Background Information
This section will provide general background information on class loaders and dynamic method invocation.
Class Loaders
What does it mean to load a class? I can't provide a complete technical description, but I can tell you that once a class has been loaded, a special object of the class named Class will have been automatically instantiated. The Class object represents the newly-loaded class, and you can do lots of things with it. (See for example the introspection example in the earlier lesson entitled Swing from A to Z: Analyzing Swing Components, Part 2, GUI Setup.)
Putting class loaders to work
As I explained earlier, I claim no special expertise in the complex area of class loaders. However, I have learned enough about them to put them to work and I will share that knowledge with you.
Two kinds of class loaders
I am led to believe that there are two kinds of class loaders:
- The primordial class loader
- Class loader objects
There is only one primordial class loader in a running Java program, and it is part of the Java Virtual Machine.
There may in addition be one or more class loader objects, which are created by the program at runtime.
When can a class be reloaded?
I am led to believe that once a class is loaded, it can only be reloaded if it was loaded by a class loader object. Classes loaded by the primordial class loader cannot be reloaded. If a class cannot be reloaded, it also cannot be replaced by a new class having the same name.
Class loading priority
After creating a class loader object, you can ask it to load classes according to certain restrictions. However, I believe that even if you ask a class loader object to load a class, the primordial class loader is given an opportunity to load the class first. If the primordial class loader finds the class on the classpath, it will load it.
Avoid putting your re-loadable classes on the classpath
As mentioned above, once a class is loaded by the primordial class loader, it cannot be reloaded. Therefore, classes that you intend to load and reload using class loader objects must not be on the class path. If they are, they will be loaded by the primordial loader, and once loaded cannot be reloaded.
The URLClassLoader class
It is possible to define your own class loader objects to deal with special class loading requirements. However, that is not demonstrated in this lesson. Rather, this lesson instantiates an object of the URLClassLoader class and uses it to load classes. The URLClassLoader class is contained in the standard Java class library.
Loading a class
Once you have a URLClassLoader object, you can ask it to load a class by invoking the loadClass method on the object passing the name of the class as a String. If the class is successfully loaded, the loadClass method will return a reference to a Class object that represents the newly-loaded class. (The loadClass method throws the ClassNotFoundException if it can't find the class file.)
Instantiating an object of the newly-loaded class
Once you have a Class object that represents the newly-loaded class, you can instantiate an object of the class by invoking the newInstance method on the Class object.
What is the type of the new object's reference?
However, the type of the reference returned by the newInstance method is not the name of the class represented by the Class object. Rather, in J2SE 5.0 and later, it is the generic type <T>.
Cannot cast to the true type
Furthermore, because the newly-loaded class is not on the classpath, it is not known to the compiler at compile time, so you cannot compile a statement that will cast the object's reference to the type of the newly-loaded class.
(However, to get on more familiar ground, you can save the reference as type Object if you are uncomfortable with the concept of the generic type <T>. Prior to the release of J2SE 5.0 and its concept of Generics, the newInstance method of the Class class actually returned a reference of type Object .)
How do you invoke a method belonging to the new object?
That brings us to the next topic. If your reference to the new object is not of the correct type, how do you invoke methods belonging to the new object?
As I mentioned earlier, there are at least three ways to invoke the new object's methods. Both of the programs that I will explain in Part 1 of this lesson will use the invoke method of the Method class (reflection) to dynamically invoke methods belonging to the object.
Part 2 of this lesson will demonstrate the second approach, which uses a common interface while avoiding the complexity of dynamic method invocation. Part 2 will also describe, but probably will not demonstrate the third approach.
Dynamic Method Invocation using Reflection
The Class object that represents a class provides a large number of methods that make it possible for you to get information pertaining to the class represented by the object. For example, the method named getDeclaredMethods (plural form):
"Returns an array of Method objects reflecting all the methods declared by the class or interface represented by this Class object."
Similarly, the method named getDeclaredMethod (singular form):
"Returns a Method object that reflects the specified declared method of the class or interface represented by this Class object."
Will use the singular form of the method
Since I already know the names, return types, and parameter types for the methods of interest in the programs in this lesson, I won't need a list of all the methods belonging to the object. Therefore, I can use the singular form, getDeclaredMethod, described above.
The Method class
The getDeclaredMethod method returns a reference to an object of the class Method. According to the Sun documentation:
"A Method provides information about, and access to, a single method on a class or interface. The reflected method may be a class method or an instance method (including an abstract method)."
The invoke method of the Method class
Among the many methods provided by the Method class is the method named invoke. Again, according to the Sun documentation, this method:
"Invokes the underlying method represented by this Method object, on the specified object with the specified parameters."
Makes it possible to invoke a particular method...
Thus, once you have a Method object that represents a particular method, it is possible to invoke the method named invoke on the Method object to cause that particular method belonging to a particular object to be executed.
Does not require a reference of the true type
Furthermore, that is possible even if the type of your object's reference is not the true type of the object. For example, your reference could be the generic type Object.
(Normally, if you have a reference to an object as type Object, you cannot directly invoke a method on the object unless the method is one of the eleven methods defined in the class named Object. However, you can get around that restriction by using the dynamic method invocation process described above. I will demonstrate the process in the two programs in this document.)
Someone once said, "The devil is in the details."
There are quite a few tedious details involved in the use of dynamic method invocation. I will explain some of those details in the explanation of the code in the sections that follow.
Discussion and Sample Code
- Reload01
- Reload02
The first program listed above is designed to illustrate how to use dynamic class loading and dynamic method invocation. This is a relatively simple, but not particularly useful program.
The second program listed above is designed to incorporate dynamic class loading and dynamic method invocation into a useful but much more complex program.
The Program Named Reload01
The program named Reload01 illustrates writing, compiling, loading, recompiling, and reloading a new class, and invoking a method on an object instantiated from that newly-loaded class totally under program control at runtime.
Write a simple source code file
The program begins by automatically writing the simple class definition shown in Listing 1 into a source code file named Reload01a.java in a subdirectory (of the current directory) named temp.
public class Reload01a{ public String theMethod(String str,double val){ System.out.println("Executing theMethod"); return str + " " + "Tom" + " " + val/3; } }
The program GUI
The program displays the simple GUI shown in Figure 5.
Figure 5
This GUI has a single button labeled Recompile and Reload. Each time you click the button, the program compiles and reloads the class named Reload01a, which was originally written as shown in Listing 1, but which may have modified by you, external to the program after it was originally written.
Then the program instantiates an object of the newly-loaded class and invokes the method named theMethod on the object.
If you modify the source code...
If you modify the source code file for the class using a text editor outside the program, the next time you click the button to cause the file to be recompiled and reloaded, the new behavior that matches your modifications will be exhibited.
Compiler errors
When you modify the source code for the class, you may inadvertently insert a syntax error. If the compilation process fails to return within five seconds, the compilation process is aborted and a "Compilation timeout error" is declared.
It is also possible that the compilation process could return within five seconds with a compilation error. In either case, a "Probable compile error" will be declared and displayed on the command-line screen.
However, the program does not terminate as a result of a probable compile error, so you can fix the problem in the source code and try again by clicking the button again.
The location of the class file
The location of the class file is hard-coded as the subdirectory (of the current directory) named temp, but could be anywhere (including being located at some URL on the internet) that is accessible by the program if you were to modify the program accordingly. In other words, classes can be dynamically loaded at runtime from a variety of locations.
Watch out for the classpath
You must make certain that there is not a copy of a compiled version of the class named Reload01a on the classpath. If the program finds a copy on the classpath, that version of the class will be loaded by the primordial loader, and will not be reloaded when a reload is requested.
Program output
Figure 6 shows typical output produced by the program on the command-line screen.
Writing the class file. In actionPerformed Compiling tempReload01a.java Waiting for completion Compile complete Executing theMethod Hello Tom 3.3666666666666667 In actionPerformed Compiling tempReload01a.java Waiting for completion Compilation timeout error. Probable compiler error. In actionPerformed Compiling tempReload01a.java Waiting for completion Compile complete Executing theMethod Hello Bill 3.3666666666666667 In actionPerformed Compiling tempReload01a.java Waiting for completion Compile complete Executing theMethod Hello Bill 2.525
Figure 6
Modified source code
The source code for the class was modified between each click of the button in Figure 5 producing the output shown in Figure 6. Thus, the behavior of the recompiled and reloaded class was different each time the button was clicked. (Note in particular the names and the numeric values.) In one case, a syntax error was purposely created in such a way as to produce a compiler error.
Program testing
This program was tested using J2SE 5.0 under Windows XP.
Will explain the code in fragments
A complete listing of the program is provided in Listing 35 near the end of the lesson. I will explain the code in fragments.
Event-driven programming code
Much of the code in this program involves event-driven programming and the Delegation or JavaBeans event model. If you have studied my earlier lessons on these topics, this material should be familiar to you.
(This event-driven programming code is included in the program simply as a means of controlling the process and is not an inherent part of dynamic class loading.)
I won't bore you by explaining the event-driven programming code in detail, but will skip over it fairly rapidly and mention it fairly briefly. I will concentrate on the code required to write, compile, load, recompile, and reload the new class named Reload01a, and to invoke a method on an object instantiated from that newly-loaded class totally under program control at runtime.
The Reload01 class
The beginning of the class and the main method for the class named Reload01 is shown in Listing 2.
class Reload01 extends JFrame{ File targetDir;//location of the file named Reload01a public static void main(String[] args){ new Reload01().writeTheClassFile(); }//end main
The code in Listing 2 instantiates a new object of the class named Reload01 and invokes the method named writeTheClassFile on that object. The purpose of the method named writeTheClassFile is to write the source code file for the class named Reload01a in a subdirectory (of the current directory) named temp.
The method named writeTheClassFile
The method named writeTheClassFile is shown in its entirety in Listing 3.
//Write the source code for the file named Reload01a // into a subdirectory named temp. If the file // exists, it will be overwritten. void writeTheClassFile(){ try{ //Create a File object that points to a directory // where the class file will reside. targetDir = new File(System.getProperty("user.dir") + File.separator + "temp" + File.separator); //If the directory doesn't exist, make it. if(!targetDir.exists()){ targetDir.mkdir(); }//end if //Get an output stream for writing the source code // for the new class file. DataOutputStream dataOut = new DataOutputStream( new FileOutputStream("temp" + File.separator + "Reload01a.java")); //Create the source code for the new class file. System.out.println("Writing the class file."); dataOut.writeBytes( "public class Reload01a{" + "public String theMethod(String str,double val){" + "System.out.println("Executing theMethod");" + "return str + " " + "Tom" + " " + val/3;" + "}" + "}" );//end writeBytes method dataOut.close();//Close the output file. }catch(Exception e){ e.printStackTrace(); }//end catch }//end writeTheClassFile
Most of the code in Listing 3 should be familiar to you, particularly if you have studied my previous lesson entitled Core Java Classes, Input and Output Streams. Therefore, I won't discuss the code in Listing 3 any further.
The constructor
The constructor for the class named Reload01 begins in Listing 4.
Reload01(){//constructor setTitle("Copyright 2006, R.G.Baldwin"); JButton button = new JButton("Recompile and Reload"); getContentPane().add(button); button.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ System.out.println("nIn actionPerformed");
An anonymous inner class
The boldface code in Listing 4 shows the beginning of the definition of an anonymous listener class, and the instantiation of an anonymous listener object of the anonymous class.
This code is something less than straightforward. If you are unfamiliar with the use of anonymous inner classes, I recommend that you go back and review my earlier lesson entitled The Essence of OOP using Java, Anonymous Classes along with other lessons that I have published on this topic. You can access those other lessons using the links at http://www.dickbaldwin.com/tocmed.htm. You might also want to review the lessons on member classes and local classes while you are at it.
The last two lines in Listing 4 show the beginning of the definition of the actionPerformed method, which is executed each time the user clicks the button shown in Figure 5.
Invoke the compile method
Continuing in the actionPerformed method, the code in Listing 5 invokes the method named compile to cause the new source file named Reload01a to be compiled.
try{ boolean compileStatus = compile( "temp" + File.separator + "Reload01a.java");
The method named compile returns true on a successful compile and false otherwise. The return value is saved in the variable named compileStatus for later use.
(If you are unfamiliar with the use of File.separator, you can look it up in the Java documentation from Sun.)
The method named compile
The code for the method named compile begins in Listing 6.
private static boolean compile(String file) throws IOException{ System.out.println("Compiling " + file);
The code in Listing 6 simply displays a message on the command-line screen.
Executing the Java compiler in a separate process
The really important code in the compile method is shown in the single statement in Listing 7.
Process p = Runtime.getRuntime().exec("javac " + file);
In case you have never done this before, Listing 7 shows how you can cause Java programs to execute other programs written in other languages. According to Sun, the exec method of the Runtime class:
"Executes the specified string command in a separate process."
In this case, the code in Listing 7 causes the Java compiler named javac.exe to be executed to compile the file named Reload01a in the subdirectory named temp.
(I explained this process (used for an entirely different purpose) in an earlier lesson entitled Introduction to the Java Robot Class.)
An object of the Process class
As you can see, the invocation of the exec method in Listing 7 returns a reference to an object of the class Process.
Part of what Sun has to say about a Process object is shown in Figure 7.
"The ProcessBuilder.start() and Runtime.exec methods create a native process and return an instance of a subclass of
Process that can be used to control the process and obtain information about it. The class
Process provides methods for performing input from the process, performing output to the process,
waiting for the process to complete, checking the exit status of the process, and
destroying (killing) the process."
Figure 7
In this program, I will be particularly interested in the following two capabilities listed in Figure 7:
- Waiting for the process to complete
- Destroying (killing) the process
Will invoke the waitFor method
Once I start the compilation process, I will invoke the waitFor method on the Process object to cause the program to block until the compilation is finished. However, I have determined experimentally that sometimes the waitFor method hangs up and fails to return when there is a compiler error.
A five-second timer
Therefore, I designed some special code to deal with that problem. The code that I designed allows five seconds for the compilation to complete successfully and for the waitFor method to return. If the waitFor method fails to return within five seconds, the code
- Declares a "Compilation timeout error"
- Invokes the destroy method on the Process object
- Returns false to indicate a compiler error
However, it doesn't terminate the program and the user may correct the source code for the class and try again.
Complex flow of control
I will be trying to explain the program flow of control involving two threads that are executing in parallel in the paragraphs that follow. This can become a little difficult to explain.
The compiling thread and the timer thread
For want of a better approach, I will refer to the thread that executes the code in Listing 8 as the compiling thread. I will refer to the other thread as the timer thread.
Two browser windows would be useful
This is a place where it would definitely be useful for you to have this lesson open in two or more browser windows so that you can conveniently view two or more code listings at the same time.
Start a five-second timer
The code in Listing 8, which is executing in the compiling thread, instantiates a new Thread object of the Timer class and starts it running as a different thread, which is the timer thread. The timer is set to run for 5000 milliseconds, or five seconds.
(If you are unfamiliar with multithreaded programming in Java, see my earlier lesson entitled Threads of Control.)
Thread myTimer = new Thread( new Timer(Thread.currentThread(),5000)); //Start Timer thread myTimer.start();
The Timer class
The Timer class, which is instantiated in Listing 8, is shown in its entirety in Listing 9.
class Timer implements Runnable{ Thread theCompilingThread; int delay;//time interval to sleep //-----------------------------------------------------// Timer(Thread theCompilingThread, int delay){//constructor this.theCompilingThread = theCompilingThread; this.delay = delay; }//end constructor //-----------------------------------------------------// public void run(){ try{ Thread.currentThread().sleep(delay); }catch(InterruptedException e){ //No action is required when this sleeping thread is // interrupted. return; }//end catch //Control is transferred to here when the sleeping // thread awakens naturally after the specified delay // period. This means that the compilation process is // probably hung up. Interrupt the compilation // process and terminate the run method. theCompilingThread.interrupt(); }//end run method }//end Timer class
The constructor
The constructor for the Timer class receives and saves two incoming values:
- A reference back to the compiling thread.
- The amount of time to count down in milliseconds.
The run method
The essential functionality of a Thread object is written into its run method, so that is what I will concentrate on.
The run method is executed after the code in Listing 8 invokes the start method on the Timer object.
(Apparently the start method takes care of some necessary tasks, and then invokes the run method on the Thread object.)
Go to sleep
The code in the run method begins by putting the timer thread to sleep for the specified delay interval (5000 milliseconds or 5 seconds in this case). The thread will sleep for that amount of time and then wake up and continue executing statements unless awakened prematurely.
Waking up prematurely
A sleeping thread is awakened prematurely when code that is executing in some other thread invokes the interrupt method on the sleeping thread. You will see shortly how that can happen in this program.
An InterruptedException
When a sleeping thread is awakened prematurely, it will wake up and throw an InterruptedException. This, in turn, causes the thread to execute the code in the matching catch block.
For now, just note that when the thread is awakened prematurely, no special action is required. The code in the matching catch block in Listing 9 simply executes a return statement, which causes the run method to terminate and the thread to die.
When the thread wakes up naturally
The case that is of particular interest to us at this point in the program is the case where the sleeping thread wakes up naturally after having slept for five seconds. When this happens, the code below the catch block in Listing 9 is executed.
The compiling thread must be hung up
The code in the compiling thread is responsible for completing the compilation process and invoking the interrupt method on the timer thread to awaken the timer thread before the five seconds has elapsed.
Therefore, if control reaches this point in the program, the assumption is that the waitFor method that was invoked on the Process object in the compiling thread is hung up in the wait state for some reason. It is also assumed that this is probably due to a compiler error.
Interrupt the compiling thread
Having concluded that a compiler error has probably occurred, the last statement in Listing 9 invokes the interrupt method on the compiling thread on which the waitFor method was invoked. This causes the waitFor method to terminate and to throw an InterruptedException, which in turn causes the code in the catch block in Listing 11 to be executed.
(I will explain the code in the catch block in Listing 11 shortly.)
The sequence of events
Returning now to a review of Listing 8, note that the code in Listing 8 instantiates the object of the Timer class and causes the run method to be invoked on that object, starting the five-second timeout interval to begin on the timer thread, which is running in parallel with the compiling thread that executes the code in Listing 8.
Then control moves to the code on the compiling thread shown in Listing 10.
System.out.println("Waiting for completion"); try{ p.waitFor();//wait for completion //The waitFor method has returned, if(myTimer.isAlive()){ //Stop the timer. myTimer.interrupt(); }//end if
Wait for the compilation to complete
After starting the five-second timer on the timer thread, the code in Listing 10 displays a message and then immediately enters a try block where it invokes the waitFor method on the Process object. This effectively puts the compiling thread to sleep also, awaiting completion of the compilation of the class file that was started in Listing 7.
If all goes well...
If all goes well, the compilation process will have completed (either successfully or unsuccessfully) before the five-second timer wakes up, and control will have passed to the if statement shown in Listing 10.
The if statement checks to see if the timer thread is still alive (meaning that it is still sleeping in this case) and if so, invokes the interrupt method on the timer thread to cause it to wake up prematurely. When the timer thread is awakened prematurely, it executes the code in the catch block in Listing 9. As mentioned earlier, this causes the timer thread to die quietly.
If things don't go well...
However, if the waitFor method fails to return within the five-second timeout interval of the timer, the timer thread in Listing 9 will awaken naturally and will invoke the interrupt method on the compiling thread running in Listing 10.
(Again recall that this is based on the assumption that the compilation should easily complete within five seconds. If five seconds has elapsed, it is assumed that the waitFor method is hung up, and it is also assumed that this is probably the result of a compiler error.)
This causes the waitFor method to terminate and to throw an InterruptedException, transferring control to the catch block shown in Listing 11.
}catch(InterruptedException e){ //The timer expired before the waitFor method // returned and interrupted the waitFor method. System.out.println("Compilation timeout error."); p.destroy(); return false; }//end catch
Handling the InterruptedException
The code in Listing 11:
- Displays a Compilation timeout error message,
- Invokes the destroy method on the Process object for the purpose of terminating the compilation operation that began in Listing 7,
- Terminates the compile method, returning a value of false to indicate a probable compiler error.
When the waitFor method returns within five seconds
The code in Listing 12 (at the end of the compile method) is executed only if the waitFor method that was called in Listing 10 returned during the five-second timeout interval.
//The waitFor method returned in five seconds or less. //p.exitValue() other than 0 indicates a compiler // error. return p.exitValue() == 0; }//end method compile
Not necessarily a successful compilation
The fact that the waitFor method returned within five seconds does not necessarily mean that the compilation was successful. For the amount of code being compiled in this program, one would hope that the method would always return within five seconds whether or not the compilation was successful.
(The fact that it frequently doesn't return within five seconds indicates some sort of an inter-process communication bug to me.)
The process exit value
In any event, there is an exitValue associated with the Process object. By convention, this value will be 0 for a successful completion of the process. The last statement in Listing 12 gets and compares the exitValue with 0, returning true for success and false for failure.
Back to the actionPerformed method
That brings us back to the code in the actionPerformed method of Listing 5 where the compile method was called with the return value of true or false being saved in a local boolean variable named compileStatus.
When the compilation is successful
Listing 13 shows the beginning of an if-else statement in the actionPerformed method that deals with the possibility that the compilation either was, or was not successful.
if(compileStatus){//If compile was successful. System.out.println("Compile complete");
The println statement in Listing 13 is executed when the compile process was successful.
(If you would like to do so, you can skip ahead to Listing 24 to see what happens when the compile process is not successful.)
Listing 14 continues with the behavior of the program as a result of a successful compilation.
Load/reload the class
At this point, the class has been defined (once by the program and possibly more than once by the user external to the program). The class has also been successfully compiled.
(In fact, the file may have been compiled many times with manual changes to the source code by the user in between compilations.)
In any event, a compiled class file is available at this point for loading or reloading.
Listing 14 invokes the method named reloadTheClass to cause the class file named Reload01a.class to be loaded. The method named reloadTheClass returns a reference to a Class object that represents the newly-loaded version of the class.
Class loadedClass = reloadTheClass("Reload01a", targetDir);
The code in Listing 14 passes the name of the class along with the directory containing the class file that is to be loaded to the method named reloadTheClass.
The method named reloadTheClass
The purpose of this method is to load a class that is specified by name as a String from a subdirectory specified by a File parameter named dir.
As I mentioned earlier, the class will be loaded using a class loader object of type URLClassLoader, which is a class in the standard Java class library.
The method named reloadTheClass begins in Listing 15.
static Class reloadTheClass(String reloadableClass, File dir){ URL[] theUrl = null;
An array reference variable of type URL[]
Listing 15 declares an array reference variable of type URL[] initializing its value to null. The code in the method will use the information about the directory containing the class file to create a URL object and will use that URL object to instantiate and populate the URL array object.
Create the URL object
At this point, we need to get a URL object that points to the directory containing the class file for the class that is to be loaded.
Following the recommendations in the Sun documentation, the code in Listing 16 converts the incoming File object to a URI and then converts the URI to a URL. The reference to the URL object is deposited in a new one-element URL array object. The array object's reference is stored in the reference variable named theUrl, which was declared in Listing 15.
try{ URI uri = dir.toURI(); URL url = uri.toURL(); theUrl = new URL[]{url}; }catch(Exception e){ e.printStackTrace(); }//end catch
Next step is to load the class
The next step in the process is to load the class, getting and returning a Class object that represents the class in the process.
Listing 17 declares a reference variable of type Class, which will be populated later with a reference to the Class object that represents the newly-loaded class.
Class theClass = null;
Get a URLClassLoader object
Listing 18 instantiates a new class loader object of type URLClassLoader associated with the directory containing the class file that is to be loaded.
try{ ClassLoader classLoader = new URLClassLoader(theUrl);
An array of URL object references
Note that the constructor for the URLClassLoader class requires an array of URL object references as an incoming parameter. The class loader object that is constructed is capable of loading classes only from the URLs that are specified by the references to URL objects stored in the array.
In this case, that list of URLs is restricted to the single directory containing the class that is to be loaded. However, for a larger program, it may be necessary to load classes from a variety of different URLs. If so, each of those URLs would be specified by references to URL objects stored in the array.
Load the class
Finally, the code in Listing 19 invokes the loadClass method on the URLClassLoader object, passing the String name of the class that is to be loaded as a parameter. The class loader object will search the specified URLs for which it was constructed, looking for a class file having the specified name and will attempt to load it if it is found.
theClass = classLoader.loadClass(reloadableClass); }catch (Exception e){ e.printStackTrace(); }//end catch
Success or failure in loading the class
If the load is successful, the loadClass method returns a reference to a Class object that represents the newly-loaded class. That reference is saved in the reference variable named theClass.
If the load is unsuccessful, the method throws a ClassNotFoundException. In this case, the exception handler simply prints a stack trace describing the problem.
Return the Class object's reference
Listing 20 returns the reference to the Class object that represents the newly-loaded class and terminates the method named reloadTheClass.
return theClass; }//end reloadTheClass
Note that if the load was unsuccessful, Listing 20 returns null.
Returning to the actionPerformed method
Returning once more to the code in Listing 14, which is part of the actionPerformed method being registered on the button shown in Figure 5, this code saves the reference to the Class object that represents the newly-loaded class in a reference variable named loadedClass.
Instantiate an object
Listing 21 invokes the newInstance method on the Class object to instantiate an object of the newly-loaded class, and saves the object's reference in a reference variable of type Object named obj.
Object obj = loadedClass.newInstance();
Need to invoke the method named theMethod
Our objective is to invoke the method named theMethod on the object instantiated in Listing 21. However, as explained earlier, it is not possible to invoke that method directly on the object's reference while the reference is being treated as type Object. It is also not possible to cast the object's reference to the class type Reload01a because the compiler knows nothing about that class at compile time. Therefore, another approach must be found to invoke the method named theMethod.
Will use reflection
This program will invoke that method using reflection. This entails invoking the invoke method on an object of the Method class that represents the method named theMethod belonging to the object of the newly-loaded Reload01a class.
Get a Method object
Listing 22 does the following:
- Invokes getDeclaredMethod of the Class class
- To get a reference to an object of type Method
- That represents the instance method named theMethod
- That requires two parameters, one of type String and the other of type double
- Defined in the class that is represented by the Class object
- Whose reference is stored in the reference variable named loadedClass.
Method methodObj = loadedClass.getDeclaredMethod( "theMethod", new Class[]{String.class,double.class});
(The method named theMethod belonging to the target object will be invoked later by invoking the method named invoke on the object of type Method, passing the target object's reference as a parameter to the invoke method.)
Note that nowhere does the code in Listing 22 mention the name of the target class, Reload01a.
The name of the target method
The first parameter passed to getDeclaredMethod specifies the name of the target method that will be invoked later. In this case, the name is theMethod, and the name of the method is passed as a reference to an object of type String.
Number and types of parameters
The second parameter specifies the number and types of parameters required by the method named theMethod. In this case, the method requires two parameters, one of type String and the other of type double.
Specify parameters in an array of type Class
Note that the number and types of the parameters are specified by passing a reference to an array object of type Class. The number of elements in the array specifies the number of parameters. In this case, the number of elements is two. The class (or type) represented by each of the Class objects referred to by the elements in the array specifies the types of the parameters. In this case, the types are String and double.
The target method could be overloaded
Keep in mind that a class could define many different overloaded versions of methods having the same name. In that case, a different Method object could be obtained for each overloaded version by invoking getDeclaredMethod more than once with the first parameter being the same in each case, but the second parameter being different in each case.
Save the reference to the Method object
The reference to the Method object returned by getDeclaredMethod is saved in the reference variable of type Method named methodObj.
Cause theMethod to be invoked by reflection
Listing 23 causes the method named theMethod to be invoked on the target object by invoking the method named invoke on the Method object, passing the target object's reference and a reference to a parameter array as parameters to the invoke method.
String returnVal = (String)methodObj.invoke( obj, new Object[]{"Hello",new Double(10.1)}); System.out.println(returnVal);
Display the returned value
The invoke method returns type Object. Listing 23 casts the return value from Object to String and stores it in a String variable named returnVal. Then Listing 23 displays the return value.
Passing parameters for the target method
Note that parameters for the target method are passed to the invoke method in an array of type Object. Each parameter occupies one element in the array. When the target method requires primitive parameters, they must be wrapped in an object of the corresponding wrapper class for passing to the invoke method. In this case, the double value 10.1 is wrapped in an object of type Double for passing to the invoke method.
The primitive parameters are automatically unwrapped by the system for delivery to the target method when it is executed.
Returned values
Similarly, when the target method returns a value of a primitive type, the invoke method wraps that value in an object of the corresponding wrapper class and returns it as type Object.
As a result, the code that calls the invoke method must cast the returned reference to the appropriate wrapper type and extract the primitive value from the wrapper object. That wasn't the case in this example because the return type for the target method was String.
Wrapping things up
Listing 24 shows the closing portions of the if-else statement that began in Listing 13. If the compilation process fails, the value of compileStatus is false. In that event, all of the code in the if clause of the statement is skipped, and the code in the else clause shown in Listing 24 is executed.
}//end if on compileStatus else{ System.out.println( "Probable compiler error."); }//end else
The code in the else clause simply displays a message on the command-line screen announcing a Probable compiler error. At that point, the user can correct the source code and click the button in Figure 5 to try again.
Complete the anonymous listener class definition
Listing 25 contains cleanup code for the actionPerformed method and for the anonymous listener class definition that began in Listing 4.
}catch(Exception ex){ ex.printStackTrace(); }//end catch }//end actionPerformed }//end new ActionListener );//end addActionListener
Complete the constructor
Finally, Listing 26 contains the cleanup code for the constructor that began in Listing 4.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(250,100); setVisible(true); }//end constructor
Listing 26 also signals the end of the program named Reload01. And that wraps up the explanation of the program named Reload01. Next, I will explain the more substantive program named Reload02.
The Program Named Reload02
The program named Reload02 is the plotting program that I described in some detail earlier. Therefore, I won't repeat that description here.
Two versions of the same program
I will present and explain two versions of this program in the two parts of this lesson. The version that I will explain in Part 1 (this document) uses reflection to access and execute the three methods (f1, f2, and f3) belonging to an object of a newly-loaded class named Reload02a.
In Part 2, I will present and explain a version of the program that uses a
common interface to access and execute those methods, thus avoiding the
complexity of reflection. I will also describe, but probably won't
demonstrate a third approach to dealing with the same issue.
Location of the class file
A new class file named Reload02a.class is created in a subdirectory of the current directory named temp. This class file defines three methods named f1, f2, and f3. The three methods are evaluated and plotted in the GUI shown in Figure 1.
If the subdirectory doesn't exist, it will be created. If a class file having the same name already exists in that subdirectory, it will be overwritten.
Program testing
This program was tested using J2SE 5.0 under Windows XP. Because this program uses static import directives, it requires J2SE 5.0 or later to compile and run successfully.
Will discuss in fragments
I will discuss this program in fragments. You will find a complete listing of the program in Listing 36 near the end of the lesson.
Plotting code has been explained before
Those of you who are familiar with my earlier publications may have recognized the plotting format shown in Figure 1 as being very similar to plotting formats that I have used in earlier lessons. In fact, the plotting code, as well as the code that manages the bottom portion of the GUI shown in Figure 1, is very similar to code that I have explained in earlier lessons.
The explanations in the earlier lessons began with the lesson entitled Plotting Engineering and Scientific Data using Java. Therefore, I won't bore you by explaining that code again. Rather, I will concentrate on code that is new to this lesson. If you are unfamiliar with the plotting code, please refer back to those earlier lessons.
The class named Reload02
The class named Reload02 is shown in its entirety in Listing 27.
class Reload02{ public static void main(String[] args){ new ScienceGraph(); }//end main }//end class Reload02
The main method in Listing 27 simply instantiates a GUI object of the ScienceGraph class as shown in Figure 1. Thus, most of the substance of this program is written into the GUI class named ScienceGraph.
The ScienceGraph class
The definition of the ScienceGraph class begins in Listing 28. As explained above, I deleted the plotting code from Listing 28 for brevity. You can view that code in its entirety in Listing 36 near the end of the lesson.
class ScienceGraph extends JFrame implements ActionListener{ //Plotting code deleted for brevity //Text fields for methods with default equations // inserted. JTextField f1Txt = new JTextField( "y = (x*x*x + 40*x*x + 100*x -6000)/100;",40); JTextField f2Txt = new JTextField( "y = (x * ((new java.util.Date().getTime())/" + "(new java.util.Date().getTime())));",40); JTextField f3Txt = new JTextField( "y = 100.0*(cos(x/10.0)*sin(x/11.0));",40); //Check box used to force rewrite, recompile, and reload // of the class. JCheckBox reloadCkBox = new JCheckBox( "Rewrite, Recompile, and Reload the Class " + "using the Above Equations",false); //Panels to contain a label and a text field JPanel pan0 = new JPanel(); JPanel pan1 = new JPanel(); JPanel pan2 = new JPanel(); JPanel pan3 = new JPanel(); JPanel pan4 = new JPanel(); JPanel pan5 = new JPanel(); JPanel pan6 = new JPanel(); JPanel pan7 = new JPanel(); JPanel pan8 = new JPanel(); JPanel pan9 = new JPanel(); //Misc instance variables int frmWidth = 475; int frmHeight = 430; int width; int height; //A reference to a newly-loaded class. Class loadedClass = null; //Plot is drawn on this canvas MyCanvas canvas;
Although long and tedious, the code in Listing 28 simply declares a large number of instance variables used later in the program. The comments in Listing 28 should suffice and no further explanation of the code in Listing 28 should be required.
Implements the ActionListener interface
It is worth noting, however, that the ScienceGraph class implements the ActionListener interface. Therefore, an object of the ScienceGraph class can and will be registered on the button in the bottom of Figure 1 to listen for action events on that button.
The constructor
The constructor for the ScienceGraph class begins in Listing 29.
ScienceGraph(){//constructor System.out.println( "Write, compile, and load initial class file."); boolean compileStatus = updateClass(); if(!compileStatus){ System.out.println( "Unable to compile initial class"); }//end if
The updateClass method is invoked in Listing 29 for the purpose of writing, compiling, and loading an initial class file. The updateClass method returns true on success and false on a failure to compile.
The returned value from the updateClass method is stored in the boolean variable named compileStatus. If the returned value is false, the code in Listing 29 posts an Unable to compile initial class message on the command-line screen.
The updateClass method
Setting the discussion of the constructor aside for awhile, Listing 30 shows the beginning of the updateClass method.
boolean updateClass(){ boolean compileStatus = false; try{ //Create a File object that points to a directory // where the class file will reside. File targetDir = new File( System.getProperty("user.dir") + File.separator +"temp" + File.separator); //If the directory doesn't exist, make it. if(!targetDir.exists()){ targetDir.mkdir(); }//end if //Get an output stream for writing the source code // for the new class file. DataOutputStream dataOut = new DataOutputStream( new FileOutputStream("temp" + File.separator + "Reload02a.java"));
Very similar code
Because this program uses the same methodology for compiling, loading, and instantiating classes, and for invoking the methods belonging to the objects of those newly-loaded classes, much of the code in this program is very similar to code that was explained earlier in conjunction with the program named Reload01.
(The purpose of presenting and explaining the program named Reload01 was to explain the code necessary to support those concepts in a relatively simple program.)
Won't repeat the explanation
In those cases where the code in this program is very similar to the code in the earlier program, I won't bore you by repeating the explanation. Rather, I will simply refer you back to the earlier explanation.
For example, the code in Listing 30 is very similar to the code that was explained in conjunction with Listing 3 earlier. Please refer to that explanation and mentally apply it to the code in Listing 30
Create the class file source code
This program creates the source code for three different class files whereas the program named Reload01 created the source code for only one class file. In addition, the definitions of the class files in this program are based on information provided by the user in the three text fields shown at the top of the GUI in Figure 1.
The code in Listing 31 causes the source code files for the three class files to be written.
//Get the equations from the text fields. String eq1 = f1Txt.getText(); String eq2 = f2Txt.getText(); String eq3 = f3Txt.getText(); //Create the source code for the new class file. dataOut.writeBytes( "import static java.lang.Math.*;" + "public class Reload02a{" + "public double f1(double x)"+ "{" + "double y = 0.0;" + eq1 + "return y;" + "}" + "public double f2(double x)"+ "{" + "double y = 0.0;" + eq2 + "return y;" + "}" + "public double f3(double x)"+ "{" + "double y = 0.0;" + eq3 + "return y;" + "}" + "}" );//end writeBytes method dataOut.close();//Close the output file.
Get the text from the text fields
Listing 31 begins by invoking the getText method to extract the current text from each of the three text fields at the top of Figure 1. This text is saved in the String variables named eq1, eq2, and eq3.
Insert the text into skeleton methods
Then those three strings are concatenated into strings that provide the skeletons for three methods named f1, f2, and f3. Those strings are written into the output file named Reload02a.java in a manner very similar to that explained for Listing 3 earlier in the lesson.
Compile and load the class file
The remainder of the updateClass method shown in Listing 32 compiles and loads the class file in a manner very similar to that explained for Listing 5 through Listing 20 earlier.
//Now compile the new class file compileStatus = compile( "temp" + File.separator + "Reload02a.java"); if(compileStatus){ System.out.println("Compile complete"); //The class has been defined and compiled. Now // force it to be loaded. //Get a URL object that points to the directory // containing the class file. A File object that // points to that directory was created earlier. //The compiled class file for the reloadable class // is stored in a directory that is pointed to by a // reference variable of type File named targetDir. //Following the recommendations in the Sun docs, // convert the File object to a URI and convert the // URI to a URL. Deposit the reference to the URL // object into an one-element array of type URL. URI uri = targetDir.toURI(); URL url = uri.toURL(); URL[] theUrl = new URL[]{url}; //Create a new class loader associated with the // directory (URL) containing the reloadable class. ClassLoader classLoader = new URLClassLoader(theUrl); // Load the specified class, creating a Class // object that represents the class in the process. loadedClass = classLoader.loadClass("Reload02a"); }else{ System.out.println("Probable compile error"); }//end else }catch (Exception e){ e.printStackTrace(); System.exit(0); }//end catch return compileStatus; }//end updateClass method
Returning to the constructor
Now, returning to the discussion of the constructor from Listing 29 above, Listing 33 assembles the GUI shown in Figure 1 by creating and adding various components to the JFrame object. The boldface code in Listing 33 registers the object of the Reload02 class as an action listener on the Graph button shown in the bottom of the GUI in Figure 1.
//Now build the GUI. canvas = new MyCanvas(); JPanel southPanel = new JPanel(); //Set the layout manager to GridLayout with // 2 rows x 4 cols southPanel.setLayout(new GridLayout(2,4)); JPanel northPanel = new JPanel(); northPanel.setLayout(new GridLayout(4,1)); //Button for replotting the graph JButton graphBtn = new JButton("Graph"); graphBtn.addActionListener(this); //Populate each small panel with a label // and a text field pan0.add(new JLabel("xMin")); pan0.add(xMinTxt); pan1.add(new JLabel("xMax")); pan1.add(xMaxTxt); pan2.add(new JLabel("yMin")); pan2.add(yMinTxt); pan3.add(new JLabel("yMax")); pan3.add(yMaxTxt); pan4.add(new JLabel("xTicInt")); pan4.add(xTicIntTxt); pan5.add(new JLabel("yTicInt")); pan5.add(yTicIntTxt); pan6.add(new JLabel("xCalcInc")); pan6.add(xCalcIncTxt); pan7.add(new JLabel("f1")); pan7.add(f1Txt); //Make the color of the labels that identify the // equations for f2 and f3 match the color that will // be used to plot those two equations. f1 is // already black so I didn't need to change its color. JLabel f2Label = new JLabel("f2"); f2Label.setForeground(Color.RED); pan8.add(f2Label); pan8.add(f2Txt); JLabel f3Label = new JLabel("f3"); f3Label.setForeground(Color.BLUE); pan9.add(f3Label); pan9.add(f3Txt); //Add the populated panels, the button, and the check // box to the control panels for the South and North // locations. southPanel.add(pan0); southPanel.add(pan1); southPanel.add(pan2); southPanel.add(pan3); southPanel.add(pan4); southPanel.add(pan5); southPanel.add(pan6); southPanel.add(graphBtn); northPanel.add(pan7); northPanel.add(pan8); northPanel.add(pan9); northPanel.add(reloadCkBox); //Add the sub-assemblies to the frame. Set the frame's // location, size, and title, and make it visible. getContentPane().add(northPanel,BorderLayout.NORTH); getContentPane().add(southPanel,BorderLayout.SOUTH); getContentPane().add(canvas,BorderLayout.CENTER); canvas.setBackground(Color.WHITE); setBounds(0,0,frmWidth,frmHeight); setTitle( "ScienceGraph, Copyright 2006, Richard G. Baldwin"); setVisible(true);//Make the GUI visible //Set to exit on X-button setDefaultCloseOperation(EXIT_ON_CLOSE); //Get and save the size of the plotting surface width = canvas.getWidth(); height = canvas.getHeight(); //Cycle visibility once to force the initial methods // to be displayed. There must be a better way to // accomplish this. Without this, the initial // methods are not displayed at startup. This // appears to be the result of a timing problem // involving compilation, etc. setVisible(false); setVisible(true); }//end constructor
Although the code in Listing 33 is long and tedious, it is straightforward and shouldn't require any explanation beyond that provided in the comments. If you are unfamiliar with this kind of code, you may want to review my earlier tutorial lessons on the topic that you will find here and here.
The actionPerformed method
As mentioned earlier, because the Reload02 class implements the ActionListener interface, an object of the class can be, and is registered on the Graph button at the bottom of the GUI shown in Figure 1. (See the boldface code in Listing 33.) Also, because the Reload02 class implements the ActionListener interface, and the class is not declared abstract, the class must define the interface method named actionPerformed.
The actionPerformed method, with some of the plotting code deleted for brevity, is shown in Listing 34.
public void actionPerformed(ActionEvent evt){ System.out.println("nExecuting actionPerformed"); //Plotting code deleted for brevity. boolean compileStatus = true; if(reloadCkBox.isSelected()){ //Clear the checkbox, recompile, and reload. reloadCkBox.setSelected(false); compileStatus = updateClass(); }//end if on reloadCkBox.isSelected() if(compileStatus){ //Repaint the plotting surface canvas.repaint(); }else{ System.out.println("Unable to compile new class"); }//end else }//end actionPerformed
This event handler is registered on the button to cause the methods to be re-plotted. In addition, if the checkbox at the top of the GUI is checked, the class is rewritten, recompiled, and reloaded before being evaluated to produce the plots.
If the check box is checked...
If the check box at the top of the GUI is checked, the updateClass method discussed earlier is invoked to recompile and reload the class.
If the recompilation is successful, the repaint method is invoked on the Canvas object to cause the methods named f1, f2, and f3 to be evaluated and plotted. If the recompilation is unsuccessful, an Unable to compile new class message is posted on the command-line screen and no attempt is made to evaluate and plot the methods.
The remaining program code
All of the remaining code in the program, including the overridden paint
method, is either plotting code that is very similar to code that was explained
in earlier lessons, or code that is very similar to code that was explained
earlier in this lesson in conjunction with the program named Reload01.
Therefore, I won't explain the remaining code in the program. You can view
the remaining code in Listing 36 near the end of the lesson.
Page 1 of 2
IT Solutions Builder TOP IT RESOURCES TO MOVE YOUR BUSINESS FORWARD
Which topic are you interested in?
Data Storage
IT Management
What is your company size?
What is your job title?
What is your job function?
Searching our resource database to find your matches...


text:
Gordonebyers necesitaba un nuevo diseño de logotipo y lanzó un concurso de diseño en 99designs.
Un ganador ha sido elegido entre 118 diseños de 24 diseñadores freelance.
Byers Dental Group
We are a father and son dental practice in Vero Beach, FL. We deire a logo that we can use to brand us and for recognition in the community we practice. The practice was started by the father in 1974 and is well respected.
All people within our community. We want the logo to signify quality. We want to be able to use the logo for community recognition, office sign, stationary, etc.
1) logo that signifies quality, however not to busy or fancy. Clear and bold.
2) I do not want the logo to have teeth or a tooth brush as part of it. This is cheesy. No cartoons.
3) Byers Dental Group should be part of the logo.
4) I like the color blue most of all, but you can experiment with colors. Would like to be able to change the logo color letters depending on the color background. Have seen some white lettering on a blue backgroung that is nice.
5) I would like the logo " Byers Dental Group" to be able to stand alone for advertising sometimes and easily add the dentists names to it especially for stationary, sign, etc. The dentists names and titles are Gordon E. Byers, D.D.S., P.A. and John C. Byers, D.M.D.
6) May be able to do something creative with the inital B for Byers above the name Byers Dental Group.
7) A slogan may be nice as part of the logo: A Commitment to Excellence
Descubre cómo funciona un concurso de diseño u obtén más información sobre nuestros servicios de diseño de logo.

subset: commoncrawl


text:
Although the Highwaymen are the largest motorcycle club in the city, they are excluded from the Detroit Federation of Motorcycle Clubs as they have a reputation as a criminal organization. The club has undergone a number of large-scale police and FBI investigations, most notably in 1973, 1987 and 2007.
Criminal activities
On May 5, 2007, the Federal Bureau of Investigation arrested forty members and associates of the Detroit chapter of the Highwaymen on a number of charges including racketeering, murder for hire, assault, police corruption, cocaine trafficking, vehicle theft, and mortgage and insurance fraud. Twenty-nine illegal firearms, including assault rifles, shotguns and handguns, were also found when FBI agents raided homes and the chapter's clubhouse. The investigation in to the club lasted two years and involved wiretaps and two informants, one of which was eventually murdered.
High-ranking Highwaymen member Randell Lee McDaniel was arrested for running a chop shop in Lansing, Michigan on June 13, 2007. The investigation by the Monroe County Auto Theft Enforcement began in October 2006 and served several search warrants on properties owned by McDaniel. He was charged with conducting a criminal enterprise, operating a chop shop, motor vehicle theft and possessing a controlled substance.
Four police officers and a member of the Highwaymen were indicted on March 12, 2008 by a federal grand jury in Detroit on charges stemming from the 2007 investigation into drug trafficking. Highwaymen member Sean Donovan, who was already incarcerated on stolen property charges, was charged with possession with intent to distribute marijuana and Vicodin. The four police officers were also jailed for corruption.
A Highwaymen-run methamphetamine lab in Eaton Rapids, Michigan was raided by the Tri-County Metro Narcotics Squad and Michigan State Police Emergency Response Team on February 14, 2009. Forty pounds of anhydrous ammonia and a variety of chemicals and equipment that are used to manufacture the drug were found on the scene, as well as methamphetamine itself. One man was arrested at the scene and several others were later apprehended.
Highwaymen MC
Founded: 1954 in Detroit, Michigan, United States
Years active: 1954-present
Territory: Midwestern and Southern United States
Ethnicity: Predominantly White
Membership: 200+
Criminal activities: Drug trafficking, arms dealing, assault, auto theft, contract killing, chop shop, prostitution, extortion, money laundering, mortgage fraud, insurance fraud, police corruption, and Racketeering
Allies: Sons of Silence
Rivals: Black Pistons and Outlaws
See also: Biker Gangs


text:
I don't think I'll be able to fit it in the refrigerator. I can go through a small bag in about 2 weeks.
My flickr food photos account:
Rice lasts a good long time, I'm sure you'll be fine. A small bag has to be at least a pound, right? Then your 15 pound bag will last 30 weeks. That's a bit more than 6 months, and rice has to last at least that long between harvests anyway.
Why would you want to put it in the fridge? I'd think that would be the last place you'd want to keep it. You want to put it somewhere dry.
My blog is Food and Shoes
15lbs is 6.8kgs. Where I live a small bag is usually around half a kg (500g) so I'm guessing the same as Bronwyn, that you'll get through it within 6 or 7 months (when I was single 15lbs wold have lasted me around 3 months).
If the rice is white and not brown (bran oils can go a bit rancid when stored over long periods) it's unlikely you'll notice much of a difference between the same rice now and how it tastes in September/October... although you might need a smidgen more water to cook it with then, then again, you may not notice this difference either.
I agree, the fridge isn't the place to store raw white rice. Somewhere dark, dry and where flying or crawling pests can't get at it is all you need.
As neither my husband or I drive, and in order to save money, our backs and delivery costs, we've been buying rice in bulk lately. I bought two 10kg bags of rice in February (about 45lbs). From the looks of it we get through one of these every two months as we're just coming to the end of the second bag. I'll probably get three bags on my next order, so these should last us the same amount of time as your 15lb bag - my guess is that the rice we get will be from exactly the same batch as before, this means I'm expecting our rice to taste fine after 10 months - and that's on top of the time it took to get from the USA to the UK.
The new US grown crops won't be harvested until sometime in September, so I think it's fine to have rice stored until the Autumn/Fall. Once we reach October I'll look at acquiring rice from the new crops.
Bronwyn, are there rice harvests going on in NZ or Austalia? I'm not obsessed enough to look for new rice from the South but I am curious.
We don't grow rice at all in New Zealand, but yes, they should be harvesting it in Australia about now. Which means that most of the rice in my cupboard is at least one year old. My Jasmine and Basmati are grown elsewhere though.
The SunRice brand is Australian.
Thanks guys! I actually found a store that offered smaller bags of good quality rice at the same price per pound as the large bag I found online. Thanks for letting me know about the fridge- I thought I read that it was important to keep rice in the fridge.
You only need to keep rice in the fridge if it's been cooked, it goes a bit sticky though; I wouldn't eat it plain, it'd have to be fried for me.
|Last Post
|Sesame salad dressing
|5 years 12 weeks ago
|Authentic paella?
|5 years 13 weeks ago
|IMPORTANT: If you have a blog on JustBento...
|5 years 16 weeks ago
|Shiso - uses for this herb
|5 years 18 weeks ago
|Fuki (Japanese Butterbur) Tsukemono Recipes
|5 years 18 weeks ago
@justbento - strictly site updates
@makiwi - Maki tweets at random


text:
Mayor Don Wesely today released Lincoln sales tax figures for February showing that net sales tax collections are up 15.4 percent compared to the same month last year and exceeded $5 million for the first time. The net sales tax revenue is up 11 percent for the first six months of this fiscal year, which began September 1. The figures reflect December sales, which are reported to the state in January and received by the City in February.
"December figures are very important for retailers and for the City because they reflect the level of holiday shopping," said Mayor Wesely. "We projected that sales tax revenue would rise 4.9 percent this fiscal year, so we are very encouraged that the growth is far surpassing our estimate."
Sales tax revenues fund about 42 percent of the City's tax-supported budget. Property tax revenue funds about 28 percent of the budget, with the remainder coming from fees, interest income and other sources.
Net sales tax revenue for February was $5,163,582, which is $230,894 higher than what the City had projected. Net sales tax revenue is calculated by subtracting refunds to businesses for LB775 tax credits from gross sales tax revenues. Gross sales tax revenues increased 4.9 percent for February, and sales tax refunds decreased by 88 percent, resulting in the 15.4 percent net sales tax revenue increase.
Media Release


text:
Organizing for Action:
You In?
Our work didn't end on Election Day.
Organizing for Action will support the legislative agenda we voted on, train the next generation of grassroots organizers and leaders, and organize around local issues in our communities.
Watch this video the First Lady recorded about the next step of this grassroots movement, and say you're in:


text: The mission of the Academic English Program (AEP) is to provide the highest quality of English language instruction for academic purposes to students of higher levels of English proficiency. The credit-bearing undergraduate coursework offered by the AEP integrates international students into Saint Michael's College undergraduate and graduate courses. Students who complete this program are prepared to meet the academic and cultural expectations of US institutions of higher learning.


text:
August 22-24 Amazing Arachnids in Spiders Alive! main content.
by AMNH on
Arachnophobes and 'philes alike will get a kick out of the spectacular spiders featured in the live animal exhibition Spiders Alive! —20 species of live arachnids (including 16 spider species, two scorpion species, a vinegaroon, and African whip spiders), ranging from the reclusive trapdoor spider to the goliath bird eater spider, one of the biggest spiders in the world.
Spiders evolved more than 300 million years ago, long before dinosaurs walked on Earth, and scientists have identified more than 44,500 spider species so far!
True or false: spiders have good eyesight.
False! Nearly all have eight simple eyes, but for the most part, don't see very well. In most cases, spiders use other senses, like touch and smell, to help capture prey. Learn more in our Spiders: True or False?
Scope out spiders in their habitats and get up close with amazing arachnids, like the Chilean rose hair tarantula and emperor scorpion, in live presentations by Museum staff that take place throughout the day.
To cap off your arachnid adventure, jump up on the climbable spider model, a trapdoor spider enlarged to 50 times life size.
Check out this video of Curator Norman Platnick as he answers pressing spider questions such as, "Is it better to be bitten by a black widow or a brown recluse?" and "Why don't spiders get stuck in their own webs?"
Spiders Alive! is open now through November 2. Purchase your tickets today.


text:
Cory Gunz & Mickey Factz Freestyle On The Deal
King County reports "Cory Gunz and Mickey Factz rip the booth to break in the new year on the show The Deal "
Please click the "Report" button below if the video on this page is not working properly.
Comments will only be displayed by verified emails. No Spamming or Racism.


text:
Tao Tao House is owned by ex-Flower Drum chef Jason Au, which carries with it some pressure. I'm pleased to say that the food lived up to my expectations, especially the most amazing dish of the day, Spicy Beef Tendons. This dish is so good that I would go back just on the strength of this dish alone. We all loved it and got another serving after we quickly ate the first.
The dim sum in general were all of a high standard. Items like siu mia, char siu bao and char siu rolls which I don't usually like, were good. Chicken feet was excellent, as was the fried prawn rolls. Of the two steamed rice rolls, the prawns were good but the beef and mushrooms was the only dish of the day that I disliked. It just tasted super weird.
Steamed dumplings all had great thin skin and good filling. Har gow were superb and other steamed items like chive dumplings, corn and prawn dumplings, bean curd wrapped chicken and fish paste on burn curd were all good.
I thought we would end our meals with some egg tarts, but Allan had other ideas. While we still got the egg tarts, which were very good, Allan also ordered mango pancakes, mochi ice cream balls and custard buns. All were excellent, especially the mochi ice cream balls and custard buns.
The restaurant was surprisingly quiet during the early sitting that we dined. This may have led to better service, but I think the normal service would be good still as the wait staff all seemed clued-in. The room itself is nicely decorated and has a regal Chinese feel with good furniture and decorations. The food carts were rolled out quite quickly and explained clearly, which I like as it's hard to guess what's what sometimes. Price wise, it wasn't any more expensive than other places and was fair for about $25 per person. I would definitely go back to have more yum cha at Tao Tao House, and be ordering two of that tendon dish every time.
Overall Rating: 14/20, Good yum cha in a very nicely decorated restaurant.
Scores: 1-9: Unacceptable, don't bother. 10-11: Just OK,some shortcomings. 12: Fair. 13: Getting there. 14: Recommended. 15: Good. 16: Really good. 17: Truly excellent. 18: An outstanding experience. 19-20:Approaching perfection, Victoria's best.


text:
Radiation from Airport Scanners -- How Much Dose We Get
Media Contact
Our Public Position Statements section includes AAPM positions and opinions on a number of issues of public interest.
Representatives of the media should contact Lisa Rose Sullivan for further information on these and other issues related to medical physics and the activities of the AAPM.
The AAPM also operates a virtual press room at its annual meetings. Follow the Annual Meeting icon top center of this website to locate the virtual press room.


text:
Welcome and Blessings.
This is my space for my free digital scrap-booking kits. I am taking a little break from designing scrap kits, but I shall post free kits from time to time. I am concentrating on Poser at the moment.
thank you so much for today's beautiful portion!
Hello and Thank you for these pretty pieces...


text:
With the deaths that have recently surfaced caused by esophageal perforation following cryoablation procedures for the treatment of atrial fibrillation, Dr. John Mandrola (a fellow colleague and EP-blogger) delves deeper into the incidence, issues, and current recommendations that might improve the safety of the procedure over at theHeart.org today. It's an excellent review of the current state of the art as he's been able to review it. Go now and read his piece.
Of course, as Dr. Mandrola points out, although the incidence of this deadly complication is rare, there is still much we don't know about this procedure's long-term safety, especially as newly-engineered cryoballoons enter the EP community's ablation toolkits. Careful long-term assessment of this technology's safety and efficacy, as well as its safety compared to more conventional radiofrequency ablation techniques for pulmonary vein isolation, remain unknown.
Monday, April 22, 2013
To Burn or Freeze During Catheter Ablation of Atrial Fibrillation, That Is the Question
2 comments:
- Richard Kato said...
I have been referred to a MD who is performing his first cryoablations for paroxysmal atrial fib. There is a sense that you are still weary about cryoablation for atrial fib. Is cryoablation done in the Chicagoland area?
- Sat May 04, 09:59:00 AM CDT
- Dan Walter said...
Catheter ablation for afib is a corporate-driven procedure that is riskier and less effective than advertised.
I recommend this post by Dr. David Mayer: http://educatetheyoung.wordpress.com/2013/04/14/collateral-damage/
- Fri May 10, 09:07:00 AM CDT
Subscribe to: Post Comments (Atom)


text:
The Hamptons Collection boasts clean, modern lines, reminiscent of the yachts that sail off the coast of this group's namesake. Celebrate brisk New England Americanism with this comfortably refined collection. Versatile roominess and understated elegance means The Hamptons Collection is easily adaptable to multiple room and decor styles. Self-expression is also a crucial feature of this set; it easily takes a central, comfortable place in any living room, but is just as impressive on the terrace. Free-standing sectional units can be arranged as a continuous seating arrangement or moved about to create intimate conversation nooks. Durable loom woven wicker over sturdy aluminum supports makes this the perfect choice for any outdoor living area.
Additional Information


text:
The most expensive piece of meat in the world – costing about "US $12,000 per kilo" (2.2 pounds) – does not come from a ranch but a laboratory. The meat is grown in vitro, without killing a living animal.
The material required for in vitro meat is gathered by "a relatively harmless muscle biopsy from a pig, cow, sheep, chicken," says Nicola Jones, author of a recent article on in vitro meat. From this extracted muscle tissue, researchers separate myosatellite cells, which are adult stem cells used to grow and repair the animal's muscles after exercise or injury.
Stem cells are important to this process because they can self-divide and multiply their numbers to create a mass of cells where there once was only one. These myosatellite cells are incubated in a petri dish with a substance designed to cause cell division and provide nutrients for muscle growth.
Yet the practice has not quite caught up to the theory. There are a number of hurdles that scientists must overcome before large-scale growth can occur.
"The myosatellite cells will divide only a limited number of times," according to Jones, making it difficult to produce high volumes of meat.
Mark Post, a physiology professor at Eindhoven University of Technology in the Netherlands, for example, has been unable to produce enough meat to make a single sausage, which will "require another year of research and at least $250,000".
Additionally, the muscles atrophy without the animal to exercise them naturally. Post describes the meat he has produced as "weak and without texture." Although researchers are forbidden from tasting their creations, Post describes a TV journalist who stealthily ate a piece and described it as "chewy and tasteless." The price and taste of in vitro meat must be dramatically improved before artificial meat is "even remotely competitive with current products," says Post.
Despite lacking feasibility for large-scale production, in vitro meat inspires excitement because it is an alternative to status quo meat production, which is increasingly viewed as ecologically unsustainable.
Modern meat production causes many forms of "environmental degradation," says a report published in Environmental Health Perspectives (EHP). The report continues, "meat production contributes disproportionately to these problems, in part because feeding grain to livestock to produce meat – instead of feeding it directly to humans – involves a large energy loss."
A New York Times article estimates that "two to five times more grain is required to produce the same amount of calories through livestock as through direct grain consumption." Despite this inefficient trade-off, "roughly one third of grain is consumed by domestic animals," says Joel Cohen, professor of population studies at Columbia University.
By not requiring food, in vitro meat frees up grain resources, which reaps "environmental benefits" and "benefits against world starvation," according to Post.
What do you think? Will lab-grown meat help nourish the planet? Tell us in the comments.
• Grant Potter is a development associate and executive assistant to the president of Worldwatch.
• To purchase your own copy of "State of the World 2011: Innovations that Nourish the Planet," please click HERE. And to watch the one-minute book trailer, click HERE.
• This article originally appeared at Nourishing the Planet, a blog published by the Worldwatch Institute.


text:
Miguel Cotto and Manny Pacquiao to Fight Nov 14!
A deal has been completed for boxing's biggest fight of the fall: a showdown between pound-for-pound king Manny Pacquiao and welterweight titleholder Miguel Cotto.
Please click the "Report" button below if the video on this page is not working properly.
Comments will only be displayed by verified emails. No Spamming or Racism.


text:
Log Out
Our Terms of Use and Privacy Policy have changed. We think you'll like them better this way.
Current, pertinent and information dense this is your link to late breaking grass roots news and regional calender announcements in Kansas and beyond.
Listening Post Program Schedule:
Free Speech Radio News - Headlines
Regional event briefings, across the area there are many organizations and groups meeting to create public opinion for progressive change in this the "reddest of red" region of the country. Keep your scheduler, note book and planner open for quick notices.
Building Bridges: Your Community Labor Report, hosted by Ken Nash and Mimi Rosenberg from WBAI-FM New York City. The award winning half hour national edition of the full program, available as as a live stream from New York.
Free Speech Radio News - Complete 30 min.broadcast of the latest news from around the world. FSRN started from a news reporters labor strike in the last century and has since grown to over 100 radio stations worldwide. Professional quality, generated by over 200 reporters across the planet it is "an ear to the ground, a voice on the air."
Sorry we couldn't complete your registration. Please try again.
You must accept the Terms and conditions to register


text:
Jenifer Gillen Cohn writes, "When I first met "Mr. Gillen," he was sharing a studio with four other artists/illustrators in downtown New Milford, CT. In his 1956 article in American Artist, Norman Kent says, "I found him (Denver) in a studio building occupied by several illustrators and enjoying a camaraderie with them more typical of the past than is usually possible at the present in a big city."
"Pop shared a floor above retail space with Robert Kuhn,"
"Walter Skor,"
"John Clymer,"
"and C.E. Monroe (who I don't remember)."
"As you can imagine, it seemed quite normal to hang around these artistic types."
"[After he moved his studio home] Pop stayed in touch with Bob Kuhn, Walter Skor and John Clymer. They were great friends and we visited one another's homes often. Fortunately, the wives all got along, too. And, we kids did have fun with the similarly aged children of the Kuhn's."
"I know, from overhearing my parents talk, that Walter Skor had tremendous trouble promoting himself and had an agent. I think things were harder for him than the others in that respect. He eventually branched out and started doing framing for other artists -- beautiful works of art in their own right. Remember, though, that the art world in New York at that time was a smaller place. I'm pretty sure that all of these guys shared information and passed around ideas and contacts."
"I think that there have always been "starving" artists, and it's the rare and pit bull types that weather the ups and downs and/or pursue other types of work to continue in the career they love."
"Pop was very concerned about the growing tendency by magazines, even in his day, to use photography as a way of illustrating stories."
"He was aware that there was a growing trend that was narrowing the opportunities for the illustrator. I can't remember exactly when I first heard the conversations, but it was probably before I went to Boston University."
"I became acutely aware of Pop's wariness of photography vs illustration when I decided to take a photography course at BU. This was after I left the School of Fine Arts. I had decided to take time out from pursuing a "fine arts" path. I knew it wasn't for me, and quite frankly, I wasn't terribly good. I did learn so much, though, about color and design, but I just didn't like paint. Really. I hated oils in particular."
"Pop really did not like the direction that I was going in, but, really, drawing was very hard for me, and I guess he figured this was better than nothing. But, the disappointment was apparent. We had philosophical discussions about photography vs illustration. Fine art vs illustration. Graphic art vs illustration."
"I do remember that Pop had been doing quite a bit of textbook illustration (for Ginn & Company, I think, and others). This was while I still lived in at home in Connecticut, so that would have been in the late 50s, early 60s. And, he did not enjoy this type of work; very boring."
[Note: the examples show here are from the Childcraft series of textbook/encyclopedias, c. 1964 - Leif]
"Pop told me he "was not a genius" and would never be a superstar like Picasso. He had to earn a living, too, he said, because he liked living a good life, so being an illustrator gave him the best of both worlds."
Jenifer's narrative concludes... tomorrow.
Denver Gillen Flickr set.
Celebrating illustration, design, cartoon and comic art of the mid-20th century.
Thursday, December 06, 2007
Denver Gillen: Earning a Living as an Illustrator
1 comment:
Charlie Allen emailed the following comment to me. I'm posting it here with his permission:ReplyDelete
LEIF....As usual, enjoying this week's blog on Denver Gillen. Never recorded his work or his name on my very busy mind in the 50's. Admire his economy of style, yet getting it done....again proving what you leave out as important as what you put in. Had to learn that the hard way! Also, such a difference of assignments back there, and yet such similarity with deadlines and nature of the biz. Inspirationally speaking, thanks again! Chas.
Subscribe to: Post Comments (Atom)