For a listing of bug fixes and enhancements included in
this release, please visit our bug
database.
The purpose of the Openwings container implementation is
to allow multiple Java process to be run inside the same
JVM. There are several goals that we aimed to achieve with
our implementation:
- Reduce the footprint of an Openwings system by running
fewer JVMs. Core Java classes (java.*, javax.*, etc.)
are shared between processes.
- Processes running inside a container (shared JVM) should
be completely isolated from each other and not able to
affect each other.
- Any legal Java process should run successfully without
modification inside the container (Note: this is different
than a J2EE environment where EJBs cannot perform certain
functions like threading).
Our implementation is mostly successful in acheiving these
goals. However, since the Java language does not have a
proper process abstraction to date, there are some caveats,
as well as behaviors we've had to limit.
In the meantime, we've had a large degree of success in
our container implementation. We've been successful in isolating
processes in several key aspects:
- Thread management. Each process is executed in
its own ThreadGroup and may not access threads from another
process. When a process stops, its threads are cleaned
up.
- Class scope. Each process is isolated in its
own ClassLoader.
- AWT/Swing. Processes can open and close windows
freely. If a process stops without closing a window, the
container detects this and cleans up the process window.
- Property access. Each process has its own set
of system properties.
- Security policy. Each process has its own security
policy applied to it.
- Exit. System.exit() and Runtime.exit() are trapped
so that when a process calls these methods, it is stopped
without shutting down the entire JVM.
- Output. The System.err and System.out streams
have been replaced so that the output of each process
is redirected to a separate log file.
There are practical reasons for not running some Java processes
in the Openwings container reference implementation. Here
is a summary of known weaknesses of the container implementation:
- Memory usage. The JVM is being run with a memory
limit. If one process uses up all the memory, other processes
will get OutOfMemoryErrors. There is no way to partition
or allocate the memory of the JVM between different processes.
- CPU usage. If a process in the container goes
into an infinite loop, it can lock out other processes
in the container. There is no way to monitor the CPU usage
of a particular process within a container. A possible
mitigation would be to lower the priority of a process's
root thread group, although we have not explored this
yet.
We've also had to limit certain functions that would be
allowed to a regular Java program:
- System.setSecurityManager(). This will always
result in a SecurityException. The container has a single
security manager that may not be replaced.
- System.setProperties()/getProperties(). This
will always result in a SecurityException. The container
has a single properties object that may not be replaced.
However, system properties are isolated between processes,
and System.setProperty()/getProperty() is allowed.
- System.setOut()/System.setErr(). This will always
result in a SecurityException. The container controls
where the output of each process goes.
- Thread(). This is one of the most intricate parts
of the container implementation. Using methods such as
Thread.getThreadGroup(), ThreadGroup.getParent(), ThreadGroup.enumerate(),
it is possible to navigate the entire thread model of
a JVM. We have decided to allow processes to only create
and access threads in their own thread groups.
The threading limitations deserve a fuller explanation,
especially since they are new in the 0.9.2 release.
Everyone would agree that processes in a container should
not be allowed to access the threads and thread groups of
other processes, or the threads used to manage the container
itself. What is more controversial is our decision to protect
access to thread access and creation in the JVM's core thread
groups. This includes the JVM thread groups called "main"/"system",
"AWT" and "RMI". By default, process
code may not create threads in these thread groups (note
that threads created by Java core libraries are generally
allowed). However, there are legitimate reasons that processes
would want to create threads in these groups, so we provide
a configurable permission to allow trusted code to create
threads in these core JVM thread groups.
To allow code access to the core JVM thread groups, you
will need to grant the following permission:
permission com.gd.openwings.container.jvm.ContainerThreadPermission,
"<thread group name>";
The "ContainerThreadPermission" class extends
java.security.BasicPermission, so the thread group name
may be wildcarded.
This permission should be granted with caution. For example,
if a process were allowed to create threads in the system
thread group, it could create a long running thread that
would not be identified as being part of the process and
could therefore outlive the process. Here's another example:
if a process were allowed to get an enumeration of the threads
in the AWT thread group, it could attack the windowing for
all processes in the container.
The most common cases where programmers will run into this
problem is when applications create worker threads in callbacks:
Threading example 1 - RMI: An application provides
a service and has used an RMI connector. On an incoming
RMI call, the application spawns a thread to perform some
task. If this thread is created using the Thread() constructor,
a SecurityException will be thrown, since the Thread() constructor
defaults to creating the thread in the current thread group.
Since this is an incoming RMI call, the current thread group
is the RMI thread group, which the process is not allowed
to access. The workaround is for the application to save
off its root thread group during startup (Thread.currentThread().getThreadGroup()).
When an incoming RMI call is received, the application should
create the worker thread using the Thread(ThreadGroup, String)
constructor, passing in the process thread group.
Threading example 2 - AWT/Swing: An application
displays a window with a button or some other widget that
has a callback. In the context of the callback, the application
spawns a thread to perform some task. If this thread is
created using the Thread() constructor, a SecurityException
will be thrown -- the current thread group is the AWT thread
group. The workaround described above in the RMI example
is useful, also consider using SwingUtilities.invokeLater(Runnable)
for Swing apps.
Feature History
- 1.1
- Fixed defect 6766 (java.exe crashes on Windows).
This was a major reliability problem on Windows platforms
that occurred periodically when stopping a process
running in a container.
- Added new permission
com.gd.openwings.container.jvm.ContainerThreadPermission
to allow access to core JVM threads.
- 1.0
- 0.9.2
- Container Manager (ow)
- Clean shutdown for standalone Java programs
- Container
- Code Security - enforcement of per-process Java
security policies
- LogAccess utility
- View process log files remotely, even for stopped
processes
- 0.9.1
- Container Manager (ow)
- Support for platform-specific performance monitors,
including Solaris/SunOS, Linux, Windows
- Container
- Significant performance/reliability improvements
from 0.9 release
- LogAccess utility
- Customizable control of log files - turn logging
off entirely, limit log file size, or schedule
automatic deletion of log files
- 0.9
- Container Manager (ow)
- Improved support for components that use native
code
- Remote access to process log files through the
Openwings Explorer
- 0.8.x
- Container Manager (ow)
- Manages execution of Java and non-Java programs
- Manages containers on a single platform
- Restart and Fail-Over Support
- Automatically runs core services
- Container
- Supports Java virtual machine sharing
- Supports Mobile applications
Known Issues
- Container Manager (ow)
- There is no implementation of clustering in this
release.
- Container
- The fix for defect 6766 (java.exe crashes) may result
in a small number of process threads outliving the
process (specifically, threads that are on a wait()
call may not exit).
- Running a Java component that creates GUIs or registers
a shutdown hook makes the component uninstallable
until Openwings is restarted. This is a Java bug.
- Starting and stopping components produces a slow
memory leak in the Container, due to classes not being
unloaded. This is a Java bug.
Future Releases