webclient implementation guide
overview of primary classes and interfaces
The primary interfaces and classes for Webclient are:
BrowserControlFactory
BrowserControl
BrowserControlImpl
BrowserControlCanvas
WrapperFactory
WrapperFactoryImpl
WindowControl
WindowControlImpl
ImplObject
ImplObjectNative
Understanding the primary classes and interfaces is essential to knowing how Webclient works.
BrowserControlFactory
BrowserControlFactory
is the starting point for building an application
with Webclient. It is a class that provides two essential methods, both static:
setAppData()
newBrowserControl()
setAppData()
setAppData()
checks to see that (1) the String
specifying
the absolute path to the native browser binary directory
(absolutePathToNativeBrowserBinDir
)
is not null and that (2) the path actually exists on the machine. It then attempts
to determine the correct canvas class for the platform, Win32 or Motif.
It sets platformCanvasClassName
by first attempting to load
"sun.awt.windows.WDrawingSurfaceIno"
.
If it loads, then it sets platformCanvasClassName
for Win32. If
it fails, then it tries the same thing for Motif.
If one loads, then it sets:
BrowserControlCanvasClass = Class.forName(platformCanvasClassName);
This class is then used when BrowserControlFactory.newBrowserControl()
is invoked.
In our example application, it is invoked in the very next line of code:
browsercontrol = BrowserControlFactory.newBrowserControl();
The result is as follows:
newBrowserControl()
newBrowserControl()
sets newCanvas
to a new instance
of browserControlCanvasClass.
It then does the following:
- passes
newCanvas
to the constructor ofBrowserControlImpl
to get a new instance ofBrowserControlImpl
calledresult
; - checks both
newCanvas
andresult
to see if they arenull
; - if neither is
null
, then initializesnewCanvas
, passingresult
to theinitialize()
method as follows:
newCanvas.initialize(result);
The effect of this initialization is as follows:
Examining BrowserControlCanvas.initialize(BrowserControl controlImpl)
,
it can be see that it sets the variable private BrowserControl webShell
equal to result
, the argument passed to initialize()
,
first checking that the argument is not null
(we already now that
it isn't).
This says that result
is the BrowserControlImpl
instance
for newCanvas
, which is a BrowserControlCanvas
implementation
instance.
Summary
In summary, setAppData()
checks the path to the binary directory
for Mozilla and finds the correct canvas class, while newBrowserControl()
creates an instance of the canvas, creates a browser control from it,
and associates that browser control with the canvas. (Note: setAppData()
also invokes BrowserControlImpl.appInitialize()
, the effects of
which are discussed in BrowserControlImpl
.)
BrowserControl
BrowserControl
is an interface that sets a number of static
variables used by implementations
(BOOKMARKS_NAME
, BROWSER_CONTROL_CANVAS_NAME
,
CURRENT_PAGE_NAME
...), and it defines an abstract method called
queryInterface(String interfaceName)
.
The variables represent various browser functions, and queryInterface()
returns an instance of the implementation of the browser function named by the
variable. For instance, the navigation function of the browser is represented
by the variable
NAVIGATION_NAME = "webclient.Navigation";
By passing this variable to queryInterface()
, an instance of the
implementation of the navigation function (i.e., instance of NavigationImpl
)
is returned.
Thus the developer can use just those functions desired for the application.
BrowserControlImpl
BrowserControlImpl
implements BrowserControl. Thus it it inherits
the static
variables of BrowserControl
and implements
queryInterface()
. It also adds methods of its own, including a
constructor, appInitialize()
and createWrapperFactory()
.
constructor
The constructor takes a BrowserControlCanvas
object as an argument
and sets a private
BrowserControlCanvas
variable called
myCanvas
equal to it. Thus there is a particular canvas object
associated with the BrowserControlImpl
object.
appInitialize()
appInitialize()
is a
static
method that sets
wrapperFactory = createWrapperFactory()
, if the
static wrapperFactory
variable
is null
, and then invokes
initialize()
on wrapperFactory
.
Notes
wrapperFactory
is set as typeWrapperFactory
, which is an abstract class.createWrapperFactory()
is aprivate static
method ofBrowserControlImpl
that returns an object of typeWrapperFactory
.
createWrapperFactory()
To accommodate different type of wrappers
("native" and "non-native"),
some generality is introduced via the createWrapperFactory()
method:
First, a String
called wrapperFactoryClassName
is
temporarily set to the package name for BrowserControlImpl
. Then
String PARAMETERIZED_VALUE
is set to the wrapper type (currently,
"native", since this code is being used for a native wrapper). Then
we have:
wrapperFactoryClassName = wrapperFactoryClassName + "wrapper_" + PARAMETERIZED_VALUE + "." + WrapperFactory.IMPL_NAME; wrapperFactoryClass = Class.forName(wrapperFactoryClassName);
The first statement sets wrapperFactoryclassName
to the fully-
qualified name for WrapperFactory.IMPL_Name
. The second statement
sets wrapperFactoryClass
to the actual class.
Note that WrapperFactory.IMPL_NAME
is determined by the abstract
class WrapperFactory
. public static String IMPL_NAME
is currently set to "WrapperFactoryImpl
" in that class.
Thus WrapperFactory.IMPL_NAME
is simply the String
"WrapperFactoryImpl
". This again give us generality,
since we have the opportunity to set the directory for the WrapperFactory
implementation according to the type of wrapper, and we also have the opportunity
to name the implementation class as we like.
createWrapperFactory()
finally creates a new instance of
wrapperFactoryClass
and returns it.
When the flow of control returns to appInitialize()
, it sets
the instance to wrapperFactory
and invokes the initialize()
method on it. WrapperFactoryImpl.initialize()
is explained under
WrapperFactory, WrapperFactoryImpl
.
queryInterface()
queryInterface()
is used to create instances of a desired browser
functions, such as navigation, bookmarks, history, as mentioned previously.
All instances of a desired function are created similarly. Let us take the case
of creating an instance of the history function. We could pass
"webclient.History"
to queryInterface()
,
which would set:
history = (History) wrapperFactory.newImpl(HISTORY_NAME, this);
this
would be a reference to the BrowserControlImpl
instance that is invoking newImpl()
. The effect would be to cause
wrapperFactory.newImpl()
to set:
result = new HistoryImpl(this, browserControl);
this
is a reference to the invoking WrapperFactoryImpl
instance, wrapperFactory
, while browserControl
is a reference to the BrowserControlImpl
instance that invokes
wrapperFactory.newImpl()
.
BrowserControlCanvas
BrowserControlCanvas
is an abstract
class that extends
Canvas
and is extended by a platform-specific class.
BrowserControlCanvas
has only one abstract
method, getWindow()
, which is
implemented by the platform-specific class. For example, in the case of the
Win32 platform, a class called Win32BrowserControlCanvas
implements
getWindow()
by returning an int
for the Window Handle
(a unique 32-bit value that identifies the Window). It does this via the
getHWnd()
method of the WDrawingSurfaceInfo
class
in the sun.awt.windows
package.
initialize()
In the initialize()
method of BrowserControlCanvas
an argument of type BrowserControl
is passed to it and a
private
variable of the same type, webShell
, is set equal to it.
addNotify()
addNotify()
is worth examining. It is at the heart of this class.
Note that when the BrowserControlCanvas
implementation instance
(such as browserCanvas
in our example) is added to the
Frame
of an application, the addNotify()
method of <
code>BrowserControlCanvas
is called and addNotify()
generates wc
, an instance
of WindowControlImpl
cast
as type WindowControl
. Let
us take a closer look at how this is
done and what is happening in the addNotify()
method:
First, it gets the peer
of the BrowserControlCanvas
implementation instance and casts it as type DrawingSurface
(sun.awt.DrawingSurface
).
Then it uses the <
code>getDrawingSurfaceInfo() method of DrawingSurface
to get the DrawingSurfaceInfo
object dsi
.
Next, windowRelativeBounds
is set to new Rectangle()
.
windowRelativeBounds
is a Rectangle
at point (0,0)
with width and height = 0.
Then, dsi
is locked so that the information is not changed elsewhere,
then dsi
is passed to getWindow()
to get an
int
called nativeWindow
. getWindow(DrawingSurfaceInfo
dsi)
is an abstract method of BrowserControlCanvas
that
is implemented in the concrete class of which we have an instance. (Note: It
is assumed that an instance of the implementation of
BrowserControlCanvas
would be created in a custom applications
following the invocation of the
setAppdata()
method of
BrowserControlFactory
.)
Next, in the try
block a new Rectangle
is created
by passing getBoundsRelativeToWindow()
as an argument to the
constructor for Rectangle
.
getBoundsRelativeToWindow()
returns
a Rectangle
object that has been translated so that
its x
and y
data fields reference the Window of
our custom application
and not the particular container that it may be in
within that Window.
Finally, WindowControl wc
is created and its createWindow(int
nativeWindow, Rectangle bounds)
method is used to create the Window.
createWindow()
is discussed in detail under
WindowControlImpl
.
WrapperFactory, Wrapper FactoryImpl
WrapperFactory
is an abstract
class that allows for
different types of browsers that might be embedded, native or non-native,
and it has an important abstract method called newImpl()
that is implemented by WrapperFactoryImpl
. newImpl()
is what is called by BrowserControlImpl.queryInterface()
to actually
get an instance of some browser function such as navigation, bookmarks, history,
etc.
For example, if the navigation function is desired, that is, an instance
of NavigationImpl
, "webclient.Navigation"
would be passed to BrowserControlImpl.queryInterface()
and control
would be passed to the following statement within that method:
if (NAVIGATION_NAME.equals(interfaceName)) { if (null == navigation) { navigation = (Navigation) wrapperFactory.newImpl(NAVIGATION_NAME, this); } return navigation;
wrapperFactory
in the test example is in fact an instance of
WrapperFactoryImpl
for the type of browser being embedded, and the WrapperFactoryImpl
class is located in its own directory for that type; i.e., for Windows, it is
located in wrapper_native
.
wrapperFactory.newImpl()
with NAVIGATION_NAME
as
the argument passes control to the following statement in WrapperFactoryImpl.newImpl()
:
if (BrowserControl.NAVIGATION_NAME == interfaceName) { result = new NavigationImpl(this, browserControl); return result;
Thus it creates the new instances of NavigationImp
for the type
of browser being embedded.
WrapperFactoryImpl.initialize()
synchronizes on the instance of
WrapperFactoryImpl
and then invokes the native method
nativeAppInitialize()
.
nativeAppInitialize()
is
called at the beginning of program execution
to allow for one-time
initialization of tasks. The native method initializes XPCOM and so on.
WindowControl
WindowControl
is an interface that includes methods to create
a window, control it, and get the native webshell.
WindowControlImpl
An instance of WindowControlImpl
is created via the
addNotify()
method of BrowserControlCanvas
.
addNotify()
is called
when an instance of an implementation of
BrowserControlCanvas
(such
as an instance of
win32BrowserControlCanvas
) is added to the custom application.
BrowserControlCanvas.addNotify()
uses the
queryInterface()
method of BrowserControlImpl
via
an instance of the latter called
webShell
, which is passed to the
BrowserControlCanvas
object via its initialize()
method.
The createWindow()
method is worth some attention. Following some
preliminary checking, it locks myBrowserControl
(the
BrowserControlImpl
object) and this
(the
WindowControlImpl
object), then
passes nativeWindow
to nativeCreateInitContext()
,
along with other arguments, to
obtain nativeWebShell
. nativeWindow
was created in
BrowserControlCanvas.addNotify()
via getWindow()
,
which gets, in the case of Win32, the Window Handle for the native Window.
nativeCreateInitContext()
is the native method for initialization.
Next, createWindow()
creates eventThread
, an instance
of NativeEventThread
. NativeEventThread
extends
java.lang.Thread
and adds native methods. createWindow()
starts the thread by invoking
eventThread.start()
, then invokes
wait()
on the main thread in a try
block.
eventThread.start()
causes
the thread to begin and
eventThread.run()
invokes nativeInitialize()
, which is
a native method for initializing Mozilla. Following nativeInitialize()
in NativeEventThread.run()
, windowControl.notify()
tells the main thread that it can run again.
Note that WindowControlImpl
extends ImplObjectNative
and implements WindowControl
.
ImplObject
ImplObjec
t defines two attributes for a number of the
implementations
of the Webclient interfaces. The two attributes are:
public WrapperFactory myFactory;
public BrowserControl myBrowserControl;
In the case of a native embedded browser, the implementations of the interfaces
extend the subclass of ImplObject
called ImplObjectNative
.
Two interfaces that do not extend the subclass are WrapperFactoryImpl
and BrowserControlImpl
.
ImplObjectNative
ImplObjectNative
, which is used for native embedded browsers,
extends ImplObject
. All implementations, other than
WrapperFactoryImpl
and BrowserControlImpl
, extend
it so as to provide easy access
to the WrapperFactory
and
BrowserControl
attributes.
ImplObjectNative
provides a constructor that invokes
getNativeWebShell()
.
Blackwood Release 0.9/Netscape PR3 - Last Modified 10/13/2000