Transferred work from private ns tree back into mozilla.

This commit is contained in:
fur%netscape.com 1998-08-29 03:00:50 +00:00
Родитель 8a3eba90d3
Коммит b2058b3efa
31 изменённых файлов: 577 добавлений и 4199 удалений

Просмотреть файл

@ -1,4 +0,0 @@
*.ncb
*.opt
Debug
Release

Просмотреть файл

@ -1,144 +0,0 @@
# Microsoft Developer Studio Project File - Name="LiveConnect" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 5.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=LiveConnect - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "LiveConnect.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "LiveConnect.mak" CFG="LiveConnect - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "LiveConnect - Win32 Release" (based on\
"Win32 (x86) Dynamic-Link Library")
!MESSAGE "LiveConnect - Win32 Debug" (based on\
"Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "LiveConnect - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /Zi /O2 /I ".." /I "$(JDK)\include" /I "$(JDK)\include\win32" /D "NDEBUG" /D "XP_PC" /D "JSFILE" /D "WIN32" /D "_WINDOWS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ..\Release\js32.lib $(JDK)\lib\javai.lib /nologo /subsystem:windows /dll /debug /machine:I386
!ELSEIF "$(CFG)" == "LiveConnect - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I ".." /I "$(JDK)\include" /I "$(JDK)\include\win32" /D "_DEBUG" /D "_CONSOLE" /D "DEBUG" /D "XP_PC" /D "JSFILE" /D "WIN32" /D "_WINDOWS" /FR /YX /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ..\Debug\js32.lib $(JDK)\lib\javai_g.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Debug/LiveConnect_g.dll" /pdbtype:sept
!ENDIF
# Begin Target
# Name "LiveConnect - Win32 Release"
# Name "LiveConnect - Win32 Debug"
# Begin Source File
SOURCE=..\liveconnect\jsj.c
# End Source File
# Begin Source File
SOURCE=..\liveconnect\jsj_array.c
# End Source File
# Begin Source File
SOURCE=..\liveconnect\jsj_class.c
# End Source File
# Begin Source File
SOURCE=..\liveconnect\jsj_convert.c
# End Source File
# Begin Source File
SOURCE=..\liveconnect\jsj_field.c
# End Source File
# Begin Source File
SOURCE=.\jsj_hash.c
# End Source File
# Begin Source File
SOURCE=.\jsj_JavaArray.c
# End Source File
# Begin Source File
SOURCE=.\jsj_JavaClass.c
# End Source File
# Begin Source File
SOURCE=.\jsj_JavaObject.c
# End Source File
# Begin Source File
SOURCE=.\jsj_JavaPackage.c
# End Source File
# Begin Source File
SOURCE=.\jsj_JSObject.c
# End Source File
# Begin Source File
SOURCE=..\liveconnect\jsj_method.c
# End Source File
# Begin Source File
SOURCE=..\liveconnect\jsj_utils.c
# End Source File
# End Target
# End Project

Просмотреть файл

@ -1,432 +0,0 @@
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="Author" CONTENT="Scott Furman">
<META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]">
<TITLE>README for LiveConnect</TITLE>
</HEAD>
<BODY>
<H2>
Introduction</H2>
This is the README file for the JavaScript LiveConnect implementation.&nbsp;
It consists of build conventions and instructions, source code conventions,
and a brief file-by-file description of the source.
<P>This document assumes basic familiarity with JSRef, the reference implementation
of JavaScript, and with the LiveConnect technology&nbsp; (LiveConnect allows
JavaScript and Java virtual machines to be connected.&nbsp; It enables
JavaScript to access Java fields, invoke Java methods and makes it possible
for Java to access JavaScript object properties and evaluate JavaScript.&nbsp;
More information on LiveConnect can be found by searching the index on
Netscape's <A HREF="http://developer.netscape.com">DevEdge site</A>.)
<P>JSRef builds a library or DLL containing the JavaScript runtime (compiler,
interpreter, decompiler, garbage collector, atom manager, standard classes).&nbsp;
The LiveConnect project/makefiles build a library that links both with
JSRef and with a Java Virtual Machine (JVM) that implements the Java Native
Interface (JNI), as specified by JavaSoft.&nbsp; It then compiles a small
"shell" program and links that with the library to make an interpreter
that can be used interactively and with test scripts.
<P><I>Scott Furman, 4/8/98</I>
<H2>
Compatibility</H2>
Unlike this release, all previous versions of LiveConnect appeared only
as a component of Netscape Navigator, not as a standalone module.&nbsp;
The variants of LiveConnect that appeared in Navigator versions 3.x and
4.x all behave much the same, modulo bugs.&nbsp; For brevity we refer to
this classic version of LiveConnect as "LC1" and this most recent release
as "LC2".&nbsp; The following incompatibilities with LC1 are known:
<UL>
<LI>
As in LC1, JavaScript objects appear to Java as instances of <I>netscape.javascript.JSObject</I>.&nbsp;
In LC1, two <I>JSObject</I>'s could be tested for equality, i.e. to see
if they refer to the same instance, by using the `==' operator.&nbsp; Instead,
developers must now use the <TT>equals()</TT>method of <I>netscape.javascript.JSObject</I>
for comparison, a method that overrides <TT>java.lang.Object.equals()</TT>.&nbsp;
Using <TT>equals()</TT> instead of `==' should work the same on both LC1
and LC2.&nbsp;<BR>
<BR>
It is not possible to replicate the identity behavior of the `==' operator
that LC1 provides without the use of "weak" references, i.e. references
that do not contribute to making a Java object reachable for purposes of
garbage collection, but which nonetheless allow reference to an object
as long as it is reachable by other means.&nbsp; The use of weak references
is not portable, however.&nbsp; It is not part of the JNI or the JDK and
it is not provided on all JVMs.&nbsp; The JDK1.2 release will include standard
support for weak references.<BR>
<BR></LI>
<LI>
It's possible that, in a set of overloaded Java methods, more than one
is compatible with the types of the actual arguments in a call from JavaScript
via LiveConnect.&nbsp; LC1 resolved these ambiguities in a simplistic manner,
by simply invoking whatever method was enumerated first by the JVM.&nbsp;
The enumeration order of reflected methods using <I>java.lang.reflect</I>&nbsp;
is not specified by Sun and may differ among vendor's JVMs, i.e. enumeration
could be in order of classfile appearance, hashtable order, etc.&nbsp;&nbsp;&nbsp;
With the Netscape and Sun JVMs, it is possible to change the behavior of
an LC1 program by changing the order that Java methods appear in a source
file, thus changing the method enumeration order.&nbsp; Hence, the Java
method chosen when there is more than one compatible method may vary depending
on the JVM.<BR>
<BR>
A future release of LiveConnect will provide a new algorithm for overloaded
Java method resolution that is both independent of the JVM used and more
likely than LC1 to invoke the method that the developer expects.<BR>
<BR></LI>
<LI>
There are several minor changes in error handling to make LiveConnect more
conformant to ECMAScript.&nbsp; These include, for example, making any
attempt to delete JavaObject, JavaClass or JavaPackage properties fail
silently, rather than causing an error.&nbsp; Also, some error messages
have been changed to be more informative.&nbsp; These changes should generally
be backward-compatible with LC1 because few programs that use LiveConnect
will depend on the exact behavior of LiveConnect when handling errors.</LI>
</UL>
<H2>
New Features</H2>
Several minor features have been added to this release of LiveConnect.&nbsp;
These features were not available in the versions of LiveConnect that were
integrated with Netscape Naviagtor versions 4.x and earlier.
<BR>&nbsp;
<BLOCKQUOTE>
<LI>
The Java methods of <I>java.lang.Object</I> are now invokeable methods
of <TT><FONT SIZE=+1>JavaArray</FONT></TT> objects, matching the behavior
of arrays when accessed from Java<I>.</I>&nbsp; (Java arrays are a subclass
of <I>java.lang.Object</I>.) For example, Java's <TT><FONT SIZE=+1>getClass()</FONT></TT>
and <TT><FONT SIZE=+1>hashCode()</FONT></TT> methods can now be called
on <TT><FONT SIZE=+1>JavaArray</FONT></TT> objects.&nbsp; (In prior versions
of LiveConnect, the methods of <I>java.lang.Object</I> were only inherited
by non-array Java objects.)</LI>
<P>Note that this change has caused the string representation of JavaArray
objects to change.&nbsp; Previously, the JavaArray toString() method always
printed "<TT><FONT SIZE=+1>[object JavaArray]"</FONT></TT> for all <TT><FONT SIZE=+1>JavaArray</FONT></TT>'s.&nbsp;
Now, the Java <TT><FONT SIZE=+1>java.lang.Object.toString()</FONT></TT>
method is called to convert JavaArray objects to strings, just as with
other, non-array Java objects that are accessible via LiveConnect.&nbsp;
<TT><FONT SIZE=+1>java.lang.Object.toString()</FONT></TT>is defined in
the <I>Java Language Specification</I> to return the value of the following
expression:
<P><TT><FONT SIZE=-1>getClass().getName() + '@' + Integer.toHexString(hashCode())</FONT></TT>
<BR>&nbsp;
<LI>
A one-character string is now an acceptable match for an argument to a
Java method of type <TT><FONT SIZE=+1>char</FONT></TT>.&nbsp; (In earlier
versions of LiveConnect, the only acceptable match for a <TT><FONT SIZE=+1>char</FONT></TT>
had to be a JavaScript value that was convertible to a number.)&nbsp; For
example, the following is now possible:</LI>
<P><TT><FONT SIZE=-1>c = new java.lang.Character("F")</FONT></TT>
<BR>&nbsp;
<LI>
A JavaClass object is now an acceptable match for an argument to a Java
method of type <I>java.lang.Class</I>.&nbsp; For example, you can now write:</LI>
<P><TT><FONT SIZE=-1>java.lang.reflect.Array.newInstance(java.lang.String,
3)</FONT></TT>
<P>instead of the more verbose:
<P><TT><FONT SIZE=-1>jls = java.lang.Class.forName("java.lang.String")</FONT></TT>
<BR><TT><FONT SIZE=-1>java.lang.reflect.Array.newInstance(jls, 3)</FONT></TT>
<BR>&nbsp;</BLOCKQUOTE>
<H2>
Build conventions</H2>
Update your JVM's <TT><FONT SIZE=+1>CLASSPATH</FONT></TT> to point to the
<TT><FONT SIZE=+1>liveconnect/classes</FONT></TT> subdirectory.&nbsp; If
you do not, LiveConnect will still operate but with the limitation that
JS objects may not be passed as arguments of Java methods and it will not
be possible to call from Java into JavaScript, i.e. the <I>netscape.javascript.JSObject</I>
class will be inaccessible.&nbsp; Another downside of operating without
these classes is that Java error messages will not include a Java stack
trace, when one is available.&nbsp; If your <TT><FONT SIZE=+1>CLASSPATH</FONT></TT>
is set improperly, you will see a message like, "<TT><FONT SIZE=+1>initialization
error: Can't load class netscape/javascript/JSObject</FONT></TT>" when
starting a LiveConnect debug build.
<P>By default, LiveConnect is not re-entrant.&nbsp; To enable multi-threaded
execution, define the <TT><FONT SIZE=+1>JS_THREADSAFE</FONT></TT> cpp macro
and flesh out the stubs and required headers in jslock.c/.h.&nbsp; See
the JS API docs for more.&nbsp; JSRef must also be built with <TT><FONT SIZE=+1>JS_THREADSAFE</FONT></TT>.
<BR>&nbsp;
<UL><B>Windows</B>
<UL>
<LI>
Use MSDEV5.0 with the <TT><FONT SIZE=+1>LiveConnectShell.dsw</FONT></TT>
project file.</LI>
<LI>
You must first build the JS runtime, js32.dll, by using the normal JSRef
build procedure.</LI>
<LI>
Identify the JVM that you are linking against by setting the <TT><FONT SIZE=+1>JDK</FONT></TT>
environment variable to point to the top-level JDK directory, e.g. <TT><FONT SIZE=+1>D:\jdk1.1.5</FONT></TT>.&nbsp;
This is used to establish paths for header file inclusion, linking and
execution.&nbsp; If you are not using Sun's JVM, the project files may
require manual tweaking to set these paths correctly.</LI>
<LI>
The output files (DLLs and executables) are placed in the <TT><FONT SIZE=+1>js/ref/liveconnect/Debug</FONT></TT>
or <TT><FONT SIZE=+1>js/ref/liveconnect/Release</FONT></TT> directories.</LI>
<LI>
The LiveConnect-enabled shell is named <TT><FONT SIZE=+1>lcshell.exe</FONT></TT>
and appears in the output directory.</LI>
<LI>
You must have the JVM DLL in your <TT><FONT SIZE=+1>PATH</FONT></TT> environment
variable in order to run.&nbsp; If you are using the Sun JDK, the DLL appears
in the JDK's bin directory.</LI>
<LI>
Use any Java compiler to compile the java source files in the <TT><FONT SIZE=+1>js/ref/liveconnect/classes/netscape/javascript</FONT></TT>
directory.</LI>
</UL>
<BR>
<B>Mac OS</B>
<UL>
<LI>
Using CodeWarrior Pro 3 is recommended.&nbsp; With some modifications,
the project files can be made to work with CodeWarrior Pro 2.&nbsp; The
CodeWarrior project files are <TT><FONT SIZE=+1>js/ref/liveconnect/macbuild/LiveConnect.mcp</FONT></TT>,
<TT><FONT SIZE=+1>js/ref/liveconnect/macbuild/LiveConnectShell.mcp</FONT></TT>,
and<TT><FONT SIZE=+1> js/ref/macbuild/JSRef.mcp</FONT></TT>.</LI>
<LI>
Install Apple's JVM, MRJ 2.0 (or later), and the <A HREF="ftp://dev.apple.com/devworld/Java/MRJSDK2.0.1EarlyAccess4.hqx">MRJ
SDK v2.0.1ea4</A>.&nbsp; Note: You do not need to install MRJ if you are
running a recent version of MacOS 8, since it is shipped with the OS.</LI>
<LI>
Copy the folders CIncludes &amp; Libraries from the SDK's Interfaces&amp;Libraries
directory to <TT><FONT SIZE=+1>js/ref/liveconnect/macbuild/JavaSession</FONT></TT>.</LI>
<LI>
Build the JavaScript test application, <TT><FONT SIZE=+1>JSRef</FONT></TT>,
with <TT><FONT SIZE=+1>js/ref/macbuild/JSRef.mcp</FONT></TT>.</LI>
<LI>
Build the LiveConnect test application, <TT><FONT SIZE=+1>LiveConnectShell</FONT></TT>,
with <TT><FONT SIZE=+1>js/ref/liveconnect/macbuild/LiveConnectShell.mcp</FONT></TT>.</LI>
<LI>
Build <TT><FONT SIZE=+1>liveconnect.jar</FONT></TT> with <TT><FONT SIZE=+1>js/ref/liveconnect/macbuild/LiveConnect.mcp</FONT></TT>.</LI>
<LI>
Make an alias to <TT><FONT SIZE=+1>liveconnect.jar</FONT></TT> and place
it in "<TT><FONT SIZE=+1>{SystemFolder}Extensions:MRJ Libraries:MRJClasses</FONT></TT>".<BR>
<BR></LI>
</UL>
<B>Unix</B>
<UL>
<LI>
<FONT COLOR="#FF0000">No Makefiles have been completed yet.&nbsp; These
notes are a work in progress.</FONT></LI>
<LI>
Use vendor cc or gcc (ftp://prep.ai.mit.edu/pub/gnu) for compiling,&nbsp;
and use gmake for building.</LI>
<LI>
To compile optimized code, set BUILD_OPT=1 on the nmake/gmake command line
or preset it in the environment or makefile.&nbsp; The C preprocessor macro
DEBUG&nbsp; will be undefined, and NDEBUG (archaic Unix-ism for "No Debugging")
will be defined.&nbsp; Without BUILD_OPT, DEBUG is predefined and NDEBUG
is undefined.</LI>
<LI>
Your own debug flag, DEBUG_$USER, will be defined or undefined as BUILD_OPT
is unset or set.</LI>
<LI>
To add C compiler options from the make command line, set XCFLAGS=-Dfoo.</LI>
<LI>
To predefine -D or -U options in the makefile, set DEFINES.</LI>
<LI>
To predefine -I options in the makefile, set INCLUDES.</LI>
</UL>
</UL>
<H2>
Naming and coding conventions:</H2>
<UL>
<LI>
Public function names begin with JSJ_ followed by capitalized "intercaps",&nbsp;
e.g. JSJ_ConnectToJavaVM.</LI>
<LI>
Extern but library-private function names use a jsj_ prefix and mixed case,
e.g. jsj_LookupSymbol.</LI>
<LI>
Most static function names have unprefixed, underscore-separated names:
get_char.</LI>
<LI>
But static native methods of JS objects have intercaps names, e.g., JavaObject_getProperty().</LI>
<LI>
And library-private and static data use underscores, not intercaps (but
library-private data do use a js_ prefix).</LI>
<LI>
Scalar type names are lowercase and js-prefixed: jsdouble.</LI>
<LI>
Aggregate type names are JS-prefixed and mixed-case: JSObject.</LI>
<LI>
Macros are generally ALL_CAPS and underscored, to call out potential side
effects, multiple uses of a formal argument, etc.</LI>
<LI>
Four spaces of indentation per statement nesting level.&nbsp; The files
are space-filled, so adjusting of your tab setting should be unnecessary.</LI>
<LI>
DLL entry points have their return type expanded within a PR_PUBLIC_API()&nbsp;
macro call, to get the right Windows secret type qualifiers in the right
places for both 16- and 32-bit builds.</LI>
<LI>
Callback functions that might be called from a DLL are similarly macroized
with PR_STATIC_CALLBACK (if the function otherwise would be static to hide
its name) or PR_CALLBACK (this macro takes no type argument; it should
be used after the return type and before the function name).</LI>
</UL>
<H2>
The LiveConnect API</H2>
All public LiveConnect entry points and callbacks are documented in jsjava.h,
the header file that exports those functions.
<BR>&nbsp;
<H2>
File Walk-through</H2>
&nbsp;
<TABLE BORDER=3 CELLSPACING=0 CELLPADDING=4 >
<TR>
<TD>jsjava.h</TD>
<TD>LiveConnect's only public header file.&nbsp; Defines all public API
entry points, callbacks and types.&nbsp;</TD>
</TR>
<TR>
<TD>jsj_private.h</TD>
<TD>LiveConnect internal header file for intra-module sharing of functions
and types</TD>
</TR>
<TR>
<TD>jsj.c</TD>
<TD>Public LiveConnect API entry points and initialization code</TD>
</TR>
<TR>
<TD>jsj_array.c</TD>
<TD>Read and write elements of a Java array, performing needed conversions
to/from JS types.</TD>
</TR>
<TR>
<TD>jsj_class.c</TD>
<TD>Construct and manipulate JavaClassDescriptor structs, which are the
native representation for Java classes.&nbsp; JavaClassDescriptors are
used to describe the methods and fields of a class, including their type
signatures, and include a reference to the peer <I>java.lang.Class</I>
object.&nbsp; Since each Java object has a class, there is a JavaClassDescriptor
associated with the JavaScript reflection of each Java Object.</TD>
</TR>
<TR>
<TD>jsj_convert.c</TD>
<TD>Convert between Java and JavaScript values of all types, which may
require calling routines in other files to wrap JS objects as Java objects
and vice-versa.</TD>
</TR>
<TR>
<TD>jsj_field.c</TD>
<TD>Reflect Java fields as properties of JavaObject objects and implement
getter/setter access to those fields.</TD>
</TR>
<TR>
<TD>jsj_JavaArray.c</TD>
<TD>Implementation of the JavaScript JavaArray class.&nbsp; Instances of
JavaArray are used to reflect Java arrays.</TD>
</TR>
<TR>
<TD>jsj_JavaClass.c</TD>
<TD>Implementation of the JavaScript JavaClass class.&nbsp;&nbsp; Instances
of JavaClass are used to reflect Java classes.</TD>
</TR>
<TR>
<TD>jsj_JavaObject.c</TD>
<TD>Implementation of the JavaScript JavaObject class.&nbsp;&nbsp; Instances
of JavaObject are used to reflect Java objects, except for Java arrays,
although some of the code in this file is used by the JavaArray code.</TD>
</TR>
<TR>
<TD>jsj_JavaPackage.c</TD>
<TD>Implementation of the JavaScript JavaPackage class.&nbsp;&nbsp; Instances
of JavaPackage are used to reflect Java packages.&nbsp; The JS properties
of a JavaPackage are either nested JavaPackage objects or a JavaClass object.</TD>
</TR>
<TR>
<TD>jsj_JSObject.c</TD>
<TD>Implementation of the native methods for the&nbsp; <I>netscape.javascript.JSObject</I>
Java class, which are used for calling into JavaScript from Java.&nbsp;
It also contains the code that wraps JS objects as instances of&nbsp; <I>netscape.javascript.JSObject
</I>and the code that handles propagation of exceptions both into and out
of Java.</TD>
</TR>
<TR>
<TD>jsj_method.c</TD>
<TD>Reflect Java methods as properties of JavaObject objects and make it
possible to invoke those methods.&nbsp; Includes overloaded method resolution
and argument/return-value conversion code.</TD>
</TR>
<TR>
<TD>jsj_utils.c</TD>
<TD>Low-level utility code for reporting errors, etc.</TD>
</TR>
</TABLE>
&nbsp;
<BR>&nbsp;
</BODY>
</HTML>

Просмотреть файл

Просмотреть файл

@ -1,4 +1,6 @@
/* Insert copyright and license here 19** */
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
package netscape.javascript;

Просмотреть файл

@ -1,4 +1,6 @@
/* -*- Mode: C; tab-width: 4; -*- */
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/* Insert copyright and license here 19** */
@ -23,7 +25,7 @@ import java.applet.Applet;
* which can be used to access methods and fields of the java object.
* Converting this wrapper to a string will call the toString method
* on the original object, converting to a number will call the
* floatValue method if possible and fail otherwise. Converting
* doubleValue method if possible and fail otherwise. Converting
* to a boolean will try to call the booleanValue method in the
* same way.
* <li>Java arrays are wrapped with a JavaScript object that understands
@ -35,8 +37,9 @@ import java.applet.Applet;
* Values passed from JavaScript to Java are converted as follows:<ul>
* <li>objects which are wrappers around java objects are unwrapped
* <li>other objects are wrapped with a JSObject
* <li>strings, numbers and booleans are converted to String, Float,
* <li>strings, numbers and booleans are converted to String, Double,
* and Boolean objects respectively
* <li>undefined is converted to a string
* </ul>
* This means that all JavaScript values show up as some kind
* of java.lang.Object in Java. In order to make much use of them,
@ -53,60 +56,74 @@ public final class JSObject {
*/
private static native void initClass();
static {
System.loadLibrary("LiveConnect");
initClass();
String liveConnectLibrary = null;
String OSName = System.getProperty("os.name", null);
// On MRJ, this property won't exist, because the library is preloaded.
liveConnectLibrary = System.getProperty("netscape.jsj.dll", null);
// On Mac, native methods are statically linked and manually registered.
if ((liveConnectLibrary == null) && (OSName.indexOf("Mac") == -1))
liveConnectLibrary = "LiveConnect";
if (liveConnectLibrary != null) {
System.loadLibrary(liveConnectLibrary);
initClass();
}
}
/**
* it is illegal to construct a JSObject manually
*/
private JSObject(int jsobj_addr) {internal = jsobj_addr;}
private JSObject(int jsobj_addr) {
internal = jsobj_addr;
}
/**
* Retrieves a named member of a JavaScript object.
* Equivalent to "this.<i>name</i>" in JavaScript.
*/
public native Object getMember(String name);
public native Object getMember(String name);
/**
* Retrieves an indexed member of a JavaScript object.
* Equivalent to "this[<i>index</i>]" in JavaScript.
*/
// public Object getMember(int index) { return getSlot(index); }
public native Object getSlot(int index);
// public Object getMember(int index) { return getSlot(index); }
public native Object getSlot(int index);
/**
* Sets a named member of a JavaScript object.
* Equivalent to "this.<i>name</i> = <i>value</i>" in JavaScript.
*/
public native void setMember(String name, Object value);
public native void setMember(String name, Object value);
/**
* Sets an indexed member of a JavaScript object.
* Equivalent to "this[<i>index</i>] = <i>value</i>" in JavaScript.
*/
// public void setMember(int index, Object value) {
// public void setMember(int index, Object value) {
// setSlot(index, value);
// }
public native void setSlot(int index, Object value);
public native void setSlot(int index, Object value);
/**
* Removes a named member of a JavaScript object.
*/
public native void removeMember(String name);
public native void removeMember(String name);
/**
* Calls a JavaScript method.
* Equivalent to "this.<i>methodName</i>(<i>args</i>[0], <i>args</i>[1], ...)" in JavaScript.
*/
public native Object call(String methodName, Object args[]);
public native Object call(String methodName, Object args[]);
/**
* Evaluates a JavaScript expression. The expression is a string
* of JavaScript source code which will be evaluated in the context
* given by "this".
*/
public native Object eval(String s);
public native Object eval(String s);
/**
* Converts a JSObject to a String.
@ -115,30 +132,23 @@ public final class JSObject {
// should use some sort of identifier rather than String
// is "property" the right word?
// native String[] listProperties();
// native String[] listProperties();
/**
* get a JSObject for the window containing the given applet
*/
public static native JSObject getWindow(Applet applet);
public static native JSObject getWindow(Applet applet);
/**
* Finalization decrements the reference count on the corresponding
* JavaScript object.
*/
protected native void finalize();
protected native void finalize();
/**
* Override java.lang.Object.equals() because identity is not preserved
* with instances of JSObject.
*/
public boolean equals(Object obj) {
JSObject jsobj;
if (!(obj instanceof JSObject))
return false;
jsobj = (JSObject)obj;
return (internal == jsobj.internal);
}
public native boolean equals(Object obj);
}

Просмотреть файл

@ -1,19 +1,5 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/* ** */
/**

Просмотреть файл

@ -1,3 +1,7 @@
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
package netscape.javascript;
/**

Просмотреть файл

@ -1,19 +1,5 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/* ** */

Просмотреть файл

Просмотреть файл

@ -1,745 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the top-level initialization code and the implementation of the
* public API.
*
*/
#include <stdlib.h>
#include <string.h>
#include "prtypes.h"
#include "prassert.h"
#include "prprintf.h"
#include "prosdep.h"
#include "jsj_private.h" /* LiveConnect internals */
#include "jsjava.h" /* LiveConnect external API */
/*
* At certain times during initialization, there may be no JavaScript context
* available to direct error reports to, in which case the error messages
* are sent to this function. The caller is responsible for free'ing
* the js_error_msg argument.
*/
static void
report_java_initialization_error(JNIEnv *jEnv, const char *js_error_msg)
{
const char *error_msg, *java_error_msg;
java_error_msg = NULL;
if (jEnv) {
java_error_msg = jsj_GetJavaErrorMessage(jEnv);
(*jEnv)->ExceptionClear(jEnv);
}
if (java_error_msg) {
error_msg = PR_smprintf("initialization error: %s (%s)\n",
js_error_msg, java_error_msg);
free((void*)java_error_msg);
} else {
error_msg = PR_smprintf("initialization error: %s\n",
js_error_msg);
}
jsj_LogError(error_msg);
}
/*
* Opaque JVM handles to Java classes and methods required for Java reflection.
* These are computed and cached during initialization.
*/
jclass jlObject; /* java.lang.Object */
jclass jlrMethod; /* java.lang.reflect.Method */
jclass jlrField; /* java.lang.reflect.Field */
jclass jlVoid; /* java.lang.Void */
jclass jlrConstructor; /* java.lang.reflect.Constructor */
jclass jlThrowable; /* java.lang.Throwable */
jclass jlSystem; /* java.lang.System */
jclass jlClass; /* java.lang.Class */
jclass jlBoolean; /* java.lang.Boolean */
jclass jlDouble; /* java.lang.Double */
jclass jlString; /* java.lang.String */
jclass njJSObject; /* netscape.javascript.JSObject */
jclass njJSException; /* netscape.javascript.JSException */
jclass njJSUtil; /* netscape.javascript.JSUtil */
jmethodID jlClass_getMethods; /* java.lang.Class.getMethods() */
jmethodID jlClass_getConstructors; /* java.lang.Class.getConstructors() */
jmethodID jlClass_getFields; /* java.lang.Class.getFields() */
jmethodID jlClass_getName; /* java.lang.Class.getName() */
jmethodID jlClass_getComponentType; /* java.lang.Class.getComponentType() */
jmethodID jlClass_getModifiers; /* java.lang.Class.getModifiers() */
jmethodID jlClass_isArray; /* java.lang.Class.isArray() */
jmethodID jlrMethod_getName; /* java.lang.reflect.Method.getName() */
jmethodID jlrMethod_getParameterTypes; /* java.lang.reflect.Method.getParameterTypes() */
jmethodID jlrMethod_getReturnType; /* java.lang.reflect.Method.getReturnType() */
jmethodID jlrMethod_getModifiers; /* java.lang.reflect.Method.getModifiers() */
jmethodID jlrConstructor_getParameterTypes; /* java.lang.reflect.Constructor.getParameterTypes() */
jmethodID jlrConstructor_getModifiers; /* java.lang.reflect.Constructor.getModifiers() */
jmethodID jlrField_getName; /* java.lang.reflect.Field.getName() */
jmethodID jlrField_getType; /* java.lang.reflect.Field.getType() */
jmethodID jlrField_getModifiers; /* java.lang.reflect.Field.getModifiers() */
jmethodID jlBoolean_Boolean; /* java.lang.Boolean constructor */
jmethodID jlBoolean_booleanValue; /* java.lang.Boolean.booleanValue() */
jmethodID jlDouble_Double; /* java.lang.Double constructor */
jmethodID jlDouble_doubleValue; /* java.lang.Double.doubleValue() */
jmethodID jlThrowable_toString; /* java.lang.Throwable.toString() */
jmethodID jlThrowable_getMessage; /* java.lang.Throwable.getMessage() */
jmethodID jlSystem_identityHashCode; /* java.lang.System.identityHashCode() */
jobject jlVoid_TYPE; /* java.lang.Void.TYPE value */
jmethodID njJSException_JSException; /* netscape.javascript.JSexception constructor */
jmethodID njJSObject_JSObject; /* netscape.javascript.JSObject constructor */
jmethodID njJSUtil_getStackTrace; /* netscape.javascript.JSUtil.getStackTrace() */
jfieldID njJSObject_internal; /* netscape.javascript.JSObject.internal */
jfieldID njJSException_lineno; /* netscape.javascript.JSException.lineno */
jfieldID njJSException_tokenIndex; /* netscape.javascript.JSException.tokenIndex */
jfieldID njJSException_source; /* netscape.javascript.JSException.source */
jfieldID njJSException_filename; /* netscape.javascript.JSException.filename */
/* Obtain a reference to a Java class */
#define LOAD_CLASS(qualified_name, class) \
{ \
jclass _##class = (*jEnv)->FindClass(jEnv, #qualified_name); \
if (_##class == 0) { \
report_java_initialization_error(jEnv, \
"Can't load class " #qualified_name); \
return JS_FALSE; \
} \
class = (*jEnv)->NewGlobalRef(jEnv, _##class); \
}
/* Obtain a methodID reference to a Java method or constructor */
#define _LOAD_METHOD(qualified_class, method, mvar, signature, class, is_static)\
if (is_static) { \
class##_##mvar = \
(*jEnv)->GetStaticMethodID(jEnv, class, #method, signature); \
} else { \
class##_##mvar = \
(*jEnv)->GetMethodID(jEnv, class, #method, signature); \
} \
if (class##_##mvar == 0) { \
report_java_initialization_error(jEnv, \
"Can't get mid for " #qualified_class "." #method "()"); \
return JS_FALSE; \
}
/* Obtain a methodID reference to a Java instance method */
#define LOAD_METHOD(qualified_class, method, signature, class) \
_LOAD_METHOD(qualified_class, method, method, signature, class, JS_FALSE)
/* Obtain a methodID reference to a Java static method */
#define LOAD_STATIC_METHOD(qualified_class, method, signature, class) \
_LOAD_METHOD(qualified_class, method, method, signature, class, JS_TRUE)
/* Obtain a methodID reference to a Java constructor */
#define LOAD_CONSTRUCTOR(qualified_class, method, signature, class) \
_LOAD_METHOD(qualified_class,<init>, method, signature, class, JS_FALSE)
/* Obtain a fieldID reference to a Java instance or static field */
#define _LOAD_FIELDID(qualified_class, field, signature, class, is_static) \
if (is_static) { \
class##_##field = (*jEnv)->GetStaticFieldID(jEnv, class, #field, signature);\
} else { \
class##_##field = (*jEnv)->GetFieldID(jEnv, class, #field, signature);\
} \
if (class##_##field == 0) { \
report_java_initialization_error(jEnv, \
"Can't get fid for " #qualified_class "." #field); \
return JS_FALSE; \
}
/* Obtain a fieldID reference to a Java instance field */
#define LOAD_FIELDID(qualified_class, field, signature, class) \
_LOAD_FIELDID(qualified_class, field, signature, class, JS_FALSE)
/* Obtain the value of a static field in a Java class */
#define LOAD_FIELD_VAL(qualified_class, field, signature, class, type) \
{ \
jfieldID field_id; \
field_id = (*jEnv)->GetStaticFieldID(jEnv, class, #field, signature);\
if (field_id == 0) { \
report_java_initialization_error(jEnv, \
"Can't get fid for " #qualified_class "." #field); \
return JS_FALSE; \
} \
class##_##field = \
(*jEnv)->GetStatic##type##Field(jEnv, class, field_id); \
if (class##_##field == 0) { \
report_java_initialization_error(jEnv, \
"Can't read static field " #qualified_class "." #field); \
return JS_FALSE; \
} \
}
/* Obtain the value of a static field in a Java class, which is known to
contain an object value. */
#define LOAD_FIELD_OBJ(qualified_class, field, signature, class) \
LOAD_FIELD_VAL(qualified_class, field, signature, class, Object); \
class##_##field = (*jEnv)->NewGlobalRef(jEnv, class##_##field);
/*
* Load the Java classes, and the method and field descriptors required for Java reflection.
* Returns JS_TRUE on success, JS_FALSE on failure.
*/
static JSBool
init_java_VM_reflection(JSJavaVM *jsjava_vm, JNIEnv *jEnv)
{
/* Load Java system classes and method, including java.lang.reflect classes */
LOAD_CLASS(java/lang/Object, jlObject);
LOAD_CLASS(java/lang/Class, jlClass);
LOAD_CLASS(java/lang/reflect/Method, jlrMethod);
LOAD_CLASS(java/lang/reflect/Constructor, jlrConstructor);
LOAD_CLASS(java/lang/reflect/Field, jlrField);
LOAD_CLASS(java/lang/Throwable, jlThrowable);
LOAD_CLASS(java/lang/System, jlSystem);
LOAD_CLASS(java/lang/Boolean, jlBoolean);
LOAD_CLASS(java/lang/Double, jlDouble);
LOAD_CLASS(java/lang/String, jlString);
LOAD_CLASS(java/lang/Void, jlVoid);
LOAD_METHOD(java.lang.Class, getMethods, "()[Ljava/lang/reflect/Method;",jlClass);
LOAD_METHOD(java.lang.Class, getConstructors, "()[Ljava/lang/reflect/Constructor;",jlClass);
LOAD_METHOD(java.lang.Class, getFields, "()[Ljava/lang/reflect/Field;", jlClass);
LOAD_METHOD(java.lang.Class, getName, "()Ljava/lang/String;", jlClass);
LOAD_METHOD(java.lang.Class, isArray, "()Z", jlClass);
LOAD_METHOD(java.lang.Class, getComponentType, "()Ljava/lang/Class;", jlClass);
LOAD_METHOD(java.lang.Class, getModifiers, "()I", jlClass);
LOAD_METHOD(java.lang.reflect.Method, getName, "()Ljava/lang/String;", jlrMethod);
LOAD_METHOD(java.lang.reflect.Method, getParameterTypes, "()[Ljava/lang/Class;", jlrMethod);
LOAD_METHOD(java.lang.reflect.Method, getReturnType, "()Ljava/lang/Class;", jlrMethod);
LOAD_METHOD(java.lang.reflect.Method, getModifiers, "()I", jlrMethod);
LOAD_METHOD(java.lang.reflect.Constructor, getParameterTypes, "()[Ljava/lang/Class;", jlrConstructor);
LOAD_METHOD(java.lang.reflect.Constructor, getModifiers, "()I", jlrConstructor);
LOAD_METHOD(java.lang.reflect.Field, getName, "()Ljava/lang/String;", jlrField);
LOAD_METHOD(java.lang.reflect.Field, getType, "()Ljava/lang/Class;", jlrField);
LOAD_METHOD(java.lang.reflect.Field, getModifiers, "()I", jlrField);
LOAD_METHOD(java.lang.Throwable, toString, "()Ljava/lang/String;", jlThrowable);
LOAD_METHOD(java.lang.Throwable, getMessage, "()Ljava/lang/String;", jlThrowable);
LOAD_METHOD(java.lang.Double, doubleValue, "()D", jlDouble);
LOAD_METHOD(java.lang.Boolean, booleanValue, "()Z", jlBoolean);
LOAD_STATIC_METHOD(java.lang.System, identityHashCode, "(Ljava/lang/Object;)I", jlSystem);
LOAD_CONSTRUCTOR(java.lang.Boolean, Boolean, "(Z)V", jlBoolean);
LOAD_CONSTRUCTOR(java.lang.Double, Double, "(D)V", jlDouble);
LOAD_FIELD_OBJ(java.lang.Void, TYPE, "Ljava/lang/Class;", jlVoid);
}
/* Load Netscape-specific Java extension classes, methods, and fields */
static JSBool
init_netscape_java_classes(JSJavaVM *jsjava_vm, JNIEnv *jEnv)
{
LOAD_CLASS(netscape/javascript/JSObject, njJSObject);
LOAD_CLASS(netscape/javascript/JSException, njJSException);
LOAD_CLASS(netscape/javascript/JSUtil, njJSUtil);
LOAD_CONSTRUCTOR(netscape.javascript.JSObject,
JSObject, "(I)V", njJSObject);
LOAD_CONSTRUCTOR(netscape.javascript.JSException,
JSException, "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)V",
njJSException);
LOAD_FIELDID(netscape.javascript.JSObject,
internal, "I", njJSObject);
LOAD_FIELDID(netscape.javascript.JSException,
lineno, "I", njJSException);
LOAD_FIELDID(netscape.javascript.JSException,
tokenIndex, "I", njJSException);
LOAD_FIELDID(netscape.javascript.JSException,
source, "Ljava/lang/String;", njJSException);
LOAD_FIELDID(netscape.javascript.JSException,
filename, "Ljava/lang/String;", njJSException);
LOAD_STATIC_METHOD(netscape.javascript.JSUtil,
getStackTrace, "(Ljava/lang/Throwable;)Ljava/lang/String;",
njJSUtil);
return JS_TRUE;
}
JSJavaVM *jsjava_vm_list = NULL;
/*
* Called once per Java VM, this function initializes the classes, fields, and
* methods required for Java reflection. If java_vm is NULL, a new Java VM is
* created, using the provided classpath in addition to any default classpath.
* The classpath argument is ignored, however, if java_vm_arg is non-NULL.
*/
JSJavaVM *
JSJ_ConnectToJavaVM(JavaVM *java_vm_arg, const char *user_classpath)
{
JavaVM *java_vm;
JSJavaVM *jsjava_vm;
const char *full_classpath;
JNIEnv *jEnv;
jsjava_vm = (JSJavaVM*)malloc(sizeof(JSJavaVM));
if (!jsjava_vm)
return NULL;
memset(jsjava_vm, 0, sizeof(JSJavaVM));
java_vm = java_vm_arg;
/* If a Java VM was passed in, try to attach to it on the current thread. */
if (java_vm) {
if ((*java_vm)->AttachCurrentThread(java_vm, &jEnv, NULL) < 0) {
jsj_LogError("Failed to attach to Java VM thread\n");
free(jsjava_vm);
return NULL;
}
} else {
/* No Java VM supplied, so create our own */
JDK1_1InitArgs vm_args;
/* Magic constant indicates JRE version 1.1 */
vm_args.version = 0x00010001;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
/* Prepend the classpath argument to the default JVM classpath */
if (user_classpath) {
full_classpath = PR_smprintf("%s;%s", user_classpath, vm_args.classpath);
if (!full_classpath) {
free(jsjava_vm);
return NULL;
}
vm_args.classpath = (char*)full_classpath;
}
/* Attempt to create our own VM */
if (JNI_CreateJavaVM(&java_vm, &jEnv, &vm_args) < 0) {
jsj_LogError("Failed to create Java VM\n");
free(jsjava_vm);
return NULL;
}
/* Remember that we created the VM so that we know to destroy it later */
jsjava_vm->jsj_created_java_vm = JS_TRUE;
}
jsjava_vm->java_vm = java_vm;
jsjava_vm->main_thread_env = jEnv;
/* Load the Java classes, and the method and field descriptors required for
Java reflection. */
if (!init_java_VM_reflection(jsjava_vm, jEnv)) {
JSJ_DisconnectFromJavaVM(jsjava_vm);
return NULL;
}
/*
* JVM initialization for netscape.javascript.JSObject is performed
* independently of the other classes that are initialized in
* init_java_VM_reflection, because we allow it to fail. In the case
* of failure, LiveConnect is still operative, but only when calling
* from JS to Java and not vice-versa.
*/
init_netscape_java_classes(jsjava_vm, jEnv);
/* Put this VM on the list of all created VMs */
jsjava_vm->next = jsjava_vm_list;
jsjava_vm_list = jsjava_vm;
return jsjava_vm;
}
JSJCallbacks *JSJ_callbacks = NULL;
/* Called once to set up callbacks for all instances of LiveConnect */
void
JSJ_Init(JSJCallbacks *callbacks)
{
PR_ASSERT(callbacks);
JSJ_callbacks = callbacks;
}
/*
* Initialize the provided JSContext by setting up the JS classes necessary for
* reflection and by defining JavaPackage objects for the default Java packages
* as properties of global_obj. Additional packages may be pre-defined by
* setting the predefined_packages argument. (Pre-defining a Java package at
* initialization time is not necessary, but it will make package lookup faster
* and, more importantly, will avoid unnecessary network accesses if classes
* are being loaded over the network.)
*/
JSBool
JSJ_InitJSContext(JSContext *cx, JSObject *global_obj,
JavaPackageDef *predefined_packages)
{
/* Initialize the JavaScript classes used for reflection */
if (!jsj_init_JavaObject(cx, global_obj))
return JS_FALSE;
/* if (!jsj_init_JavaMember(cx, global_obj))
return JS_FALSE; */
if (!jsj_init_JavaPackage(cx, global_obj, predefined_packages))
return JS_FALSE;
if (!jsj_init_JavaClass(cx, global_obj))
return JS_FALSE;
if (!jsj_init_JavaArray(cx, global_obj))
return JS_FALSE;
return JS_TRUE;
}
/* Eliminate a reference to a Java class */
#define UNLOAD_CLASS(qualified_name, class) \
if (class) { \
(*jEnv)->DeleteGlobalRef(jEnv, class); \
class = NULL; \
}
/*
* This routine severs the connection to a Java VM, freeing all related resources.
* It shouldn't be called until the global scope has been cleared in all related
* JSContexts (so that all LiveConnect objects are finalized) and a JavaScript
* GC is performed. Otherwise, accessed to free'ed memory could result.
*/
void
JSJ_DisconnectFromJavaVM(JSJavaVM *jsjava_vm)
{
JNIEnv *jEnv;
JavaVM *java_vm;
java_vm = jsjava_vm->java_vm;
(*java_vm)->AttachCurrentThread(java_vm, &jEnv, NULL);
/* Drop all references to Java objects and classes */
jsj_DiscardJavaObjReflections(jEnv);
jsj_DiscardJavaClassReflections(jEnv);
if (jsjava_vm->jsj_created_java_vm) {
(*java_vm)->DestroyJavaVM(java_vm);
} else {
UNLOAD_CLASS(java/lang/Object, jlObject);
UNLOAD_CLASS(java/lang/Class, jlClass);
UNLOAD_CLASS(java/lang/reflect/Method, jlrMethod);
UNLOAD_CLASS(java/lang/reflect/Constructor, jlrConstructor);
UNLOAD_CLASS(java/lang/reflect/Field, jlrField);
UNLOAD_CLASS(java/lang/Throwable, jlThrowable);
UNLOAD_CLASS(java/lang/System, jlSystem);
UNLOAD_CLASS(java/lang/Boolean, jlBoolean);
UNLOAD_CLASS(java/lang/Double, jlDouble);
UNLOAD_CLASS(java/lang/String, jlString);
UNLOAD_CLASS(java/lang/Void, jlVoid);
UNLOAD_CLASS(netscape/javascript/JSObject, njJSObject);
UNLOAD_CLASS(netscape/javascript/JSException, njJSException);
UNLOAD_CLASS(netscape/javascript/JSUtil, njJSUtil);
}
}
static JSJavaThreadState *thread_list = NULL;
static JSJavaThreadState *
new_jsjava_thread_state(JSJavaVM *jsjava_vm, const char *thread_name, JNIEnv *jEnv)
{
JSJavaThreadState *jsj_env;
jsj_env = (JSJavaThreadState *)malloc(sizeof(JSJavaThreadState));
if (!jsj_env)
return NULL;
memset(jsj_env, 0, sizeof(JSJavaThreadState));
jsj_env->jEnv = jEnv;
jsj_env->jsjava_vm = jsjava_vm;
if (thread_name)
jsj_env->name = strdup(thread_name);
/* THREADSAFETY - need to protect against races */
jsj_env->next = thread_list;
thread_list = jsj_env;
return jsj_env;
}
static JSJavaThreadState *
find_jsjava_thread(JNIEnv *jEnv)
{
JSJavaThreadState *e, **p, *jsj_env;
jsj_env = NULL;
/* THREADSAFETY - need to protect against races in manipulating the thread list */
/* Search for the thread state among the list of all created
LiveConnect threads */
for (p = &thread_list; (e = *p) != NULL; p = &(e->next)) {
if (e->jEnv == jEnv) {
jsj_env = e;
*p = jsj_env->next;
break;
}
}
/* Move a found thread to head of list for faster search next time. */
if (jsj_env)
thread_list = jsj_env;
return jsj_env;
}
PR_PUBLIC_API(JSJavaThreadState *)
JSJ_AttachCurrentThreadToJava(JSJavaVM *jsjava_vm, const char *name, JNIEnv **java_envp)
{
JNIEnv *jEnv;
JavaVM *java_vm;
JSJavaThreadState *jsj_env;
/* Try to attach a Java thread to the current native thread */
java_vm = jsjava_vm->java_vm;
if ((*java_vm)->AttachCurrentThread(java_vm, &jEnv, NULL) < 0)
return NULL;
/* If we found an existing thread state, just return it. */
jsj_env = find_jsjava_thread(jEnv);
if (jsj_env)
return jsj_env;
/* Create a new wrapper around the thread/VM state */
jsj_env = new_jsjava_thread_state(jsjava_vm, name, jEnv);
if (java_envp)
*java_envp = jEnv;
return jsj_env;
}
static JSJavaVM *
map_java_vm_to_jsjava_vm(JavaVM *java_vm)
{
JSJavaVM *v;
for (v = jsjava_vm_list; v; v = v->next) {
if (v->java_vm == java_vm)
return v;
}
return NULL;
}
/*
* Unfortunately, there's no standard means to associate any private data with
* a JNI thread environment, so we need to use the Java environment pointer as
* the key in a lookup table that maps it to a JSJavaThreadState structure,
* where we store all our per-thread private data. If no existing thread state
* is found, a new one is created.
*
* If an error occurs, returns NULL and sets the errp argument to an error
* message, which the caller is responsible for free'ing.
*/
JSJavaThreadState *
jsj_MapJavaThreadToJSJavaThreadState(JNIEnv *jEnv, char **errp)
{
JSJavaThreadState *jsj_env;
JavaVM *java_vm;
JSJavaVM *jsjava_vm;
/* If we found an existing thread state, just return it. */
jsj_env = find_jsjava_thread(jEnv);
if (jsj_env)
return jsj_env;
/* No one set up a LiveConnect thread state for a given Java thread.
Invoke the callback to create one on-the-fly. */
/* First, figure out which Java VM is calling us */
if ((*jEnv)->GetJavaVM(jEnv, &java_vm) < 0)
return NULL;
/* Get our private JavaVM data */
jsjava_vm = map_java_vm_to_jsjava_vm(java_vm);
if (!jsjava_vm) {
*errp = PR_smprintf("Total weirdness: No JSJavaVM wrapper ever created "
"for JavaVM 0x%08x", java_vm);
return NULL;
}
jsj_env = new_jsjava_thread_state(jsjava_vm, NULL, jEnv);
if (!jsj_env)
return NULL;
return jsj_env;
}
/*
* This function is used to specify a particular JSContext as *the* JavaScript
* execution environment to be used when LiveConnect is accessed from the given
* Java thread, i.e. by using one of the methods of netscape.javascript.JSObject.
* (There can only be one such JS context for a given Java thread. To
* multiplex JSContexts among a single thread, this function must be called
* before Java is invoked on that thread.) The return value is the previous
* context associated with the given Java thread.
*/
PR_PUBLIC_API(JSContext *)
JSJ_SetDefaultJSContextForJavaThread(JSContext *cx, JSJavaThreadState *jsj_env)
{
JSContext *old_context;
old_context = jsj_env->cx;
jsj_env->cx = cx;
return old_context;
}
PR_PUBLIC_API(JSBool)
JSJ_DetachCurrentThreadFromJava(JSJavaThreadState *jsj_env)
{
JavaVM *java_vm;
JSJavaThreadState *e, **p;
/* Disassociate the current native thread from its corresponding Java thread */
java_vm = jsj_env->jsjava_vm->java_vm;
if ((*java_vm)->DetachCurrentThread(java_vm) < 0)
return JS_FALSE;
/* Destroy the LiveConnect execution environment passed in */
jsj_ClearPendingJSErrors(jsj_env);
/* THREADSAFETY - need to protect against races */
for (p = &thread_list; (e = *p) != NULL; p = &(e->next)) {
if (e == jsj_env) {
*p = jsj_env->next;
break;
}
}
free(jsj_env);
return JS_TRUE;
}
JSBool
JSJ_ConvertJavaObjectToJSValue(JSContext *cx, jobject java_obj, jsval *vp)
{
JNIEnv *jEnv;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, vp);
}
/*===========================================================================*/
/* The convenience functions below present a complete, but simplified
LiveConnect API which is designed to handle the special case of a single
Java-VM, single-threaded operation, and use of only one JSContext. */
/* We can get away with global variables in our single-threaded,
single-JSContext case. */
static JSJavaVM * the_jsj_vm = NULL;
static JSContext * the_cx = NULL;
static JSJavaThreadState * the_jsj_thread = NULL;
static JSObject * the_global_js_obj = NULL;
/* Trivial implementation of callback function */
static JSJavaThreadState *
default_map_js_context_to_jsj_thread(JSContext *cx, char **errp)
{
return the_jsj_thread;
}
/* Trivial implementation of callback function */
static JSContext *
default_map_jsj_thread_to_js_context(JSJavaThreadState *jsj_env, char **errp)
{
return the_cx;
}
/* Trivial implementation of callback function */
static JSObject *
default_map_java_object_to_js_object(JNIEnv *jEnv, jobject hint, char **errp)
{
return the_global_js_obj;
}
/* Trivial implementations of callback functions */
JSJCallbacks jsj_default_callbacks = {
default_map_jsj_thread_to_js_context,
default_map_js_context_to_jsj_thread,
default_map_java_object_to_js_object
};
/*
* Initialize the provided JSContext by setting up the JS classes necessary for
* reflection and by defining JavaPackage objects for the default Java packages
* as properties of global_obj. If java_vm is NULL, a new Java VM is
* created, using the provided classpath in addition to any default classpath.
* The classpath argument is ignored, however, if java_vm is non-NULL.
*/
JSBool
JSJ_SimpleInit(JSContext *cx, JSObject *global_obj, JavaVM *java_vm, const char *classpath)
{
JNIEnv *jEnv;
PR_ASSERT(!the_jsj_vm);
the_jsj_vm = JSJ_ConnectToJavaVM(java_vm, classpath);
if (!the_jsj_vm)
return JS_FALSE;
JSJ_Init(&jsj_default_callbacks);
if (!JSJ_InitJSContext(cx, global_obj, NULL))
goto error;
the_cx = cx;
the_global_js_obj = global_obj;
the_jsj_thread = JSJ_AttachCurrentThreadToJava(the_jsj_vm, "main thread", &jEnv);
if (!the_jsj_thread)
goto error;
return JS_TRUE;
error:
JSJ_SimpleShutdown();
return JS_FALSE;
}
/*
* Free up all LiveConnect resources. Destroy the Java VM if it was
* created by LiveConnect.
*/
PR_PUBLIC_API(void)
JSJ_SimpleShutdown()
{
PR_ASSERT(the_jsj_vm);
JSJ_DisconnectFromJavaVM(the_jsj_vm);
the_jsj_vm = NULL;
the_cx = NULL;
the_global_js_obj = NULL;
the_jsj_thread = NULL;
}

Просмотреть файл

@ -1,20 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
@ -28,9 +13,6 @@
#include <stdlib.h>
#include <string.h>
#include "prtypes.h"
#include "prprintf.h"
#include "prassert.h"
#include "jsj_private.h"
#include "jsjava.h"
@ -53,6 +35,7 @@ struct CapturedJSError {
/*********************** Reflection of JSObjects ****************************/
#ifdef PRESERVE_JSOBJECT_IDENTITY
/*
* This is a hash table that maps from JS objects to Java objects.
* It is used to ensure that the same Java object results when a JS
@ -72,11 +55,13 @@ static PRHashTable *js_obj_reflections = NULL;
* read/write or * write/write access.
*/
static PRMonitor *js_obj_reflections_monitor = NULL;
#endif
#endif /* JS_THREADSAFE */
#endif /* PRESERVE_JSOBJECT_IDENTITY */
static JSBool
init_js_obj_reflections_table()
{
#ifdef PRESERVE_JSOBJECT_IDENTITY
js_obj_reflections = PR_NewHashTable(128, NULL, PR_CompareValues,
PR_CompareValues, NULL, NULL);
if (!js_obj_reflections)
@ -88,7 +73,8 @@ init_js_obj_reflections_table()
PR_HashTableDestroy(js_obj_reflections);
return JS_FALSE;
}
#endif
#endif /* JS_THREADSAFE */
#endif /* PRESERVE_JSOBJECT_IDENTITY */
return JS_TRUE;
}
@ -101,6 +87,9 @@ init_js_obj_reflections_table()
*
* If an error occurs, returns NULL and reports an error.
*/
#ifdef PRESERVE_JSOBJECT_IDENTITY
jobject
jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj)
{
@ -115,16 +104,14 @@ jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj)
/* First, look in the hash table for an existing reflection of the same
JavaScript object. If one is found, return it. */
hep = PR_HashTableRawLookup(js_obj_reflections, (prhashcode)js_obj, js_obj);
hep = PR_HashTableRawLookup(js_obj_reflections, (PRHashNumber)js_obj, js_obj);
#ifdef PRESERVE_JSOBJECT_IDENTITY
/* If the same JSObject is reflected into Java more than once then we should
return the same Java object, both for efficiency and so that the '=='
operator works as expected in Java when comparing two JSObjects.
However, it is not possible to hold a reference to a Java object without
inhibiting GC of that object, at least not in a way that is portable
to all vendor's JVM, i.e. a weak reference. So, for now, JSObject identity
is broken. */
inhibiting GC of that object, at least not in a portable way, i.e.
a weak reference. So, for now, JSObject identity is broken. */
he = *hep;
if (he) {
@ -133,7 +120,6 @@ jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj)
if (java_wrapper_obj)
goto done;
}
#endif /* PRESERVE_JSOBJECT_IDENTITY */
/* No existing reflection found, so create a new Java object that wraps
the JavaScript object by storing its address in a private integer field. */
@ -146,7 +132,7 @@ jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj)
}
/* Add the new reflection to the hash table. */
he = PR_HashTableRawAdd(js_obj_reflections, hep, (prhashcode)js_obj,
he = PR_HashTableRawAdd(js_obj_reflections, hep, (PRHashNumber)js_obj,
js_obj, java_wrapper_obj);
if (he) {
/* Tell the JavaScript GC about this object since the only reference
@ -188,7 +174,7 @@ remove_js_obj_reflection_from_hashtable(JSContext *cx, JSObject *js_obj)
#endif
/* Get the hash-table entry for this wrapper object */
hep = PR_HashTableRawLookup(js_obj_reflections, (prhashcode)js_obj, js_obj);
hep = PR_HashTableRawLookup(js_obj_reflections, (PRHashNumber)js_obj, js_obj);
he = *hep;
PR_ASSERT(he);
@ -207,6 +193,64 @@ remove_js_obj_reflection_from_hashtable(JSContext *cx, JSObject *js_obj)
return success;
}
#else /* !PRESERVE_JSOBJECT_IDENTITY */
/* This object provides is the "anchor" by which netscape.javscript.JSObject
objects hold a reference to native JSObjects. */
typedef struct JSObjectRoot {
JSObject *js_obj;
JSContext *cx; /* Creating context, needed for finalization */
} JSObjectHandle;
/*
* The caller must call DeleteLocalRef() on the returned object when no more
* references remain.
*/
jobject
jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj)
{
jobject java_wrapper_obj;
JSObjectHandle *handle;
/* Create a tiny stub object to act as the GC root that points to the
JSObject from its netscape.javascript.JSObject counterpart. */
handle = (JSObjectHandle*)JS_malloc(cx, sizeof(JSObjectHandle));
if (!handle)
return NULL;
handle->js_obj = js_obj;
handle->cx = cx;
/* No existing reflection found, so create a new Java object that wraps
the JavaScript object by storing its address in a private integer field. */
java_wrapper_obj =
(*jEnv)->NewObject(jEnv, njJSObject, njJSObject_JSObject, (jint)handle);
if (!java_wrapper_obj) {
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't create new instance of "
"netscape.javascript.JSObject");
goto done;
}
JS_AddRoot(cx, &handle->js_obj);
done:
return java_wrapper_obj;
}
JSObject *
jsj_UnwrapJSObjectWrapper(JNIEnv *jEnv, jobject java_wrapper_obj)
{
JSObjectHandle *handle;
handle = (JSObjectHandle*)((*jEnv)->GetIntField(jEnv, java_wrapper_obj, njJSObject_internal));
PR_ASSERT(handle);
if (!handle)
return NULL;
return handle->js_obj;
}
#endif /* !PRESERVE_JSOBJECT_IDENTITY */
/*************** Handling of Java exceptions in JavaScript ******************/
/*
@ -498,7 +542,6 @@ done:
}
/*************** Utilities for calling JavaScript from Java *****************/
/*
@ -523,14 +566,19 @@ enter_js(JNIEnv *jEnv, jobject java_wrapper_obj,
/* Invoke callback, presumably used to implement concurrency constraints */
if (JSJ_callbacks->enter_js_from_java) {
if (!JSJ_callbacks->enter_js_from_java(&err_msg))
if (!JSJ_callbacks->enter_js_from_java(jEnv, &err_msg))
goto entry_failure;
}
/* Check the JSObject pointer in the wrapper object for null while holding
the JS lock to deal with shutdown issues. */
/* Check the JSObject pointer in the wrapper object. */
if (js_objp) {
#ifdef PRESERVE_JSOBJECT_IDENTITY
js_obj = (JSObject *)((*jEnv)->GetIntField(jEnv, java_wrapper_obj, njJSObject_internal));
#else /* !PRESERVE_JSOBJECT_IDENTITY */
js_obj = jsj_UnwrapJSObjectWrapper(jEnv, java_wrapper_obj);
#endif /* PRESERVE_JSOBJECT_IDENTITY */
PR_ASSERT(js_obj);
if (!js_obj)
goto error;
@ -549,7 +597,7 @@ enter_js(JNIEnv *jEnv, jobject java_wrapper_obj,
Java and back into JS. Invoke a callback to obtain/create a
JSContext for us to use. */
if (JSJ_callbacks->map_jsj_thread_to_js_context) {
cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env, &err_msg);
cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env, jEnv, &err_msg);
if (!cx)
goto error;
} else {
@ -572,7 +620,7 @@ enter_js(JNIEnv *jEnv, jobject java_wrapper_obj,
error:
/* Invoke callback, presumably used to implement concurrency constraints */
if (JSJ_callbacks->exit_js)
JSJ_callbacks->exit_js();
JSJ_callbacks->exit_js(jEnv);
entry_failure:
if (err_msg) {
@ -617,7 +665,7 @@ exit_js(JSContext *cx, JSJavaThreadState *jsj_env, JSErrorReporter original_repo
/* Invoke callback, presumably used to implement concurrency constraints */
if (JSJ_callbacks->exit_js)
JSJ_callbacks->exit_js();
JSJ_callbacks->exit_js(jEnv);
return JS_TRUE;
}
@ -680,7 +728,7 @@ Java_netscape_javascript_JSObject_getMember(JNIEnv *jEnv,
property_name_ucs2 = NULL;
if (!property_name_jstr) {
JS_ReportError(cx, "illegal null member name");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_NULL_MEMBER_NAME);
member = NULL;
goto done;
}
@ -771,7 +819,7 @@ Java_netscape_javascript_JSObject_setMember(JNIEnv *jEnv,
property_name_ucs2 = NULL;
if (!property_name_jstr) {
JS_ReportError(cx, "illegal null member name");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_NULL_MEMBER_NAME);
goto done;
}
@ -847,7 +895,7 @@ Java_netscape_javascript_JSObject_removeMember(JNIEnv *jEnv,
return;
if (!property_name_jstr) {
JS_ReportError(cx, "illegal null member name");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_NULL_MEMBER_NAME);
goto done;
}
/* Get the Unicode string for the JS property name */
@ -897,7 +945,8 @@ Java_netscape_javascript_JSObject_call(JNIEnv *jEnv, jobject java_wrapper_obj,
function_name_ucs2 = NULL;
result = NULL;
if (!function_name_jstr) {
JS_ReportError(cx, "illegal null JavaScript function name");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_NULL_FUNCTION_NAME);
goto done;
}
@ -985,7 +1034,7 @@ Java_netscape_javascript_JSObject_eval(JNIEnv *jEnv,
result = NULL;
eval_ucs2 = NULL;
if (!eval_jstr) {
JS_ReportError(cx, "illegal null string eval argument");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_NULL_EVAL_ARG);
goto done;
}
@ -1108,15 +1157,49 @@ done:
JNIEXPORT void JNICALL
Java_netscape_javascript_JSObject_finalize(JNIEnv *jEnv, jobject java_wrapper_obj)
{
JSBool success;
JSContext *cx;
JSErrorReporter saved_reporter;
JSJavaThreadState *jsj_env;
JSObject *js_obj;
jsj_env = enter_js(jEnv, java_wrapper_obj, &cx, &js_obj, &saved_reporter);
if (!jsj_env) /* Note: memory leak if we exit here */
JSObjectHandle *handle;
success = JS_FALSE;
handle = (JSObjectHandle *)((*jEnv)->GetIntField(jEnv, java_wrapper_obj, njJSObject_internal));
PR_ASSERT(handle);
if (!handle)
return;
remove_js_obj_reflection_from_hashtable(cx, js_obj);
exit_js(cx, jsj_env, saved_reporter);
cx = handle->cx;
success = JS_RemoveRoot(cx, &handle->js_obj);
JS_free(cx, handle);
PR_ASSERT(success);
}
/*
* Class: netscape_javascript_JSObject
* Method: equals
* Signature: (Ljava/lang/Object;)Z
*/
JNIEXPORT jboolean JNICALL
Java_netscape_javascript_JSObject_equals(JNIEnv *jEnv,
jobject java_wrapper_obj,
jobject comparison_obj)
{
#ifdef PRESERVE_JSOBJECT_IDENTITY
# error "Missing code should be added here"
#else
JSObject *js_obj1, *js_obj2;
/* Check that we're comparing with another netscape.javascript.JSObject */
if (!comparison_obj)
return 0;
if (!(*jEnv)->IsInstanceOf(jEnv, comparison_obj, njJSObject))
return 0;
js_obj1 = jsj_UnwrapJSObjectWrapper(jEnv, java_wrapper_obj);
js_obj2 = jsj_UnwrapJSObjectWrapper(jEnv, comparison_obj);
return (js_obj1 == js_obj2);
#endif /* PRESERVE_JSOBJECT_IDENTITY */
}

Просмотреть файл

@ -1,20 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/*
@ -26,13 +11,9 @@
#include <stdlib.h>
#include <string.h>
#include "prassert.h"
#include "jsj_private.h" /* LiveConnect internals */
/* Shorthands for ASCII (7-bit) decimal and hex conversion. */
#define JS7_ISDEC(c) (((c) >= '0') && ((c) <= '9'))
#define JS7_UNDEC(c) ((c) - '0')
#include "jscntxt.h" /* for error reporting */
/*
* Convert any jsval v to an integer jsval if ToString(v)
@ -99,7 +80,7 @@ access_java_array_element(JSContext *cx,
return JS_TRUE;
}
}
JS_ReportError(cx, "illegal operation on JavaArray prototype object");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_BAD_OP_JARRAY);
return JS_FALSE;
}
class_descriptor = java_wrapper->class_descriptor;
@ -128,8 +109,8 @@ access_java_array_element(JSContext *cx,
if (!JSVERSION_IS_ECMA(version)) {
JS_ReportError(cx, "Attempt to write to invalid Java array "
"element \"%s\"", member_name);
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_CANT_WRITE_JARRAY, member_name);
return JS_FALSE;
} else {
*vp = JSVAL_VOID;
@ -150,7 +131,7 @@ access_java_array_element(JSContext *cx,
}
}
JS_ReportError(cx, "invalid Java array index expression");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_BAD_INDEX_EXPR);
return JS_FALSE;
}
@ -163,7 +144,10 @@ access_java_array_element(JSContext *cx,
/* Just let Java throw an exception instead of checking array bounds here */
if (index < 0 || index >= array_length) {
JS_ReportError(cx, "Java array index %d out of range", index);
char numBuf[12];
sprintf(numBuf, "%d", index);
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_BAD_JARRAY_INDEX, numBuf);
return JS_FALSE;
}
#endif
@ -223,7 +207,7 @@ JavaArray_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter,
uintN attrs, JSProperty **propp)
{
JS_ReportError(cx, "Cannot define a new property in a JavaArray");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_JARRAY_PROP_DEFINE);
return JS_FALSE;
}
@ -241,7 +225,7 @@ JavaArray_setAttributes(JSContext *cx, JSObject *obj, jsid id,
JSProperty *prop, uintN *attrsp)
{
/* We don't maintain JS property attributes for Java class members */
if (*attrsp != JSPROP_PERMANENT|JSPROP_ENUMERATE) {
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
PR_ASSERT(0);
return JS_FALSE;
}
@ -258,7 +242,7 @@ JavaArray_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
*vp = JSVAL_FALSE;
if (!JSVERSION_IS_ECMA(version)) {
JS_ReportError(cx, "Properties of JavaArray objects may not be deleted");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_JARRAY_PROP_DELETE);
return JS_FALSE;
} else {
/* Attempts to delete permanent properties are silently ignored
@ -335,11 +319,11 @@ JavaArray_checkAccess(JSContext *cx, JSObject *obj, jsid id,
{
switch (mode) {
case JSACC_WATCH:
JS_ReportError(cx, "Cannot place watchpoints on JavaArray object properties");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_JARRAY_PROP_WATCH);
return JS_FALSE;
case JSACC_IMPORT:
JS_ReportError(cx, "Cannot export a JavaArray object's properties");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_JARRAY_PROP_EXPORT);
return JS_FALSE;
default:
@ -384,7 +368,7 @@ JSClass JavaArray_class = {
JavaArray_getObjectOps,
};
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps;
/* Initialize the JS JavaArray class */

Просмотреть файл

@ -1,20 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
@ -36,11 +21,8 @@
#include <stdlib.h>
#include <string.h>
#include "prtypes.h"
#include "prprintf.h"
#include "prassert.h"
#include "jsj_private.h" /* LiveConnect internals */
#include "jscntxt.h" /* for error reporting */
static JSBool
JavaClass_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
@ -79,8 +61,9 @@ JavaClass_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
return JS_TRUE;
default:
return JS_TRUE;
break;
}
return JS_TRUE;
}
static JSBool
@ -107,9 +90,9 @@ lookup_static_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
if (!member_descriptor) {
JS_IdToValue(cx, id, &idval);
if (!JSVAL_IS_STRING(idval)) {
JS_ReportError(cx, "invalid JavaClass property expression. "
"(methods and fields of a JavaClass object can only be identified by their name)");
return JS_FALSE;
JS_ReportErrorNumber(cx,
jsj_GetErrorMessage, JSJMSG_BAD_JCLASS_EXPR);
return JS_FALSE;
}
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
@ -120,7 +103,7 @@ lookup_static_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
return JS_TRUE;
}
JS_ReportError(cx, "Java class %s has no public static field or method named \"%s\"",
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_MISSING_NAME,
class_descriptor->name, member_name);
return JS_FALSE;
}
@ -173,8 +156,8 @@ JavaClass_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(JS_GetFunctionObject(function));
return JS_TRUE;
}
return JS_TRUE;
}
PR_STATIC_CALLBACK(JSBool)
@ -212,7 +195,7 @@ JavaClass_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
no_such_field:
JS_IdToValue(cx, id, &idval);
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
JS_ReportError(cx, "No static field named \"%s\" in Java class %s",
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_MISSING_STATIC,
member_name, class_descriptor->name);
return JS_FALSE;
}
@ -234,7 +217,7 @@ JavaClass_finalize(JSContext *cx, JSObject *obj)
if (!jEnv)
return;
printf("Finalizing %s\n", class_descriptor->name);
/* printf("Finalizing %s\n", class_descriptor->name); */
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
}
@ -248,18 +231,25 @@ JavaClass_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
)
{
JNIEnv *jEnv;
JSErrorReporter old_reporter;
/* printf("In JavaClass_lookupProperty()\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
if (!lookup_static_member_by_id(cx, jEnv, obj, NULL, id, NULL))
return JS_FALSE;
*objp = obj;
*propp = (JSProperty*)1;
old_reporter = JS_SetErrorReporter(cx, NULL);
if (lookup_static_member_by_id(cx, jEnv, obj, NULL, id, NULL)) {
*objp = obj;
*propp = (JSProperty*)1;
} else {
*objp = NULL;
*propp = NULL;
}
JS_SetErrorReporter(cx, old_reporter);
return JS_TRUE;
}
@ -268,7 +258,7 @@ JavaClass_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter,
uintN attrs, JSProperty **propp)
{
JS_ReportError(cx, "Cannot define a new property in a JavaClass");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_JCLASS_PROP_DEFINE);
return JS_FALSE;
}
@ -286,7 +276,7 @@ JavaClass_setAttributes(JSContext *cx, JSObject *obj, jsid id,
JSProperty *prop, uintN *attrsp)
{
/* We don't maintain JS property attributes for Java class members */
if (*attrsp != JSPROP_PERMANENT|JSPROP_ENUMERATE) {
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
PR_ASSERT(0);
return JS_FALSE;
}
@ -303,7 +293,8 @@ JavaClass_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
*vp = JSVAL_FALSE;
if (!JSVERSION_IS_ECMA(version)) {
JS_ReportError(cx, "Properties of JavaClass objects may not be deleted");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_JCLASS_PROP_DELETE);
return JS_FALSE;
} else {
/* Attempts to delete permanent properties are silently ignored
@ -374,11 +365,13 @@ JavaClass_checkAccess(JSContext *cx, JSObject *obj, jsid id,
{
switch (mode) {
case JSACC_WATCH:
JS_ReportError(cx, "Cannot place watchpoints on JavaClass object properties");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_JCLASS_PROP_WATCH);
return JS_FALSE;
case JSACC_IMPORT:
JS_ReportError(cx, "Cannot export a JavaClass object's properties");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_JCLASS_PROP_EXPORT);
return JS_FALSE;
default:
@ -406,7 +399,7 @@ JavaClass_hasInstance(JSContext *cx, JSObject *obj, jsval candidate_jsval,
has_instance = JS_FALSE;
class_descriptor = JS_GetPrivate(cx, obj);
if (!class_descriptor) {
JS_ReportError(cx, "illegal operation on JavaClass prototype object");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_BAD_OP_JCLASS);
return JS_FALSE;
}
@ -424,7 +417,7 @@ JavaClass_hasInstance(JSContext *cx, JSObject *obj, jsval candidate_jsval,
java_class = class_descriptor->java_class;
java_wrapper = JS_GetPrivate(cx, candidate_obj);
if (!java_wrapper) {
JS_ReportError(cx, "illegal operation on prototype object");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_BAD_OP_PROTO);
return JS_FALSE;
}
java_obj = java_wrapper->java_obj;
@ -538,17 +531,17 @@ getClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_FALSE;
if (argc != 1 ||
!JSVAL_IS_OBJECT(argv[0]) ||
!(obj_arg = JSVAL_TO_OBJECT(argv[0])) ||
(!JS_InstanceOf(cx, obj_arg, &JavaObject_class, 0) &&
!JSVAL_IS_OBJECT(argv[0]) ||
!(obj_arg = JSVAL_TO_OBJECT(argv[0])) ||
(!JS_InstanceOf(cx, obj_arg, &JavaObject_class, 0) &&
!JS_InstanceOf(cx, obj_arg, &JavaArray_class, 0))) {
JS_ReportError(cx, "getClass expects a Java object argument");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_NEED_JOBJECT_ARG);
return JS_FALSE;
}
java_wrapper = JS_GetPrivate(cx, obj_arg);
if (!java_wrapper) {
JS_ReportError(cx, "getClass called on prototype object");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_PROTO_GETCLASS);
return JS_FALSE;
}
@ -561,7 +554,7 @@ getClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_TRUE;
}
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps;
JSBool
jsj_init_JavaClass(JSContext *cx, JSObject *global_obj)

Просмотреть файл

@ -1,20 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/*
@ -28,10 +13,10 @@
#include <stdlib.h>
#include <string.h>
#include "prassert.h"
#include "jsj_private.h" /* LiveConnect internals */
#include "jsj_hash.h" /* Hash table with Java object as key */
#include "jscntxt.h" /* for error reporting */
/*
@ -229,9 +214,13 @@ enumerate_remove_java_obj(JSJHashEntry *he, PRIntn i, void *arg)
void
jsj_DiscardJavaObjReflections(JNIEnv *jEnv)
{
JSJ_HashTableEnumerateEntries(java_obj_reflections,
enumerate_remove_java_obj,
(void*)jEnv);
if (java_obj_reflections) {
JSJ_HashTableEnumerateEntries(java_obj_reflections,
enumerate_remove_java_obj,
(void*)jEnv);
JSJ_HashTableDestroy(java_obj_reflections);
java_obj_reflections = NULL;
}
}
PR_CALLBACK JSBool
@ -254,7 +243,7 @@ JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
return JS_TRUE;
}
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_BAD_OP_JOBJECT);
return JS_FALSE;
}
@ -267,7 +256,7 @@ JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
return JS_TRUE;
case JSTYPE_FUNCTION:
JS_ReportError(cx, "can't convert Java object to function");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_CONVERT_TO_FUNC);
return JS_FALSE;
case JSTYPE_VOID:
@ -278,11 +267,11 @@ JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
case JSTYPE_NUMBER:
/* Call Java doubleValue() method, if applicable */
return jsj_ConvertJavaObjectToJSNumber(cx, jEnv, java_obj, vp);
return jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, vp);
case JSTYPE_BOOLEAN:
/* Call booleanValue() method, if applicable */
return jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, java_obj, vp);
return jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, vp);
default:
PR_ASSERT(0);
@ -312,7 +301,7 @@ lookup_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
return JS_TRUE;
}
}
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_BAD_OP_JOBJECT);
return JS_FALSE;
}
@ -324,16 +313,16 @@ lookup_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
if (!member_descriptor) {
JS_IdToValue(cx, id, &idval);
if (!JSVAL_IS_STRING(idval)) {
JS_ReportError(cx, "invalid JavaObject property expression. "
"(methods and field properties of a JavaObject object can only be strings)");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_BAD_JOBJECT_EXPR);
return JS_FALSE;
}
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
JS_ReportError(cx, "Java class %s has no public instance field or "
"method named \"%s\"",
class_descriptor->name, member_name);
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_NO_INSTANCE_NAME,
class_descriptor->name, member_name);
return JS_FALSE;
}
@ -353,6 +342,8 @@ JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
JavaObjectWrapper *java_wrapper;
JNIEnv *jEnv;
JSObject *funobj;
jsval field_val, method_val;
JSBool success;
/* printf("In JavaObject_getProperty\n"); */
@ -372,22 +363,56 @@ JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
}
java_obj = java_wrapper->java_obj;
field_val = method_val = JSVAL_VOID;
/* If a field member, get the value of the field */
if (member_descriptor->field) {
if (!member_descriptor->methods) {
return jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, vp);
} else {
PR_ASSERT(0);
}
} else {
success = jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, &field_val);
if (!success)
return JS_FALSE;
}
/* If a method member, build a wrapper around the Java method */
if (member_descriptor->methods) {
/* Create a function object with this JavaObject as its parent, so that
JSFUN_BOUND_METHOD binds it as the default 'this' for the function. */
funobj = JS_CloneFunctionObject(cx, member_descriptor->invoke_func_obj, obj);
if (funobj) {
*vp = OBJECT_TO_JSVAL(funobj);
return JS_TRUE;
}
return JS_FALSE;
if (!funobj)
return JS_FALSE;
method_val = OBJECT_TO_JSVAL(funobj);
}
#if TEST_JAVAMEMBER
/* Always create a JavaMember object, even though it's inefficient */
obj = jsj_CreateJavaMember(cx, method_val, field_val);
if (!obj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(obj);
#else /* !TEST_JAVAMEMBER */
if (member_descriptor->field) {
if (!member_descriptor->methods) {
/* Return value of Java field */
*vp = field_val;
} else {
/* Handle special case of access to a property that could refer
to either a Java field or a method that share the same name.
In Java, such ambiguity is not possible because the compiler
can statically determine which is being accessed. */
obj = jsj_CreateJavaMember(cx, method_val, field_val);
if (!obj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(obj);
}
} else {
/* Return wrapper around Java method */
*vp = method_val;
}
#endif /* !TEST_JAVAMEMBER */
return JS_TRUE;
}
PR_STATIC_CALLBACK(JSBool)
@ -427,43 +452,11 @@ no_such_field:
JS_IdToValue(cx, id, &idval);
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
class_descriptor = java_wrapper->class_descriptor;
JS_ReportError(cx, "No instance field named \"%s\" in Java class %s",
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_NO_NAME_IN_CLASS,
member_name, class_descriptor->name);
return JS_FALSE;
}
PR_CALLBACK JSBool
JavaObject_enumerate(JSContext *cx, JSObject *obj)
{
JavaObjectWrapper *java_wrapper;
JavaClassDescriptor *class_descriptor;
JavaMemberDescriptor *member_descriptor;
JNIEnv *jEnv;
/* printf("In JavaObject_enumerate\n"); */
java_wrapper = JS_GetPrivate(cx, obj);
/* Check if this is the prototype object */
if (!java_wrapper)
return JS_TRUE;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
class_descriptor = java_wrapper->class_descriptor;
member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
while (member_descriptor) {
JS_DefineProperty(cx, obj, member_descriptor->name, JSVAL_VOID, 0, 0,
JSPROP_PERMANENT|JSPROP_ENUMERATE);
member_descriptor = member_descriptor->next;
}
return JS_TRUE;
}
static JSBool
JavaObject_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
JSObject **objp, JSProperty **propp
@ -473,6 +466,7 @@ JavaObject_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
)
{
JNIEnv *jEnv;
JSErrorReporter old_reporter;
/* printf("In JavaObject_lookupProperty()\n"); */
@ -481,10 +475,16 @@ JavaObject_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
if (!jEnv)
return JS_FALSE;
if (!lookup_member_by_id(cx, jEnv, obj, NULL, id, NULL))
return JS_FALSE;
*objp = obj;
*propp = (JSProperty*)1;
old_reporter = JS_SetErrorReporter(cx, NULL);
if (lookup_member_by_id(cx, jEnv, obj, NULL, id, NULL)) {
*objp = obj;
*propp = (JSProperty*)1;
} else {
*objp = NULL;
*propp = NULL;
}
JS_SetErrorReporter(cx, old_reporter);
return JS_TRUE;
}
@ -493,7 +493,7 @@ JavaObject_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter,
uintN attrs, JSProperty **propp)
{
JS_ReportError(cx, "Cannot define a new property in a JavaObject");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_JOBJECT_PROP_DEFINE);
return JS_FALSE;
}
@ -511,7 +511,7 @@ JavaObject_setAttributes(JSContext *cx, JSObject *obj, jsid id,
JSProperty *prop, uintN *attrsp)
{
/* We don't maintain JS property attributes for Java class members */
if (*attrsp != JSPROP_PERMANENT|JSPROP_ENUMERATE) {
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
PR_ASSERT(0);
return JS_FALSE;
}
@ -528,7 +528,8 @@ JavaObject_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
*vp = JSVAL_FALSE;
if (!JSVERSION_IS_ECMA(version)) {
JS_ReportError(cx, "Properties of JavaObject objects may not be deleted");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_JOBJECT_PROP_DELETE);
return JS_FALSE;
} else {
/* Attempts to delete permanent properties are silently ignored
@ -541,7 +542,7 @@ static JSBool
JavaObject_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
/* printf("In JavaObject_defaultValue()\n"); */
return JavaObject_convert(cx, obj, JSTYPE_STRING, vp);
return JavaObject_convert(cx, obj, type, vp);
}
static JSBool
@ -604,11 +605,13 @@ JavaObject_checkAccess(JSContext *cx, JSObject *obj, jsid id,
{
switch (mode) {
case JSACC_WATCH:
JS_ReportError(cx, "Cannot place watchpoints on JavaObject object properties");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_JOBJECT_PROP_WATCH);
return JS_FALSE;
case JSACC_IMPORT:
JS_ReportError(cx, "Cannot export a JavaObject object's properties");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_JOBJECT_PROP_EXPORT);
return JS_FALSE;
default:
@ -653,7 +656,7 @@ JSClass JavaObject_class = {
JavaObject_getObjectOps,
};
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps;
JSBool

Просмотреть файл

@ -1,20 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
@ -36,12 +21,9 @@
#include <stdlib.h>
#include <string.h>
#include "prtypes.h"
#include "prprintf.h"
#include "prosdep.h"
#include "jsj_private.h" /* LiveConnect internals */
#include "jsjava.h"
#include "jscntxt.h" /* for error reporting */
JSClass JavaPackage_class; /* Forward declaration */
@ -99,11 +81,11 @@ JavaPackage_setProperty(JSContext *cx, JSObject *obj, jsval slot, jsval *vp)
{
JavaPackage_Private *package = JS_GetPrivate(cx, obj);
if (!package) {
JS_ReportError(cx, "illegal attempt to add property to "
"JavaPackage prototype object");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_BAD_ADD_TO_PACKAGE);
return JS_FALSE;
}
JS_ReportError(cx, "You may not add properties to a JavaPackage object");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_DONT_ADD_TO_PACKAGE);
return JS_FALSE;
}
@ -121,13 +103,17 @@ JavaPackage_resolve(JSContext *cx, JSObject *obj, jsval id)
char *subPath, *newPath;
const char *path;
JNIEnv *jEnv;
/* Painful hack for pre_define_java_packages() */
if (quiet_resolve_failure)
return JS_FALSE;
package = (JavaPackage_Private *)JS_GetPrivate(cx, obj);
if (!package)
return JS_TRUE;
if (!JSVAL_IS_STRING(id))
return JS_TRUE;
return JS_TRUE;
subPath = JS_GetStringBytes(JSVAL_TO_STRING(id));
/*
@ -186,6 +172,11 @@ JavaPackage_resolve(JSContext *cx, JSObject *obj, jsval id)
}
} else {
/* We assume that any failed attempt to load a class is because it
doesn't exist. If we wanted to do a better job, we would check
the exception type and make sure that it's NoClassDefFoundError */
(*jEnv)->ExceptionClear(jEnv);
/*
* If there's no class of the given name, then we must be referring to
* a package. However, don't allow bogus sub-packages of pre-defined
@ -197,14 +188,12 @@ JavaPackage_resolve(JSContext *cx, JSObject *obj, jsval id)
package = JS_GetPrivate(cx, obj);
if (package->flags & PKG_SYSTEM) {
char *msg, *cp;
/* Painful hack for pre_define_java_packages() */
if (quiet_resolve_failure)
return JS_FALSE;
/*
msg = PR_smprintf("No Java system package with name \"%s\" was identified "
"and no Java class with that name exists either",
newPath);
*/
msg = JS_strdup(cx, newPath);
/* Check for OOM */
if (msg) {
@ -212,10 +201,10 @@ JavaPackage_resolve(JSContext *cx, JSObject *obj, jsval id)
for (cp = msg; *cp != '\0'; cp++)
if (*cp == '/')
*cp = '.';
JS_ReportError(cx, msg);
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_MISSING_PACKAGE, msg);
free((char*)msg);
}
return JS_FALSE;
}
}
@ -357,7 +346,8 @@ standard_java_packages[] = {
{"sun", NULL, PKG_USER},
{"Packages", "", PKG_USER},
0
{NULL, NULL, 0}
};
/*
@ -394,7 +384,8 @@ pre_define_java_packages(JSContext *cx, JSObject *global_obj,
jsval v;
if (!simple_name) {
JS_ReportError(cx, "Package %s defined twice ?", package_name);
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_DOUBLE_SHIPPING, package_name);
goto error;
}
@ -410,7 +401,8 @@ pre_define_java_packages(JSContext *cx, JSObject *global_obj,
/* New package objects should only be created at the terminal
sub-package in a fully-qualified package-name */
if (strtok(NULL, ".")) {
JS_ReportError(cx, "Illegal predefined package definition for %s",
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_BAD_PACKAGE_PREDEF,
package_def->name);
goto error;
}
@ -458,7 +450,7 @@ error:
static JSBool
JavaPackage_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
jsval *rval)
{
if (!JS_InstanceOf(cx, obj, &JavaPackage_class, argv))
return JS_FALSE;

Просмотреть файл

@ -1,183 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the code for reading and writing elements of a Java array.
*/
#include "prtypes.h"
#include "prassert.h"
#include "jsj_private.h" /* LiveConnect internals */
/*
* Read the Java value at a given index into a Java array and convert it
* to a JS value. The array_component_signature describes the type of
* the resulting Java value, which can be a primitive type or an object type.
* More specifically it can be an array type in the case of multidimensional
* arrays.
*/
JSBool
jsj_GetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array, jsize index,
JavaSignature *array_component_signature,
jsval *vp)
{
jvalue java_value;
JavaSignatureChar component_type;
#define GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Type,member) \
(*jEnv)->Get##Type##ArrayRegion(jEnv, java_array, index, 1, \
&java_value.member); \
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
jsj_ReportJavaError(cx, jEnv, "Error reading element of " \
"Java primitive array"); \
return JS_FALSE; \
}
component_type = array_component_signature->type;
switch(component_type) {
case JAVA_SIGNATURE_BYTE:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Byte,b);
break;
case JAVA_SIGNATURE_CHAR:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Char,c);
break;
case JAVA_SIGNATURE_SHORT:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Short,s);
break;
case JAVA_SIGNATURE_INT:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Int,i);
break;
case JAVA_SIGNATURE_BOOLEAN:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Boolean,z);
break;
case JAVA_SIGNATURE_LONG:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Long,j);
break;
case JAVA_SIGNATURE_FLOAT:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Float,f);
break;
case JAVA_SIGNATURE_DOUBLE:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Double,d);
break;
case JAVA_SIGNATURE_CLASS:
case JAVA_SIGNATURE_ARRAY:
java_value.l = (*jEnv)->GetObjectArrayElement(jEnv, java_array, index);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
jsj_ReportJavaError(cx, jEnv, "Error reading Java object array");
return JS_FALSE;
}
break;
#undef GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY
default:
PR_ASSERT(0); /* Unknown java type signature */
return JS_FALSE;
}
return jsj_ConvertJavaValueToJSValue(cx, jEnv, array_component_signature, &java_value, vp);
}
JSBool
jsj_SetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array, jsize index,
JavaSignature *array_component_signature,
jsval js_val)
{
int dummy_cost;
jvalue java_value;
JavaSignatureChar component_type;
JSBool is_local_ref;
if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, array_component_signature,
&dummy_cost, &java_value, &is_local_ref))
return JS_FALSE;
#define SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Type,member) \
(*jEnv)->Set##Type##ArrayRegion(jEnv, java_array, index, 1, \
&java_value.member); \
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
jsj_ReportJavaError(cx, jEnv, "Error assigning to element of " \
"Java primitive array"); \
return JS_FALSE; \
}
component_type = array_component_signature->type;
switch(component_type) {
case JAVA_SIGNATURE_BYTE:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Byte,b);
break;
case JAVA_SIGNATURE_CHAR:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Char,c);
break;
case JAVA_SIGNATURE_SHORT:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Short,s);
break;
case JAVA_SIGNATURE_INT:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Int,i);
break;
case JAVA_SIGNATURE_BOOLEAN:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Boolean,z);
break;
case JAVA_SIGNATURE_LONG:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Long,j);
break;
case JAVA_SIGNATURE_FLOAT:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Float,f);
break;
case JAVA_SIGNATURE_DOUBLE:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Double,d);
break;
case JAVA_SIGNATURE_CLASS:
case JAVA_SIGNATURE_ARRAY:
(*jEnv)->SetObjectArrayElement(jEnv, java_array, index, java_value.l);
if (is_local_ref) \
(*jEnv)->DeleteLocalRef(jEnv, java_value.l);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
jsj_ReportJavaError(cx, jEnv, "Error assigning to Java object array");
return JS_FALSE;
}
break;
#undef SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY
default:
PR_ASSERT(0); /* Unknown java type signature */
return JS_FALSE;
}
return JS_TRUE;
}

Просмотреть файл

@ -1,606 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the code that constructs and manipulates JavaClassDescriptor
* structs, which are the native wrappers for Java classes.
* JavaClassDescriptors are used to describe the signatures of methods and
* fields. There is a JavaClassDescriptor associated with the reflection of
* each Java Object.
*/
#include <stdlib.h>
#include <string.h>
#include "prtypes.h"
#include "prprintf.h"
#include "prassert.h"
#include "jsj_private.h" /* LiveConnect internals */
#include "jsj_hash.h" /* Hash tables */
/* A one-to-one mapping between all referenced java.lang.Class objects and
their corresponding JavaClassDescriptor objects */
static JSJHashTable *java_class_reflections;
/*
* Given a JVM handle to a java.lang.Class object, malloc a C-string
* containing the UTF8 encoding of the fully qualified name of the class.
* It's the caller's responsibility to free the returned string.
*
* If an error occurs, NULL is returned and the error reporter called.
*/
const char *
jsj_GetJavaClassName(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
jstring java_class_name_jstr;
const char *java_class_name;
/* Get java.lang.String object containing class name */
java_class_name_jstr =
(*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getName);
if (!java_class_name_jstr)
goto error;
/* Convert to UTF8 encoding and copy */
java_class_name = jsj_DupJavaStringUTF(cx, jEnv, java_class_name_jstr);
if (!java_class_name)
return NULL;
return java_class_name;
error:
jsj_UnexpectedJavaError(cx, jEnv, "Can't get Java class name using"
"java.lang.Class.getName()");
return NULL;
}
/*
* Convert in-place a string of the form "java.lang.String" into "java/lang/String".
* Though the former style is conventionally used by Java programmers, the latter is
* what the JNI functions require.
*/
void
jsj_MakeJNIClassname(char * class_name)
{
char * c;
for (c = class_name; *c; c++)
if (*c == '.')
*c = '/';
}
/*
* Classify an instance of java.lang.Class as either one of the primitive
* types, e.g. int, char, etc., as an array type or as a non-array object type
* (subclass of java.lang.Object) by returning the appropriate enum member.
*
*/
static JavaSignatureChar
get_signature_type(JSContext *cx, JavaClassDescriptor *class_descriptor)
{
JavaSignatureChar type;
const char *java_class_name;
/* Get UTF8 encoding of class name */
java_class_name = class_descriptor->name;
PR_ASSERT(java_class_name);
if (!java_class_name)
return JAVA_SIGNATURE_UNKNOWN;
if (!strcmp(java_class_name, "byte"))
type = JAVA_SIGNATURE_BYTE;
else if (!strcmp(java_class_name, "char"))
type = JAVA_SIGNATURE_CHAR;
else if (!strcmp(java_class_name, "float"))
type = JAVA_SIGNATURE_FLOAT;
else if (!strcmp(java_class_name, "double"))
type = JAVA_SIGNATURE_DOUBLE;
else if (!strcmp(java_class_name, "int"))
type = JAVA_SIGNATURE_INT;
else if (!strcmp(java_class_name, "long"))
type = JAVA_SIGNATURE_LONG;
else if (!strcmp(java_class_name, "short"))
type = JAVA_SIGNATURE_SHORT;
else if (!strcmp(java_class_name, "boolean"))
type = JAVA_SIGNATURE_BOOLEAN;
else if (!strcmp(java_class_name, "void"))
type = JAVA_SIGNATURE_VOID;
else
/* Well, I guess it's a Java class, then. */
type = JAVA_SIGNATURE_CLASS;
return type;
}
static JSBool
is_java_array_class(JNIEnv *jEnv, jclass java_class)
{
return (*jEnv)->CallBooleanMethod(jEnv, java_class, jlClass_isArray);
}
/*
* Return the class of a Java array's component type. This is not the same
* as the array's element type. For example, the component type of an array
* of type SomeType[][][] is SomeType[][], but its element type is SomeType.
*
* If an error occurs, NULL is returned and an error reported.
*/
static jclass
get_java_array_component_class(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
jclass result;
result = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getComponentType);
if (!result) {
jsj_UnexpectedJavaError(cx, jEnv,
"Can't get Java array component class using "
"java.lang.Class.getComponentType()");
return NULL;
}
return result;
}
/*
* Given a Java class, fill in the signature structure that describes the class.
* If an error occurs, JS_FALSE is returned and the error reporter called.
*/
static JSBool
compute_java_class_signature(JSContext *cx, JNIEnv *jEnv, JavaSignature *signature)
{
jclass java_class = signature->java_class;
if (is_java_array_class(jEnv, java_class)) {
jclass component_class;
signature->type = JAVA_SIGNATURE_ARRAY;
component_class = get_java_array_component_class(cx, jEnv, java_class);
if (!component_class)
return JS_FALSE;
signature->array_component_signature =
jsj_GetJavaClassDescriptor(cx, jEnv, component_class);
if (!signature->array_component_signature)
return JS_FALSE;
} else {
signature->type = get_signature_type(cx, signature);
}
return JS_TRUE;
}
/*
* Convert a JavaSignature object into a string format as used by
* the JNI functions, e.g. java.lang.Object ==> "Ljava/lang/Object;"
* The caller is responsible for freeing the resulting string.
*
* If an error is encountered, NULL is returned and an error reported.
*/
const char *
jsj_ConvertJavaSignatureToString(JSContext *cx, JavaSignature *signature)
{
char *sig;
if (signature->type == JAVA_SIGNATURE_CLASS) {
/* A non-array object class */
sig = PR_smprintf("L%s;", signature->name);
if (sig)
jsj_MakeJNIClassname(sig);
} else if (signature->type == JAVA_SIGNATURE_ARRAY) {
/* An array class */
const char *component_signature_string;
component_signature_string =
jsj_ConvertJavaSignatureToString(cx, signature->array_component_signature);
if (!component_signature_string)
return NULL;
sig = PR_smprintf("[%s", component_signature_string);
JS_free(cx, (char*)component_signature_string);
} else {
/* A primitive class */
sig = PR_smprintf("%c", (char)signature->type);
}
if (!sig) {
JS_ReportOutOfMemory(cx);
return NULL;
}
return sig;
}
/*
* Convert a JavaSignature object into a human-readable string format as seen
* in Java source files, e.g. "byte", or "int[][]" or "java.lang.String".
* The caller is responsible for freeing the resulting string.
*
* If an error is encountered, NULL is returned and an error reported.
*/
const char *
jsj_ConvertJavaSignatureToHRString(JSContext *cx,
JavaSignature *signature)
{
char *sig;
JavaSignature *acs;
if (signature->type == JAVA_SIGNATURE_ARRAY) {
/* An array class */
const char *component_signature_string;
acs = signature->array_component_signature;
component_signature_string =
jsj_ConvertJavaSignatureToHRString(cx, acs);
if (!component_signature_string)
return NULL;
sig = PR_smprintf("%s[]", component_signature_string);
JS_free(cx, (char*)component_signature_string);
} else {
/* A primitive class or a non-array object class */
sig = JS_strdup(cx, signature->name);
}
if (!sig) {
JS_ReportOutOfMemory(cx);
return NULL;
}
return sig;
}
static void
destroy_java_member_descriptor(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
{
JavaMethodSpec *method, *next_method;
if (member_descriptor->field)
jsj_DestroyFieldSpec(cx, jEnv, member_descriptor->field);
method = member_descriptor->methods;
while (method) {
next_method = method->next;
jsj_DestroyMethodSpec(cx, jEnv, method);
method = next_method;
}
if (member_descriptor->invoke_func_obj)
JS_RemoveRoot(cx, &member_descriptor->invoke_func_obj);
}
static void
destroy_class_member_descriptors(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
{
JavaMemberDescriptor *next_member;
while (member_descriptor) {
next_member = member_descriptor->next;
destroy_java_member_descriptor(cx, jEnv, member_descriptor);
member_descriptor = next_member;
}
}
static void
destroy_class_descriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
{
JS_FREE_IF(cx, (char *)class_descriptor->name);
if (class_descriptor->java_class) {
(*jEnv)->DeleteGlobalRef(jEnv, class_descriptor->java_class);
JSJ_HashTableRemove(java_class_reflections,
class_descriptor->java_class, (void*)jEnv);
}
if (class_descriptor->array_component_signature)
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor->array_component_signature);
destroy_class_member_descriptors(cx, jEnv, class_descriptor->instance_members);
destroy_class_member_descriptors(cx, jEnv, class_descriptor->static_members);
destroy_class_member_descriptors(cx, jEnv, class_descriptor->constructors);
JS_free(cx, class_descriptor);
}
static JavaClassDescriptor *
new_class_descriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
JavaClassDescriptor *class_descriptor;
class_descriptor = (JavaClassDescriptor *)JS_malloc(cx, sizeof(JavaClassDescriptor));
if (!class_descriptor)
return NULL;
memset(class_descriptor, 0, sizeof(JavaClassDescriptor));
class_descriptor->name = jsj_GetJavaClassName(cx, jEnv, java_class);
if (!class_descriptor->name)
goto error;
java_class = (*jEnv)->NewGlobalRef(jEnv, java_class);
if (!java_class) {
jsj_ReportJavaError(cx, jEnv, "Unable to reference Java class");
goto error;
}
class_descriptor->java_class = java_class;
if (!compute_java_class_signature(cx, jEnv, class_descriptor))
goto error;
class_descriptor->modifiers =
(*jEnv)->CallIntMethod(jEnv, java_class, jlClass_getModifiers);
class_descriptor->ref_count = 1;
if (!JSJ_HashTableAdd(java_class_reflections, java_class, class_descriptor,
(void*)jEnv))
goto error;
return class_descriptor;
error:
destroy_class_descriptor(cx, jEnv, class_descriptor);
return NULL;
}
/* Trivial helper for jsj_DiscardJavaClassReflections(), below */
static PRIntn
enumerate_remove_java_class(JSJHashEntry *he, PRIntn i, void *arg)
{
JNIEnv *jEnv = (JNIEnv*)arg;
jclass java_class;
JavaClassDescriptor *class_descriptor;
class_descriptor = (JavaClassDescriptor*)he->value;
java_class = class_descriptor->java_class;
(*jEnv)->DeleteGlobalRef(jEnv, java_class);
class_descriptor->java_class = NULL;
return HT_ENUMERATE_REMOVE;
}
/* This shutdown routine discards all JNI references to Java objects
that have been reflected into JS, even if there are still references
to them from JS. */
void
jsj_DiscardJavaClassReflections(JNIEnv *jEnv)
{
JSJ_HashTableEnumerateEntries(java_class_reflections,
enumerate_remove_java_class,
(void*)jEnv);
}
extern JavaClassDescriptor *
jsj_GetJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
JavaClassDescriptor *class_descriptor;
class_descriptor = JSJ_HashTableLookup(java_class_reflections,
(const void *)java_class,
(void*)jEnv);
if (!class_descriptor)
return new_class_descriptor(cx, jEnv, java_class);
PR_ASSERT(class_descriptor->ref_count > 0);
class_descriptor->ref_count++;
return class_descriptor;
}
void
jsj_ReleaseJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
{
if (!--class_descriptor->ref_count)
destroy_class_descriptor(cx, jEnv, class_descriptor);
}
static JSBool
reflect_java_methods_and_fields(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
JSBool reflect_statics_only)
{
JavaMemberDescriptor *member_descriptor;
if (reflect_statics_only)
class_descriptor->static_members_reflected = JS_TRUE;
else
class_descriptor->instance_members_reflected = JS_TRUE;
if (!jsj_ReflectJavaMethods(cx, jEnv, class_descriptor, reflect_statics_only))
return JS_FALSE;
if (!jsj_ReflectJavaFields(cx, jEnv, class_descriptor, reflect_statics_only))
return JS_FALSE;
if (reflect_statics_only) {
member_descriptor = class_descriptor->static_members;
while (member_descriptor) {
class_descriptor->num_static_members++;
member_descriptor = member_descriptor->next;
}
} else {
member_descriptor = class_descriptor->instance_members;
while (member_descriptor) {
class_descriptor->num_instance_members++;
member_descriptor = member_descriptor->next;
}
}
return JS_TRUE;
}
JavaMemberDescriptor *
jsj_GetClassStaticMembers(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor)
{
if (!class_descriptor->static_members_reflected)
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
return class_descriptor->static_members;
}
JavaMemberDescriptor *
jsj_GetClassInstanceMembers(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor)
{
if (!class_descriptor->instance_members_reflected)
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_FALSE);
return class_descriptor->instance_members;
}
JavaMemberDescriptor *
jsj_LookupJavaStaticMemberDescriptorById(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jsid id)
{
JavaMemberDescriptor *member_descriptor;
member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
while (member_descriptor) {
if (id == member_descriptor->id)
return member_descriptor;
member_descriptor = member_descriptor->next;
}
return NULL;
}
JavaMemberDescriptor *
jsj_GetJavaStaticMemberDescriptor(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jstring member_name_jstr)
{
JavaMemberDescriptor *member_descriptor;
jsid id;
if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
return NULL;
member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
if (member_descriptor)
return member_descriptor;
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
if (!member_descriptor)
return NULL;
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
if (!member_descriptor->name) {
JS_free(cx, member_descriptor);
return NULL;
}
member_descriptor->id = id;
member_descriptor->next = class_descriptor->static_members;
class_descriptor->static_members = member_descriptor;
return member_descriptor;
}
JavaMemberDescriptor *
jsj_GetJavaClassConstructors(JSContext *cx,
JavaClassDescriptor *class_descriptor)
{
JavaMemberDescriptor *member_descriptor;
if (class_descriptor->constructors)
return class_descriptor->constructors;
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
if (!member_descriptor)
return NULL;
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
member_descriptor->name = JS_strdup(cx, "<init>");
if (!member_descriptor->name) {
JS_free(cx, member_descriptor);
return NULL;
}
class_descriptor->constructors = member_descriptor;
return member_descriptor;
}
JavaMemberDescriptor *
jsj_LookupJavaClassConstructors(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor)
{
if (!class_descriptor->static_members_reflected)
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
return class_descriptor->constructors;
}
JavaMemberDescriptor *
jsj_LookupJavaMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jsid id)
{
JavaMemberDescriptor *member_descriptor;
member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
while (member_descriptor) {
if (id == member_descriptor->id)
return member_descriptor;
member_descriptor = member_descriptor->next;
}
return NULL;
}
JavaMemberDescriptor *
jsj_GetJavaMemberDescriptor(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jstring member_name_jstr)
{
JavaMemberDescriptor *member_descriptor;
jsid id;
if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
return NULL;
member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
if (member_descriptor)
return member_descriptor;
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
if (!member_descriptor)
return NULL;
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
if (!member_descriptor->name) {
JS_free(cx, member_descriptor);
return NULL;
}
member_descriptor->id = id;
member_descriptor->next = class_descriptor->instance_members;
class_descriptor->instance_members = member_descriptor;
return member_descriptor;
}
JSBool
jsj_InitJavaClassReflectionsTable()
{
java_class_reflections =
JSJ_NewHashTable(64, jsj_HashJavaObject, jsj_JavaObjectComparator,
NULL, NULL, NULL);
if (!java_class_reflections)
return JS_FALSE;
return JS_TRUE;
}

Просмотреть файл

@ -1,20 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
@ -26,11 +11,8 @@
#include <stdlib.h>
#include <string.h>
#include "prtypes.h"
#include "prprintf.h"
#include "prassert.h"
#include "jsj_private.h" /* LiveConnect internals */
#include "jscntxt.h" /* for error reporting */
/* Floating-point double utilities, stolen from jsnum.h */
#ifdef IS_LITTLE_ENDIAN
@ -59,9 +41,7 @@ convert_js_obj_to_JSObject_wrapper(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj
{
if (!njJSObject) {
if (java_value)
JS_ReportError(cx, "Couldn't convert JavaScript object to an "
"instance of netscape.javascript.JSObject "
"because that class could not be loaded.");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_CANT_LOAD_JSOBJECT);
return JS_FALSE;
}
@ -160,27 +140,31 @@ jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignatu
}
/* Check if target type is netscape.javascript.JSObject wrapper class */
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value))
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) {
if (*java_value)
*is_local_refp = JS_TRUE;
return JS_TRUE;
}
/* Fall through, to attempt conversion to a Java string */
} else if (JS_TypeOfValue(cx, v) == JSTYPE_FUNCTION) {
/* JS functions can be wrapped as a netscape.javascript.JSObject */
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value))
return JS_TRUE;
/* That didn't work, so fall through, to attempt conversion to
a java.lang.String ... */
/* Check for a Java object wrapped inside a JS object */
} else if (JS_InstanceOf(cx, js_obj, &JavaMember_class, 0)) {
if (!JS_ConvertValue(cx, v, JSTYPE_OBJECT, &v))
return JS_FALSE;
return jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost,
java_value, is_local_refp);
} else {
/* Otherwise, see if the target type is the netscape.javascript.JSObject
wrapper class or one of its subclasses, in which case a
reference is passed to the original JS object by wrapping it
inside an instance of netscape.javascript.JSObject */
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value))
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) {
if (*java_value)
*is_local_refp = JS_TRUE;
return JS_TRUE;
}
/* Fall through, to attempt conversion to a Java string */
}
@ -235,7 +219,9 @@ jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignatu
/* If no other conversion is possible, see if the target type is java.lang.String */
if ((*jEnv)->IsAssignableFrom(jEnv, jlString, target_java_class)) {
#ifdef LIVECONNECT_IMPROVEMENTS
JSBool is_string = JSVAL_IS_STRING(v);
#endif
/* Convert to JS string, if necessary, and then to a Java Unicode string */
jsstr = JS_ValueToString(cx, v);
@ -260,9 +246,21 @@ conversion_error:
return JS_FALSE;
}
/* Valid ranges for Java numeric types */
#define jbyte_MAX_VALUE 127.0
#define jbyte_MIN_VALUE -128.0
#define jchar_MAX_VALUE 65535.0
#define jchar_MIN_VALUE 0.0
#define jshort_MAX_VALUE 32767.0
#define jshort_MIN_VALUE -32768.0
#define jint_MAX_VALUE 2147483647.0
#define jint_MIN_VALUE -2147483648.0
#define jlong_MAX_VALUE 9223372036854775807.0
#define jlong_MIN_VALUE -9223372036854775808.0
/* Utility macro for jsj_ConvertJSValueToJavaValue(), below */
#define JSVAL_TO_INTEGRAL_JVALUE(type_name, member_name, member_type, jsval, java_value) \
if (!JSVAL_IS_NUMBER(v)) { \
if (!JSVAL_IS_NUMBER(v)) { \
if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v)) \
goto conversion_error; \
(*cost)++; \
@ -277,12 +275,20 @@ if (!JSVAL_IS_NUMBER(v)) { \
/* Check to see if the jsval's magnitude is too large to be \
representable in the target java type */ \
if (member_name != ival) \
goto conversion_error; \
goto numeric_conversion_error; \
} else { \
jdouble dval = *JSVAL_TO_DOUBLE(v); \
\
/* NaN becomes zero when converted to integral value */ \
if (JSDOUBLE_IS_NaN(dval)) \
member_name = 0; \
else \
\
/* Unrepresentably large numbers, including infinities, */ \
/* cause an error. */ \
else if ((dval > member_type ## _MAX_VALUE) || \
(dval < member_type ## _MIN_VALUE)) { \
goto numeric_conversion_error; \
} else \
member_name = (member_type) dval; \
\
/* Don't allow a non-integral number to be converted \
@ -297,7 +303,7 @@ if (!JSVAL_IS_NUMBER(v)) { \
#if XP_MAC
// on MRJ jlong is typedef'd to wide, which is a struct.
/* on MRJ jlong is typedef'd to wide, which is a struct. */
#include <Math64.h>
static jsint jlong_to_jsint(jlong lvalue)
@ -309,7 +315,8 @@ static jsint jlong_to_jsint(jlong lvalue)
static jlong jsint_to_jlong(jsint ivalue)
{
SInt64 val = S64Set(ivalue);
return SInt64ToWide(val);
wide wval =SInt64ToWide(val);
return *(jlong*)&wval;
}
static jdouble jlong_to_jdouble(jlong lvalue)
@ -321,7 +328,8 @@ static jdouble jlong_to_jdouble(jlong lvalue)
static jlong jdouble_to_jlong(jdouble dvalue)
{
SInt64 val = LongDoubleToSInt64(dvalue);
return SInt64ToWide(val);
wide wval = SInt64ToWide(val);
return *(jlong*)&wval;
}
/* Mac utility macro for jsj_ConvertJSValueToJavaValue(), below */
@ -340,9 +348,17 @@ if (!JSVAL_IS_NUMBER(jsvalue)) { \
\
} else { \
jdouble dval = *JSVAL_TO_DOUBLE(jsvalue); \
\
/* NaN becomes zero when converted to integral value */ \
if (JSDOUBLE_IS_NaN(dval)) \
member_name = jsint_to_jlong(0); \
else \
\
/* Unrepresentably large numbers, including infinities, */ \
/* cause an error. */ \
else if ((dval > member_type ## _MAX_VALUE) || \
(dval < member_type ## _MIN_VALUE)) { \
goto numeric_conversion_error; \
} else \
member_name = jdouble_to_jlong(dval); \
\
/* Don't allow a non-integral number to be converted \
@ -379,6 +395,7 @@ jsj_ConvertJSValueToJavaValue(JSContext *cx, JNIEnv *jEnv, jsval v,
int *cost, jvalue *java_value, JSBool *is_local_refp)
{
JavaSignatureChar type;
JSBool success = JS_FALSE;
/* Initialize to default case, in which no new Java object is
synthesized to perform the conversion and, therefore, no JNI local
@ -468,6 +485,10 @@ jsj_ConvertJSValueToJavaValue(JSContext *cx, JNIEnv *jEnv, jsval v,
/* Success */
return JS_TRUE;
numeric_conversion_error:
success = JS_TRUE;
/* Fall through ... */
conversion_error:
if (java_value) {
@ -481,11 +502,11 @@ conversion_error:
if (!jsval_string)
jsval_string = "";
JS_ReportError(cx, "Unable to convert JavaScript value %s to "
"Java value of type %s",
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_CANT_CONVERT_JS,
jsval_string, signature->name);
return JS_FALSE;
}
return JS_FALSE;
return success;
}
/*
@ -511,7 +532,7 @@ jsj_ConvertJavaStringToJSString(JSContext *cx, JNIEnv *jEnv, jstring java_str)
js_str = NULL;
/* Unlike JS_NewString(), the string data passed into JS_NewUCString() is
/* The string data passed into JS_NewUCString() is
not copied, so make a copy of the Unicode character vector. */
num_bytes = ucs2_str_len * sizeof(jchar);
copy_ucs2_str = (jchar*)JS_malloc(cx, num_bytes);
@ -585,27 +606,23 @@ jsj_ConvertJavaObjectToJSString(JSContext *cx,
*/
JSBool
jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jobject java_obj, jsval *vp)
{
jdouble d;
jmethodID doubleValue;
jclass java_class;
#ifndef SUN_VM_IS_NOT_GARBAGE
/* Late breaking news: calling GetMethodID() on an object that doesn't
contain the given method may cause the Sun VM to crash. So we only
call the method on instances of java.lang.Double */
JSBool is_Double;
/* Make sure that we have a java.lang.Double */
is_Double = (*jEnv)->IsInstanceOf(jEnv, java_obj, jlDouble);
if (!is_Double)
return JS_FALSE;
doubleValue = jlDouble_doubleValue;
#else
doubleValue = (*jEnv)->GetMethodID(jEnv, java_obj, "doubleValue", "()D");
if (!doubleValue)
return JS_FALSE;
#endif
java_class = class_descriptor->java_class;
doubleValue = (*jEnv)->GetMethodID(jEnv, java_class, "doubleValue", "()D");
if (!doubleValue) {
/* There is no doubleValue() method for the object. Try toString()
instead and the JS engine will attempt to convert the result to
a number. */
(*jEnv)->ExceptionClear(jEnv);
return jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor,
java_obj, vp);
}
d = (*jEnv)->CallDoubleMethod(jEnv, java_obj, doubleValue);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
@ -626,28 +643,28 @@ jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
*/
extern JSBool
jsj_ConvertJavaObjectToJSBoolean(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jobject java_obj, jsval *vp)
{
jboolean b;
jmethodID booleanValue;
jclass java_class;
#ifndef SUN_VM_IS_NOT_GARBAGE
/* Late breaking news: calling GetMethodID() on an object that doesn't
contain the given method may cause the Sun VM to crash. So we only
call the method on instances of java.lang.Boolean */
JSBool is_Boolean;
/* Make sure that we have a java.lang.Boolean */
is_Boolean = (*jEnv)->IsInstanceOf(jEnv, java_obj, jlBoolean);
if (!is_Boolean)
return JS_FALSE;
booleanValue = jlBoolean_booleanValue;
#else
/* Null converts to false. */
if (!java_obj) {
*vp = JSVAL_FALSE;
return JS_TRUE;
}
java_class = class_descriptor->java_class;
booleanValue = (*jEnv)->GetMethodID(jEnv, java_obj, "booleanValue", "()Z");
if (!booleanValue)
return JS_FALSE;
#endif
/* Non-null Java object does not have a booleanValue() method, so
it converts to true. */
if (!booleanValue) {
(*jEnv)->ExceptionClear(jEnv);
*vp = JSVAL_TRUE;
return JS_TRUE;
}
b = (*jEnv)->CallBooleanMethod(jEnv, java_obj, booleanValue);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
@ -683,7 +700,11 @@ jsj_ConvertJavaObjectToJSValue(JSContext *cx, JNIEnv *jEnv,
* it to obtain the original JS object.
*/
if (njJSObject && (*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) {
#ifdef PRESERVE_JSOBJECT_IDENTITY
js_obj = (JSObject *)((*jEnv)->GetIntField(jEnv, java_obj, njJSObject_internal));
#else
js_obj = jsj_UnwrapJSObjectWrapper(jEnv, java_obj);
#endif
PR_ASSERT(js_obj);
if (!js_obj)
return JS_FALSE;

Просмотреть файл

@ -1,386 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the code used to reflect Java fields as properties of
* JavaObject objects and the code to access those fields.
*
*/
#include <stdlib.h>
#include "prtypes.h"
#include "prprintf.h"
#include "prassert.h"
#include "jsj_private.h" /* LiveConnect internals */
/*
* Add a single field, described by java_field, to the JavaMemberDescriptor
* named by field_name within the given JavaClassDescriptor.
*
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
*/
static JSBool
add_java_field_to_class_descriptor(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jstring field_name_jstr,
jobject java_field, /* a java.lang.reflect.Field */
jint modifiers)
{
jclass fieldType;
jfieldID fieldID;
jclass java_class;
JSBool is_static_field;
JavaMemberDescriptor *member_descriptor = NULL;
const char *sig_cstr = NULL;
const char *field_name = NULL;
JavaSignature *signature = NULL;
JavaFieldSpec *field_spec = NULL;
is_static_field = modifiers & ACC_STATIC;
if (is_static_field) {
member_descriptor = jsj_GetJavaStaticMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
} else {
member_descriptor = jsj_GetJavaMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
}
if (!member_descriptor)
goto error;
field_spec = (JavaFieldSpec*)JS_malloc(cx, sizeof(JavaFieldSpec));
if (!field_spec)
goto error;
field_spec->modifiers = modifiers;
/* Get the Java class corresponding to the type of the field */
fieldType = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getType);
if (!fieldType) {
jsj_UnexpectedJavaError(cx, jEnv,
"Unable to determine type of field using"
" java.lang.reflect.Field.getType()");
goto error;
}
signature = jsj_GetJavaClassDescriptor(cx, jEnv, fieldType);
if (!signature)
goto error;
field_spec->signature = signature;
field_name = jsj_DupJavaStringUTF(cx, jEnv, field_name_jstr);
if (!field_name)
goto error;
field_spec->name = field_name;
/* Compute the JNI-style (string-based) signature of the field type */
sig_cstr = jsj_ConvertJavaSignatureToString(cx, signature);
if (!sig_cstr)
goto error;
/* Compute the JNI fieldID and cache it for quick field access */
java_class = class_descriptor->java_class;
if (is_static_field)
fieldID = (*jEnv)->GetStaticFieldID(jEnv, java_class, field_name, sig_cstr);
else
fieldID = (*jEnv)->GetFieldID(jEnv, java_class, field_name, sig_cstr);
if (!fieldID) {
jsj_UnexpectedJavaError(cx, jEnv,
"Can't get Java field ID for class %s, field %s (sig=%s)",
class_descriptor->name, field_name, sig_cstr);
goto error;
}
field_spec->fieldID = fieldID;
JS_free(cx, (char*)sig_cstr);
member_descriptor->field = field_spec;
/* Success */
return JS_TRUE;
error:
if (field_spec) {
JS_FREE_IF(cx, (char*)field_spec->name);
JS_free(cx, field_spec);
}
JS_FREE_IF(cx, (char*)sig_cstr);
if (signature)
jsj_ReleaseJavaClassDescriptor(cx, jEnv, signature);
return JS_FALSE;
}
/*
* Free up a JavaFieldSpec and all its resources.
*/
void
jsj_DestroyFieldSpec(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field)
{
JS_FREE_IF(cx, (char*)field->name);
jsj_ReleaseJavaClassDescriptor(cx, jEnv, field->signature);
JS_free(cx, field);
}
/*
* Add a JavaMemberDescriptor to the collection of members in class_descriptor
* for every public field of the identified Java class. (A separate collection
* is kept in class_descriptor for static and instance members.)
* If reflect_only_static_fields is set, instance fields are not reflected. If
* it isn't set, only instance fields are reflected and static fields are not
* reflected.
*
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
*/
JSBool
jsj_ReflectJavaFields(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor,
JSBool reflect_only_static_fields)
{
int i;
JSBool ok;
jint modifiers;
jobject java_field;
jstring field_name_jstr;
jarray joFieldArray;
jsize num_fields;
jclass java_class;
/* Get a java array of java.lang.reflect.Field objects, by calling
java.lang.Class.getFields(). */
java_class = class_descriptor->java_class;
joFieldArray = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getFields);
if (!joFieldArray) {
jsj_UnexpectedJavaError(cx, jEnv,
"Can't determine Java object's fields "
"using java.lang.Class.getFields()");
return JS_FALSE;
}
/* Iterate over the class fields */
num_fields = (*jEnv)->GetArrayLength(jEnv, joFieldArray);
for (i = 0; i < num_fields; i++) {
/* Get the i'th reflected field */
java_field = (*jEnv)->GetObjectArrayElement(jEnv, joFieldArray, i);
if (!java_field) {
jsj_UnexpectedJavaError(cx, jEnv, "Can't access a Field[] array");
return JS_FALSE;
}
/* Get the field modifiers, e.g. static, public, private, etc. */
modifiers = (*jEnv)->CallIntMethod(jEnv, java_field, jlrField_getModifiers);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
jsj_UnexpectedJavaError(cx, jEnv,
"Can't access a Field's modifiers using"
"java.lang.reflect.Field.getModifiers()");
return JS_FALSE;
}
/* Don't allow access to private or protected Java fields. */
if (!(modifiers & ACC_PUBLIC))
continue;
/* Reflect all instance fields or all static fields, but not both */
if (reflect_only_static_fields != ((modifiers & ACC_STATIC) != 0))
continue;
/* Determine the unqualified name of the field */
field_name_jstr = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getName);
if (!field_name_jstr) {
jsj_UnexpectedJavaError(cx, jEnv,
"Can't obtain a Field's name"
"java.lang.reflect.Field.getName()");
return JS_FALSE;
}
/* Add a JavaFieldSpec object to the JavaClassDescriptor */
ok = add_java_field_to_class_descriptor(cx, jEnv, class_descriptor, field_name_jstr,
java_field, modifiers);
if (!ok)
return JS_FALSE;
}
/* Success */
return JS_TRUE;
}
/*
* Read the value of a Java field and return it as a JavaScript value.
* If the field is static, then java_obj is a Java class, otherwise
* it's a Java instance object.
*
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
*/
JSBool
jsj_GetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
jobject java_obj, jsval *vp)
{
JSBool is_static_field;
jvalue java_value;
JavaSignature *signature;
JavaSignatureChar field_type;
jfieldID fieldID = field_spec->fieldID;
is_static_field = field_spec->modifiers & ACC_STATIC;
#define GET_JAVA_FIELD(Type,member) \
PR_BEGIN_MACRO \
if (is_static_field) \
java_value.member = \
(*jEnv)->GetStatic##Type##Field(jEnv, java_obj, fieldID); \
else \
java_value.member = \
(*jEnv)->Get##Type##Field(jEnv, java_obj, fieldID); \
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
jsj_ReportJavaError(cx, jEnv, "Error reading Java field"); \
return JS_FALSE; \
} \
PR_END_MACRO
signature = field_spec->signature;
field_type = signature->type;
switch(field_type) {
case JAVA_SIGNATURE_BYTE:
GET_JAVA_FIELD(Byte,b);
break;
case JAVA_SIGNATURE_CHAR:
GET_JAVA_FIELD(Char,c);
break;
case JAVA_SIGNATURE_SHORT:
GET_JAVA_FIELD(Short,s);
break;
case JAVA_SIGNATURE_INT:
GET_JAVA_FIELD(Int,i);
break;
case JAVA_SIGNATURE_BOOLEAN:
GET_JAVA_FIELD(Boolean,z);
break;
case JAVA_SIGNATURE_LONG:
GET_JAVA_FIELD(Long,j);
break;
case JAVA_SIGNATURE_FLOAT:
GET_JAVA_FIELD(Float,f);
break;
case JAVA_SIGNATURE_DOUBLE:
GET_JAVA_FIELD(Double,d);
break;
case JAVA_SIGNATURE_CLASS:
case JAVA_SIGNATURE_ARRAY:
GET_JAVA_FIELD(Object,l);
break;
#undef GET_JAVA_FIELD
default:
PR_ASSERT(0); /* Unknown java type signature */
return JS_FALSE;
}
return jsj_ConvertJavaValueToJSValue(cx, jEnv, signature, &java_value, vp);
}
JSBool
jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
jclass java_obj, jsval js_val)
{
JSBool is_static_field, is_local_ref;
int dummy_cost;
jvalue java_value;
JavaSignature *signature;
JavaSignatureChar field_type;
jfieldID fieldID = field_spec->fieldID;
is_static_field = field_spec->modifiers & ACC_STATIC;
#define SET_JAVA_FIELD(Type,member) \
PR_BEGIN_MACRO \
if (is_static_field) { \
(*jEnv)->SetStatic##Type##Field(jEnv, java_obj, fieldID, \
java_value.member); \
} else { \
(*jEnv)->Set##Type##Field(jEnv, java_obj, fieldID,java_value.member);\
} \
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
jsj_ReportJavaError(cx, jEnv, "Error assigning to Java field"); \
return JS_FALSE; \
} \
PR_END_MACRO
signature = field_spec->signature;
if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, signature, &dummy_cost,
&java_value, &is_local_ref))
return JS_FALSE;
field_type = signature->type;
switch(field_type) {
case JAVA_SIGNATURE_BYTE:
SET_JAVA_FIELD(Byte,b);
break;
case JAVA_SIGNATURE_CHAR:
SET_JAVA_FIELD(Char,c);
break;
case JAVA_SIGNATURE_SHORT:
SET_JAVA_FIELD(Short,s);
break;
case JAVA_SIGNATURE_INT:
SET_JAVA_FIELD(Int,i);
break;
case JAVA_SIGNATURE_BOOLEAN:
SET_JAVA_FIELD(Boolean,z);
break;
case JAVA_SIGNATURE_LONG:
SET_JAVA_FIELD(Long,j);
break;
case JAVA_SIGNATURE_FLOAT:
SET_JAVA_FIELD(Float,f);
break;
case JAVA_SIGNATURE_DOUBLE:
SET_JAVA_FIELD(Double,d);
break;
case JAVA_SIGNATURE_CLASS:
case JAVA_SIGNATURE_ARRAY:
SET_JAVA_FIELD(Object,l);
if (is_local_ref) \
(*jEnv)->DeleteLocalRef(jEnv, java_value.l);
break;
#undef SET_JAVA_FIELD
default:
PR_ASSERT(0); /* Unknown java type signature */
return JS_FALSE;
}
return JS_TRUE;
}

Просмотреть файл

@ -1,481 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This is a copy of the NSPR hash-table library, but it has been slightly
* modified to allow an additional argument to be passed into the hash
* key-comparision function. This is used to maintain thread-safety by
* passing in a JNIEnv pointer to the key-comparison function rather
* than storing it in a global. All types,function names, etc. have
* been renamed from their original NSPR names to protect the innocent.
*/
#include "jsj_hash.h"
#include "prtypes.h"
#include "prassert.h"
#include <stdlib.h>
#include <string.h>
/* Compute the number of buckets in ht */
#define NBUCKETS(ht) (1 << (JSJ_HASH_BITS - (ht)->shift))
/* The smallest table has 16 buckets */
#define MINBUCKETSLOG2 4
#define MINBUCKETS (1 << MINBUCKETSLOG2)
/* Compute the maximum entries given n buckets that we will tolerate, ~90% */
#define OVERLOADED(n) ((n) - ((n) >> 3))
/* Compute the number of entries below which we shrink the table by half */
#define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0)
/*
** Stubs for default hash allocator ops.
*/
static void *
DefaultAllocTable(void *pool, size_t size)
{
#if defined(XP_MAC)
#pragma unused (pool)
#endif
return malloc(size);
}
static void
DefaultFreeTable(void *pool, void *item)
{
#if defined(XP_MAC)
#pragma unused (pool)
#endif
free(item);
}
static JSJHashEntry *
DefaultAllocEntry(void *pool, const void *key)
{
#if defined(XP_MAC)
#pragma unused (pool,key)
#endif
return malloc(sizeof(JSJHashEntry));
}
static void
DefaultFreeEntry(void *pool, JSJHashEntry *he, PRUintn flag)
{
#if defined(XP_MAC)
#pragma unused (pool)
#endif
if (flag == HT_FREE_ENTRY)
free(he);
}
static JSJHashAllocOps defaultHashAllocOps = {
DefaultAllocTable, DefaultFreeTable,
DefaultAllocEntry, DefaultFreeEntry
};
PR_IMPLEMENT(JSJHashTable *)
JSJ_NewHashTable(PRUint32 n, JSJHashFunction keyHash,
JSJHashComparator keyCompare, JSJHashComparator valueCompare,
JSJHashAllocOps *allocOps, void *allocPriv)
{
JSJHashTable *ht;
PRUint32 nb;
if (n <= MINBUCKETS) {
n = MINBUCKETSLOG2;
} else {
n = PR_CeilingLog2(n);
if ((PRInt32)n < 0)
return 0;
}
if (!allocOps) allocOps = &defaultHashAllocOps;
ht = (*allocOps->allocTable)(allocPriv, sizeof *ht);
if (!ht)
return 0;
memset(ht, 0, sizeof *ht);
ht->shift = JSJ_HASH_BITS - n;
n = 1 << n;
#if defined(XP_PC) && !defined(_WIN32)
if (n > 16000) {
(*allocOps->freeTable)(allocPriv, ht);
return 0;
}
#endif /* WIN16 */
nb = n * sizeof(JSJHashEntry *);
ht->buckets = (*allocOps->allocTable)(allocPriv, nb);
if (!ht->buckets) {
(*allocOps->freeTable)(allocPriv, ht);
return 0;
}
memset(ht->buckets, 0, nb);
ht->keyHash = keyHash;
ht->keyCompare = keyCompare;
ht->valueCompare = valueCompare;
ht->allocOps = allocOps;
ht->allocPriv = allocPriv;
return ht;
}
PR_IMPLEMENT(void)
JSJ_HashTableDestroy(JSJHashTable *ht)
{
PRUint32 i, n;
JSJHashEntry *he, *next;
JSJHashAllocOps *allocOps = ht->allocOps;
void *allocPriv = ht->allocPriv;
n = NBUCKETS(ht);
for (i = 0; i < n; i++) {
for (he = ht->buckets[i]; he; he = next) {
next = he->next;
(*allocOps->freeEntry)(allocPriv, he, HT_FREE_ENTRY);
}
}
#ifdef DEBUG
memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]);
#endif
(*allocOps->freeTable)(allocPriv, ht->buckets);
#ifdef DEBUG
memset(ht, 0xDB, sizeof *ht);
#endif
(*allocOps->freeTable)(allocPriv, ht);
}
/*
** Multiplicative hash, from Knuth 6.4.
*/
#define GOLDEN_RATIO 0x9E3779B9U
PR_IMPLEMENT(JSJHashEntry **)
JSJ_HashTableRawLookup(JSJHashTable *ht, JSJHashNumber keyHash, const void *key, void *arg)
{
JSJHashEntry *he, **hep, **hep0;
JSJHashNumber h;
#ifdef HASHMETER
ht->nlookups++;
#endif
h = keyHash * GOLDEN_RATIO;
h >>= ht->shift;
hep = hep0 = &ht->buckets[h];
while ((he = *hep) != 0) {
if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key, arg)) {
/* Move to front of chain if not already there */
if (hep != hep0) {
*hep = he->next;
he->next = *hep0;
*hep0 = he;
}
return hep0;
}
hep = &he->next;
#ifdef HASHMETER
ht->nsteps++;
#endif
}
return hep;
}
PR_IMPLEMENT(JSJHashEntry *)
JSJ_HashTableRawAdd(JSJHashTable *ht, JSJHashEntry **hep,
JSJHashNumber keyHash, const void *key, void *value,
void *arg)
{
PRUint32 i, n;
JSJHashEntry *he, *next, **oldbuckets;
PRUint32 nb;
/* Grow the table if it is overloaded */
n = NBUCKETS(ht);
if (ht->nentries >= OVERLOADED(n)) {
#ifdef HASHMETER
ht->ngrows++;
#endif
ht->shift--;
oldbuckets = ht->buckets;
#if defined(XP_PC) && !defined(_WIN32)
if (2 * n > 16000)
return 0;
#endif /* WIN16 */
nb = 2 * n * sizeof(JSJHashEntry *);
ht->buckets = (*ht->allocOps->allocTable)(ht->allocPriv, nb);
if (!ht->buckets) {
ht->buckets = oldbuckets;
return 0;
}
memset(ht->buckets, 0, nb);
for (i = 0; i < n; i++) {
for (he = oldbuckets[i]; he; he = next) {
next = he->next;
hep = JSJ_HashTableRawLookup(ht, he->keyHash, he->key, arg);
PR_ASSERT(*hep == 0);
he->next = 0;
*hep = he;
}
}
#ifdef DEBUG
memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
#endif
(*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
}
/* Make a new key value entry */
he = (*ht->allocOps->allocEntry)(ht->allocPriv, key);
if (!he)
return 0;
he->keyHash = keyHash;
he->key = key;
he->value = value;
he->next = *hep;
*hep = he;
ht->nentries++;
return he;
}
PR_IMPLEMENT(JSJHashEntry *)
JSJ_HashTableAdd(JSJHashTable *ht, const void *key, void *value, void *arg)
{
JSJHashNumber keyHash;
JSJHashEntry *he, **hep;
keyHash = (*ht->keyHash)(key, arg);
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
if ((he = *hep) != 0) {
/* Hit; see if values match */
if ((*ht->valueCompare)(he->value, value, arg)) {
/* key,value pair is already present in table */
return he;
}
if (he->value)
(*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_VALUE);
he->value = value;
return he;
}
return JSJ_HashTableRawAdd(ht, hep, keyHash, key, value, arg);
}
PR_IMPLEMENT(void)
JSJ_HashTableRawRemove(JSJHashTable *ht, JSJHashEntry **hep, JSJHashEntry *he, void *arg)
{
PRUint32 i, n;
JSJHashEntry *next, **oldbuckets;
PRUint32 nb;
*hep = he->next;
(*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_ENTRY);
/* Shrink table if it's underloaded */
n = NBUCKETS(ht);
if (--ht->nentries < UNDERLOADED(n)) {
#ifdef HASHMETER
ht->nshrinks++;
#endif
ht->shift++;
oldbuckets = ht->buckets;
nb = n * sizeof(JSJHashEntry*) / 2;
ht->buckets = (*ht->allocOps->allocTable)(ht->allocPriv, nb);
if (!ht->buckets) {
ht->buckets = oldbuckets;
return;
}
memset(ht->buckets, 0, nb);
for (i = 0; i < n; i++) {
for (he = oldbuckets[i]; he; he = next) {
next = he->next;
hep = JSJ_HashTableRawLookup(ht, he->keyHash, he->key, arg);
PR_ASSERT(*hep == 0);
he->next = 0;
*hep = he;
}
}
#ifdef DEBUG
memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
#endif
(*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
}
}
PR_IMPLEMENT(PRBool)
JSJ_HashTableRemove(JSJHashTable *ht, const void *key, void *arg)
{
JSJHashNumber keyHash;
JSJHashEntry *he, **hep;
keyHash = (*ht->keyHash)(key, arg);
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
if ((he = *hep) == 0)
return PR_FALSE;
/* Hit; remove element */
JSJ_HashTableRawRemove(ht, hep, he, arg);
return PR_TRUE;
}
PR_IMPLEMENT(void *)
JSJ_HashTableLookup(JSJHashTable *ht, const void *key, void *arg)
{
JSJHashNumber keyHash;
JSJHashEntry *he, **hep;
keyHash = (*ht->keyHash)(key, arg);
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
if ((he = *hep) != 0) {
return he->value;
}
return 0;
}
/*
** Iterate over the entries in the hash table calling func for each
** entry found. Stop if "f" says to (return value & PR_ENUMERATE_STOP).
** Return a count of the number of elements scanned.
*/
PR_IMPLEMENT(int)
JSJ_HashTableEnumerateEntries(JSJHashTable *ht, JSJHashEnumerator f, void *arg)
{
JSJHashEntry *he, **hep;
PRUint32 i, nbuckets;
int rv, n = 0;
JSJHashEntry *todo = 0;
nbuckets = NBUCKETS(ht);
for (i = 0; i < nbuckets; i++) {
hep = &ht->buckets[i];
while ((he = *hep) != 0) {
rv = (*f)(he, n, arg);
n++;
if (rv & (HT_ENUMERATE_REMOVE | HT_ENUMERATE_UNHASH)) {
*hep = he->next;
if (rv & HT_ENUMERATE_REMOVE) {
he->next = todo;
todo = he;
}
} else {
hep = &he->next;
}
if (rv & HT_ENUMERATE_STOP) {
goto out;
}
}
}
out:
hep = &todo;
while ((he = *hep) != 0) {
JSJ_HashTableRawRemove(ht, hep, he, arg);
}
return n;
}
#ifdef HASHMETER
#include <math.h>
#include <stdio.h>
PR_IMPLEMENT(void)
JSJ_HashTableDumpMeter(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp)
{
double mean, variance;
PRUint32 nchains, nbuckets;
PRUint32 i, n, maxChain, maxChainLen;
JSJHashEntry *he;
variance = 0;
nchains = 0;
maxChainLen = 0;
nbuckets = NBUCKETS(ht);
for (i = 0; i < nbuckets; i++) {
he = ht->buckets[i];
if (!he)
continue;
nchains++;
for (n = 0; he; he = he->next)
n++;
variance += n * n;
if (n > maxChainLen) {
maxChainLen = n;
maxChain = i;
}
}
mean = (double)ht->nentries / nchains;
variance = fabs(variance / nchains - mean * mean);
fprintf(fp, "\nHash table statistics:\n");
fprintf(fp, " number of lookups: %u\n", ht->nlookups);
fprintf(fp, " number of entries: %u\n", ht->nentries);
fprintf(fp, " number of grows: %u\n", ht->ngrows);
fprintf(fp, " number of shrinks: %u\n", ht->nshrinks);
fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps
/ ht->nlookups);
fprintf(fp, "mean hash chain length: %g\n", mean);
fprintf(fp, " standard deviation: %g\n", sqrt(variance));
fprintf(fp, " max hash chain length: %u\n", maxChainLen);
fprintf(fp, " max hash chain: [%u]\n", maxChain);
for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++)
if ((*dump)(he, i, fp) != HT_ENUMERATE_NEXT)
break;
}
#endif /* HASHMETER */
PR_IMPLEMENT(int)
JSJ_HashTableDump(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp)
{
int count;
count = JSJ_HashTableEnumerateEntries(ht, dump, fp);
#ifdef HASHMETER
JSJ_HashTableDumpMeter(ht, dump, fp);
#endif
return count;
}
PR_IMPLEMENT(JSJHashNumber)
JSJ_HashString(const void *key)
{
JSJHashNumber h;
const unsigned char *s;
h = 0;
for (s = key; *s; s++)
h = (h >> 28) ^ (h << 4) ^ *s;
return h;
}
PR_IMPLEMENT(int)
JSJ_CompareStrings(const void *v1, const void *v2)
{
return strcmp(v1, v2) == 0;
}
PR_IMPLEMENT(int)
JSJ_CompareValues(const void *v1, const void *v2)
{
return v1 == v2;
}

Просмотреть файл

@ -1,141 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This is a copy of the NSPR hash-table library, but it has been slightly
* modified to allow an additional argument to be passed into the hash
* key-comparision function. This is used to maintain thread-safety by
* passing in a JNIEnv pointer to the key-comparison function rather
* than storing it in a global. All types,function names, etc. have
* been renamed from their original NSPR names to protect the innocent.
*/
#ifndef jsj_hash_h___
#define jsj_hash_h___
/*
* API to portable hash table code.
*/
#include <stddef.h>
#include <stdio.h>
#include "prtypes.h"
PR_BEGIN_EXTERN_C
typedef struct JSJHashEntry JSJHashEntry;
typedef struct JSJHashTable JSJHashTable;
typedef PRUint32 JSJHashNumber;
#define JSJ_HASH_BITS 32
typedef JSJHashNumber (*JSJHashFunction)(const void *key, void *arg);
typedef PRIntn (*JSJHashComparator)(const void *v1, const void *v2, void *arg);
typedef PRIntn (*JSJHashEnumerator)(JSJHashEntry *he, PRIntn i, void *arg);
/* Flag bits in JSJHashEnumerator's return value */
#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */
#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */
#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */
#define HT_ENUMERATE_UNHASH 4 /* just unhash the current entry */
typedef struct JSJHashAllocOps {
void * (*allocTable)(void *pool, size_t size);
void (*freeTable)(void *pool, void *item);
JSJHashEntry * (*allocEntry)(void *pool, const void *key);
void (*freeEntry)(void *pool, JSJHashEntry *he, PRUintn flag);
} JSJHashAllocOps;
#define HT_FREE_VALUE 0 /* just free the entry's value */
#define HT_FREE_ENTRY 1 /* free value and entire entry */
struct JSJHashEntry {
JSJHashEntry *next; /* hash chain linkage */
JSJHashNumber keyHash; /* key hash function result */
const void *key; /* ptr to opaque key */
void *value; /* ptr to opaque value */
};
struct JSJHashTable {
JSJHashEntry **buckets; /* vector of hash buckets */
PRUint32 nentries; /* number of entries in table */
PRUint32 shift; /* multiplicative hash shift */
JSJHashFunction keyHash; /* key hash function */
JSJHashComparator keyCompare; /* key comparison function */
JSJHashComparator valueCompare; /* value comparison function */
JSJHashAllocOps *allocOps; /* allocation operations */
void *allocPriv; /* allocation private data */
#ifdef HASHMETER
PRUint32 nlookups; /* total number of lookups */
PRUint32 nsteps; /* number of hash chains traversed */
PRUint32 ngrows; /* number of table expansions */
PRUint32 nshrinks; /* number of table contractions */
#endif
};
/*
* Create a new hash table.
* If allocOps is null, use default allocator ops built on top of malloc().
*/
PR_EXTERN(JSJHashTable *)
JSJ_NewHashTable(PRUint32 n, JSJHashFunction keyHash,
JSJHashComparator keyCompare, JSJHashComparator valueCompare,
JSJHashAllocOps *allocOps, void *allocPriv);
PR_EXTERN(void)
JSJ_HashTableDestroy(JSJHashTable *ht);
/* Low level access methods */
PR_EXTERN(JSJHashEntry **)
JSJ_HashTableRawLookup(JSJHashTable *ht, JSJHashNumber keyHash, const void *key, void *arg);
PR_EXTERN(JSJHashEntry *)
JSJ_HashTableRawAdd(JSJHashTable *ht, JSJHashEntry **hep, JSJHashNumber keyHash,
const void *key, void *value, void *arg);
PR_EXTERN(void)
JSJ_HashTableRawRemove(JSJHashTable *ht, JSJHashEntry **hep, JSJHashEntry *he, void *arg);
/* Higher level access methods */
PR_EXTERN(JSJHashEntry *)
JSJ_HashTableAdd(JSJHashTable *ht, const void *key, void *value, void *arg);
PR_EXTERN(PRBool)
JSJ_HashTableRemove(JSJHashTable *ht, const void *key, void *arg);
PR_EXTERN(PRIntn)
JSJ_HashTableEnumerateEntries(JSJHashTable *ht, JSJHashEnumerator f, void *arg);
PR_EXTERN(void *)
JSJ_HashTableLookup(JSJHashTable *ht, const void *key, void *arg);
PR_EXTERN(PRIntn)
JSJ_HashTableDump(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp);
/* General-purpose C string hash function. */
PR_EXTERN(JSJHashNumber)
JSJ_HashString(const void *key);
/* Compare strings using strcmp(), return true if equal. */
PR_EXTERN(int)
JSJ_CompareStrings(const void *v1, const void *v2);
/* Stub function just returns v1 == v2 */
PR_EXTERN(PRIntn)
JSJ_CompareValues(const void *v1, const void *v2);
PR_END_EXTERN_C
#endif /* jsj_hash_h___ */

Просмотреть файл

@ -1,20 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/*
@ -28,13 +13,9 @@
#include <stdlib.h>
#include <string.h>
#include "prtypes.h"
#include "prprintf.h"
#include "prassert.h"
#include "prosdep.h"
#include "jsj_private.h" /* LiveConnect internals */
#include "jsjava.h" /* LiveConnect external API */
#include "jscntxt.h" /* for error reporting */
/*
* A helper function for jsj_ConvertJavaMethodSignatureToString():
@ -322,8 +303,8 @@ jsj_InitJavaMethodSignature(JSContext *cx, JNIEnv *jEnv,
a = arg_signatures[i] = jsj_GetJavaClassDescriptor(cx, jEnv, arg_class);
if (!a) {
jsj_ReportJavaError(cx, jEnv, "Could not determine Java class "
"signature using java.lang.reflect");
jsj_UnexpectedJavaError(cx, jEnv, "Could not determine Java class "
"signature using java.lang.reflect");
goto error;
}
}
@ -715,7 +696,7 @@ resolve_overloaded_method(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *mem
static jvalue *
convert_JS_method_args_to_java_argv(JSContext *cx, JNIEnv *jEnv, jsval *argv,
JavaMethodSpec *method, JSBool **localvp)
JavaMethodSpec *method, JSBool **localvp)
{
jvalue *jargv;
JSBool ok, *localv;
@ -752,7 +733,8 @@ convert_JS_method_args_to_java_argv(JSContext *cx, JNIEnv *jEnv, jsval *argv,
ok = jsj_ConvertJSValueToJavaValue(cx, jEnv, argv[i], arg_signatures[i],
&dummy_cost, &jargv[i], &localv[i]);
if (!ok) {
JS_ReportError(cx, "Internal error: can't convert JS value to Java value");
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_CONVERT_JS_VALUE);
JS_free(cx, jargv);
JS_free(cx, localv);
*localvp = NULL;
@ -767,9 +749,9 @@ static JSBool
invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env,
jobject java_class_or_instance,
JavaClassDescriptor *class_descriptor,
JavaMethodSpec *method,
JavaMethodSpec *method,
JSBool is_static_method,
jsval *argv, jsval *vp)
jsval *argv, jsval *vp)
{
jvalue java_value;
jvalue *jargv;
@ -800,10 +782,12 @@ invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env,
}
old_cx = JSJ_SetDefaultJSContextForJavaThread(cx, jsj_env);
if (old_cx) {
JS_ReportError(cx, "Java thread in simultaneous use by more than "
"one JSContext ?");
#ifdef DEBUG
if (old_cx && (old_cx != cx)) {
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_MULTIPLE_JTHREADS);
}
#endif
jargv = NULL;
localv = NULL;
@ -1019,8 +1003,8 @@ static JSBool
invoke_java_constructor(JSContext *cx,
JSJavaThreadState *jsj_env,
jclass java_class,
JavaMethodSpec *method,
jsval *argv, jsval *vp)
JavaMethodSpec *method,
jsval *argv, jsval *vp)
{
jvalue *jargv;
uintN argc, i;
@ -1049,10 +1033,12 @@ invoke_java_constructor(JSContext *cx,
}
old_cx = JSJ_SetDefaultJSContextForJavaThread(cx, jsj_env);
if (old_cx) {
JS_ReportError(cx, "Java thread in simultaneous use by more than "
"one JSContext ?");
#ifdef DEBUG
if (old_cx && (old_cx != cx)) {
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, JSJMSG_MULTIPLE_JTHREADS);
}
#endif
/* Call the constructor */
java_object = (*jEnv)->NewObjectA(jEnv, java_class, methodID, jargv);
@ -1067,14 +1053,16 @@ invoke_java_constructor(JSContext *cx,
}
out:
for (i = 0; i < argc; i++) {
if (localv[i])
(*jEnv)->DeleteLocalRef(jEnv, jargv[i].l);
if (localv) {
for (i = 0; i < argc; i++) {
if (localv[i])
(*jEnv)->DeleteLocalRef(jEnv, jargv[i].l);
}
JS_free(cx, localv);
}
if (jargv)
JS_free(cx, jargv);
if (localv)
JS_free(cx, localv);
if (error_occurred)
return JS_FALSE;
else
@ -1134,25 +1122,25 @@ jsj_JavaConstructorWrapper(JSContext *cx, JSObject *obj,
/* Get class/interface flags and check them */
modifiers = class_descriptor->modifiers;
if (modifiers & ACC_ABSTRACT) {
JS_ReportError(cx, "Java class %s is abstract and therefore may not "
"be instantiated", class_descriptor->name);
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_ABSTRACT_JCLASS, class_descriptor->name);
return JS_FALSE;
}
if (modifiers & ACC_INTERFACE) {
JS_ReportError(cx, "%s is a Java interface and therefore may not "
"be instantiated", class_descriptor->name);
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_IS_INTERFACE, class_descriptor->name);
return JS_FALSE;
}
if ( !(modifiers & ACC_PUBLIC) ) {
JS_ReportError(cx, "Java class %s is not public and therefore may not "
"be instantiated", class_descriptor->name);
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_NOT_PUBLIC, class_descriptor->name);
return JS_FALSE;
}
member_descriptor = jsj_LookupJavaClassConstructors(cx, jEnv, class_descriptor);
if (!member_descriptor) {
JS_ReportError(cx, "No public constructors defined for Java class %s",
class_descriptor->name);
JS_ReportErrorNumber(cx, jsj_GetErrorMessage,
JSJMSG_NO_CONSTRUCTORS, class_descriptor->name);
return JS_FALSE;
}

Просмотреть файл

@ -1,20 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/*
@ -29,10 +14,28 @@
#ifndef _JSJAVA_PVT_H
#define _JSJAVA_PVT_H
#include "prtypes.h"
/* NSPR1 compatibility definitions */
#ifdef NSPR20
# include "prprf.h"
# include "prlog.h"
# include "plhash.h" /* NSPR hash-tables */
#else
# include "prprintf.h"
# include "prassert.h"
# include "prhash.h" /* NSPR hash-tables */
# define PRHashNumber prhashcode
#endif
#ifdef XP_MAC
# include "prosdep.h"
#endif
#include "jsj_hash.h" /* Hash tables */
#include "prhash.h" /* NSPR hash-tables */
#include "jni.h" /* Java Native Interface */
#include "jsapi.h" /* JavaScript engine API */
#include "jsjava.h" /* LiveConnect public API */
/*************************** Type Declarations ******************************/
@ -42,11 +45,7 @@ typedef struct JavaMemberDescriptor JavaMemberDescriptor;
typedef struct JavaMethodSpec JavaMethodSpec;
typedef struct JavaClassDescriptor JavaClassDescriptor;
typedef struct JavaClassDescriptor JavaSignature;
typedef struct JSJCallbacks JSJCallbacks;
typedef struct CapturedJSError CapturedJSError;
typedef struct JavaPackageDef JavaPackageDef;
typedef struct JSJavaThreadState JSJavaThreadState;
typedef struct JSJavaVM JSJavaVM;
typedef struct JavaMemberVal JavaMemberVal;
/*
@ -86,12 +85,12 @@ typedef struct JavaFieldSpec {
/* A descriptor for the reflection of a single Java method.
Each overloaded method has a separate corresponding JavaMethodSpec. */
typedef struct JavaMethodSpec {
struct JavaMethodSpec {
jmethodID methodID; /* JVM opaque access handle for method */
JavaMethodSignature signature;
const char * name; /* UTF8; TODO - Should support Unicode method names */
JavaMethodSpec * next; /* next method in chain of overloaded methods */
} JavaMethodSpec;
};
/*
* A descriptor for the reflection of a single member of a Java object.
@ -100,17 +99,17 @@ typedef struct JavaMethodSpec {
* they are overloaded methods sharing the same simple name.) This same
* descriptor type is used for both static or instance members.
*/
typedef struct JavaMemberDescriptor {
struct JavaMemberDescriptor {
const char * name; /* simple name of field and/or method */
jsid id; /* hashed name for quick JS property lookup */
JavaFieldSpec * field; /* field with the given name, if any */
JavaMethodSpec * methods; /* Overloaded methods which share the same name, if any */
JavaMemberDescriptor * next; /* next descriptor in same defining class */
JSObject * invoke_func_obj; /* If non-null, JSFunction obj to invoke method */
} JavaMemberDescriptor;
};
/* This is the native portion of a reflected Java class */
typedef struct JavaClassDescriptor {
struct JavaClassDescriptor {
const char * name; /* Name of class, e.g. "java/lang/Byte" */
JavaSignatureChar type; /* class category: primitive type, object, array */
jclass java_class; /* Opaque JVM handle to corresponding java.lang.Class */
@ -125,18 +124,18 @@ typedef struct JavaClassDescriptor {
e.g. abstract, private */
int ref_count; /* # of references to this struct */
JavaSignature * array_component_signature; /* Only non-NULL for array classes */
} JavaClassDescriptor;
};
/* This is the native portion of a reflected Java method or field */
typedef struct JavaMemberVal {
struct JavaMemberVal {
jsval field_val; /* Captured value of Java field */
jsval invoke_method_func_val; /* JSFunction wrapper around Java method invoker */
JavaMemberDescriptor * descriptor;
JavaMemberVal * next;
} JavaMemberVal;
};
/* This is the native portion of a reflected Java object */
typedef struct {
typedef struct JavaObjectWrapper {
jobject java_obj; /* Opaque JVM ref to Java object */
JavaClassDescriptor * class_descriptor; /* Java class info */
} JavaObjectWrapper;
@ -152,7 +151,7 @@ typedef struct {
/* A JSJavaVM structure must be created for each Java VM that is accessed
via LiveConnect */
typedef struct JSJavaVM {
struct JSJavaVM {
/* TODO - all LiveConnect global variables should be migrated into this
structure in order to allow more than one LiveConnect-enabled
Java VM to exist within the same process. */
@ -161,17 +160,17 @@ typedef struct JSJavaVM {
JSBool jsj_created_java_vm;
int num_attached_threads;
JSJavaVM * next; /* next VM among all created VMs */
} JSJavaVM;
};
/* Per-thread state that encapsulates the connection to the Java VM */
typedef struct JSJavaThreadState {
struct JSJavaThreadState {
const char * name; /* Thread name, for debugging */
JSJavaVM * jsjava_vm; /* All per-JVM state */
JNIEnv * jEnv; /* Per-thread opaque handle to Java VM */
CapturedJSError * pending_js_errors; /* JS errors to be thrown as Java exceptions */
JSContext * cx; /* current JS context for thread */
JSJavaThreadState * next; /* next thread state among all created threads */
} JSJavaThreadState;
};
/******************************** Globals ***********************************/
@ -181,6 +180,7 @@ extern JSJCallbacks *JSJ_callbacks;
extern JSClass JavaObject_class;
extern JSClass JavaArray_class;
extern JSClass JavaClass_class;
extern JSClass JavaMember_class;
/*
* Opaque JVM handles to Java classes, methods and objects required for
@ -291,9 +291,11 @@ jsj_ConvertJavaObjectToJSString(JSContext *cx, JNIEnv *jEnv,
jobject java_obj, jsval *vp);
extern JSBool
jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jobject java_obj, jsval *vp);
extern JSBool
jsj_ConvertJavaObjectToJSBoolean(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jobject java_obj, jsval *vp);
/************************ Java package reflection **************************/
@ -402,6 +404,9 @@ extern JSBool
jsj_ReflectJavaMethodsAndFields(JSContext *cx, JavaClassDescriptor *class_descriptor,
JSBool reflect_only_statics);
extern JSObject *
jsj_CreateJavaMember(JSContext *cx, jsval method_val, jsval field_val);
/************************* Java object reflection **************************/
extern JSBool
jsj_init_JavaObject(JSContext *, JSObject *);
@ -421,9 +426,6 @@ JavaObject_finalize(JSContext *cx, JSObject *obj);
extern JSBool
JavaObject_resolve(JSContext *cx, JSObject *obj, jsval id);
extern JSBool
JavaObject_enumerate(JSContext *cx, JSObject *obj);
extern JSBool
JavaObject_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
@ -448,6 +450,9 @@ jsj_SetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array,
extern jobject
jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj);
extern JSObject *
jsj_UnwrapJSObjectWrapper(JNIEnv *jEnv, jobject java_wrapper_obj);
extern void
jsj_ClearPendingJSErrors(JSJavaThreadState *jsj_env);
@ -467,6 +472,9 @@ jsj_GetJavaErrorMessage(JNIEnv *env);
extern void
jsj_LogError(const char *error_msg);
extern const JSErrorFormatString *
jsj_GetErrorMessage(const uintN errorNumber);
PR_CALLBACK JSJHashNumber
jsj_HashJavaObject(const void *key, void* env);
@ -504,4 +512,14 @@ jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp);
JS_free(cx, x); \
PR_END_MACRO
enum JSJErrNum {
#define MSG_DEF(name, number, format, count) \
name = number,
#include "jsj_msg.def"
#undef MSG_DEF
JSJ_Err_Limit
#undef MSGDEF
};
#endif /* _JSJAVA_PVT_H */

Просмотреть файл

@ -1,20 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/*
@ -27,11 +12,6 @@
#include <stdlib.h>
#include <string.h>
#include "prtypes.h"
#include "prprintf.h"
#include "prassert.h"
#include "prosdep.h"
#include "jsj_private.h" /* LiveConnect internals */
#include "jsjava.h" /* External LiveConnect API */
@ -43,7 +23,7 @@
PR_CALLBACK JSJHashNumber
jsj_HashJavaObject(const void *key, void* env)
{
prhashcode hash_code;
PRHashNumber hash_code;
jobject java_obj;
JNIEnv *jEnv;
@ -161,7 +141,7 @@ jsj_GetJavaErrorMessage(JNIEnv *jEnv)
jstring java_exception_jstring;
exception = (*jEnv)->ExceptionOccurred(jEnv);
if (exception) {
if (exception && jlThrowable_toString) {
java_exception_jstring =
(*jEnv)->CallObjectMethod(jEnv, exception, jlThrowable_toString);
java_error_msg = (*jEnv)->GetStringUTFChars(jEnv, java_exception_jstring, NULL);
@ -312,6 +292,31 @@ jsj_LogError(const char *error_msg)
fputs(error_msg, stderr);
}
/*
Error number handling.
jsj_ErrorFormatString is an array of format strings mapped
by error number. It is initialized by the contents of jsj_msg.def
jsj_GetErrorMessage is invoked by the engine whenever it wants
to convert an error number into an error format string.
*/
JSErrorFormatString jsj_ErrorFormatString[JSJ_Err_Limit] = {
#define MSG_DEF(name, number, count, format) \
{ format, count } ,
#include "jsj_msg.def"
#undef MSG_DEF
};
const JSErrorFormatString *
jsj_GetErrorMessage(const uintN errorNumber)
{
if ((errorNumber > 0) && (errorNumber < JSJ_Err_Limit))
return &jsj_ErrorFormatString[errorNumber];
else
return NULL;
}
jsize
jsj_GetJavaArrayLength(JSContext *cx, JNIEnv *jEnv, jarray java_array)
{
@ -339,7 +344,6 @@ jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp)
}
return NULL;
}
if (envp)
*envp = jsj_env->jEnv;
*envp = jsj_env->jEnv;
return jsj_env;
}

Просмотреть файл

@ -1,234 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* Publicly exported functions for JavaScript <==> Java communication.
*
*/
#ifndef _JSJAVA_H
#define _JSJAVA_H
#include "jni.h" /* Java Native Interface */
#include "jsapi.h" /* JavaScript engine API */
/*
* A JSJavaVM structure is a wrapper around a JavaVM which incorporates
* additional LiveConnect state.
*/
typedef struct JSJavaVM JSJavaVM;
/* LiveConnect and Java state, one per thread */
typedef struct JSJavaThreadState JSJavaThreadState;
/*
* This callback table provides hooks to external functions that implement
* functionality specific to the embedding. For example, these callbacks are
* necessary in multi-threaded environments or to implement a security
* policy.
*/
typedef struct JSJCallbacks {
/* This callback is invoked when there is no JavaScript execution
environment (JSContext) associated with the current Java thread and
a call is made from Java into JavaScript. (A JSContext is associated
with a Java thread by calling the JSJ_SetJSContextForJavaThread()
function.) This callback is only invoked when Java spontaneously calls
into JavaScript, i.e. it is not called when JS calls into Java which
calls back into JS.
This callback can be used to create a JSContext lazily, or obtain
one from a pool of available JSContexts. The implementation of this
callback can call JSJ_SetJSContextForJavaThread() to avoid any further
callbacks of this type for this Java thread. */
JSContext * (*map_jsj_thread_to_js_context)(JSJavaThreadState *jsj_env,
char **errp);
/* This callback is invoked whenever a call is made into Java from
JavaScript. It's responsible for mapping from a JavaScript execution
environment (JSContext) to a Java thread. (A JavaContext can only
be associated with one Java thread at a time.) */
JSJavaThreadState * (*map_js_context_to_jsj_thread)(JSContext *cx,
char **errp);
/* This callback implements netscape.javascript.JSObject.getWindow(),
a method named for its behavior in the browser environment, where it
returns the JS "Window" object corresponding to the HTML window that an
applet is embedded within. More generally, it's a way for Java to get
hold of a JS object that has not been explicitly passed to it. */
JSObject * (*map_java_object_to_js_object)(JNIEnv *jEnv, jobject hint,
char **errp);
/* An interim callback function until the LiveConnect security story is
straightened out. This function pointer can be set to NULL. */
JSPrincipals * (*get_JSPrincipals_from_java_caller)(JNIEnv *jEnv);
/* The following two callbacks sandwich any JS evaluation performed
from Java. They may be used to implement concurrency constraints, e.g.
by suspending the current thread until some condition is met. In the
browser embedding, these are used to maintain the run-to-completion
semantics of JavaScript. It is acceptable for either function pointer
to be NULL. */
JSBool (*enter_js_from_java)(char **errp);
void (*exit_js)(void);
/* Most LiveConnect errors are signaled by calling JS_ReportError(), but in
some circumstances, the target JSContext for such errors is not
determinable, e.g. during initialization. In such cases any error
messages are routed to this function. If the function pointer is set to
NULL, error messages are sent to stderr. */
void (*error_print)(const char *error_msg);
/* Reserved for future use */
void * reserved[10];
} JSJCallbacks;
/*===========================================================================*/
/* A flag that denotes that a Java package has no sub-packages other than those
explicitly pre-defined at the time of initialization. An access
to a simple name within such a package, therefore, must either correspond to
one of these explicitly pre-defined sub-packages or to a class within this
package. It is reasonable for LiveConnect to signal an error if a simple
name does not comply with these criteria. */
#define PKG_SYSTEM 1
/* A flag that denotes that a Java package which might contain sub-packages
that are not pre-defined at initialization time, because the sub-packages
may not be the same in all installations. Therefore, an access to a simple
name within such a a package which does not correspond to either a
pre-defined sub-package or to a class, must be assummed to refer to an
unknown sub-package. This behavior may cause bogus JavaPackage objects to be
created if a package name is misspelled, e.g. sun.oi.net. */
#define PKG_USER 2
/* A Java package defined at initialization time. */
typedef struct JavaPackageDef {
const char * name; /* e.g. "java.lang" */
const char * path; /* e.g. "java/lang", or NULL for default */
int flags; /* PKG_USER, PKG_SYSTEM, etc. */
} JavaPackageDef;
/*===========================================================================*/
/* The following two convenience functions present a complete, but simplified
LiveConnect API which is designed to handle the special case of a single
Java-VM, with single-threaded operation, and the use of only one JSContext.
The full API is in the section below. */
/* Initialize the provided JSContext by setting up the JS classes necessary for
reflection and by defining JavaPackage objects for the default Java packages
as properties of global_obj. If java_vm is NULL, a new Java VM is
created, using the provided classpath in addition to any default classpath.
The classpath argument is ignored, however, if java_vm is non-NULL. */
PR_PUBLIC_API(JSBool)
JSJ_SimpleInit(JSContext *cx, JSObject *global_obj,
JavaVM *java_vm, const char *classpath);
/* Free up all resources. Destroy the Java VM if it was created by LiveConnect */
PR_PUBLIC_API(void)
JSJ_SimpleShutdown();
/*===========================================================================*/
/* The "full" LiveConnect API, required when more than one thread, Java VM, or
JSContext is involved. Initialization pseudocode might go roughly like
this:
JSJ_Init() // Setup callbacks
for each JavaVM {
JSJ_ConnectToJavaVM(...)
}
for each JSContext {
JSJ_InitJSContext(...)
}
for each JS evaluation {
run JavaScript code in the JSContext;
}
*/
/* Called once for all instances of LiveConnect to set up callbacks */
PR_PUBLIC_API(void)
JSJ_Init(JSJCallbacks *callbacks);
/* Called once per Java VM, this function initializes the classes, fields, and
methods required for Java reflection. If java_vm is NULL, a new Java VM is
created, using the provided classpath in addition to any default classpath.
The classpath argument is ignored, however, if java_vm is non-NULL. */
PR_PUBLIC_API(JSJavaVM *)
JSJ_ConnectToJavaVM(JavaVM *java_vm, const char *classpath);
/* Initialize the provided JSContext by setting up the JS classes necessary for
reflection and by defining JavaPackage objects for the default Java packages
as properties of global_obj. Additional packages may be pre-defined by
setting the predefined_packages argument. (Pre-defining a Java package at
initialization time is not necessary, but it will make package lookup faster
and, more importantly, will avoid unnecessary network accesses if classes
are being loaded over the network.) */
PR_PUBLIC_API(JSBool)
JSJ_InitJSContext(JSContext *cx, JSObject *global_obj,
JavaPackageDef *predefined_packages);
/* This function returns a structure that encapsulates the Java and JavaScript
execution environment for the current native thread. It is intended to
be called from the embedder's implementation of JSJCallback's
map_js_context_to_jsj_thread() function. The thread_name argument is only
used for debugging purposes and can be set to NULL. The Java JNI
environment associated with this thread is returned through the java_envp
argument if java_envp is non-NULL. */
PR_PUBLIC_API(JSJavaThreadState *)
JSJ_AttachCurrentThreadToJava(JSJavaVM *jsjava_vm, const char *thread_name,
JNIEnv **java_envp);
/* Destructor routine for per-thread JSJavaThreadState structure */
PR_PUBLIC_API(JSBool)
JSJ_DetachCurrentThreadFromJava(JSJavaThreadState *jsj_env);
/* This function is used to specify a particular JSContext as *the* JavaScript
execution environment to be used when LiveConnect is accessed from the given
Java thread, i.e. when one of the methods of netscape.javascript.JSObject
has been called. There can only be one such JS context for any given Java
thread at a time. To multiplex JSContexts among a single thread, this
function could be called before Java is invoked on that thread.) The return
value is the previous JSContext associated with the given Java thread.
If this function has not been called for a thread and a crossing is made
into JavaScript from Java, the map_jsj_thread_to_js_context() callback will
be invoked to determine the JSContext for the thread. The purpose of the
function is to improve performance by avoiding the expense of the callback.
*/
PR_PUBLIC_API(JSContext *)
JSJ_SetDefaultJSContextForJavaThread(JSContext *cx, JSJavaThreadState *jsj_env);
/* This routine severs the connection to a Java VM, freeing all related resources.
It shouldn't be called until the global scope has been cleared in all related
JSContexts (so that all LiveConnect objects are finalized) and a JavaScript
GC is performed. Otherwise, accessed to free'ed memory could result. */
PR_PUBLIC_API(void)
JSJ_DisconnectFromJavaVM(JSJavaVM *);
/*
* Reflect a Java object into a JS value. The source object, java_obj, must
* be of type java.lang.Object or a subclass and may, therefore, be an array.
*/
PR_PUBLIC_API(JSBool)
JSJ_ConvertJavaObjectToJSValue(JSContext *cx, jobject java_obj, jsval *vp);
#endif /* _JSJAVA_H */

Просмотреть файл

@ -1,147 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
JavaSession.cpp
Uses MRJ to open a Java VM.
by Patrick C. Beard.
*/
#include "JavaSession.h"
#include <Errors.h>
#include <string.h>
#include <stdio.h>
#include <Resources.h>
extern "C" {
static void java_stdout(JMSessionRef session, const void *message, UInt32 messageLengthInBytes);
static void java_stderr(JMSessionRef session, const void *message, UInt32 messageLengthInBytes);
static SInt32 java_stdin(JMSessionRef session, void *buffer, SInt32 maxBufferLength);
static Boolean java_exit(JMSessionRef session, int value);
static Boolean java_authenticate(JMSessionRef session, const char *url, const char *realm,
char userName[255], char password[255]);
static void java_lowmem(JMSessionRef session);
}
static JMSessionCallbacks callbacks = {
kJMVersion, /* should be set to kJMVersion */
&java_stdout, /* JM will route "stdout" to this function. */
&java_stderr, /* JM will route "stderr" to this function. */
&java_stdin, /* read from console - can be nil for default behavior (no console IO) */
&java_exit, /* handle System.exit(int) requests */
&java_authenticate, /* present basic authentication dialog */
&java_lowmem /* Low Memory notification Proc */
};
JavaSession::JavaSession() : mSession(NULL)
{
OSStatus status = ::JMOpenSession(&mSession, /* eDisableJITC */ eJManager2Defaults, eCheckRemoteCode,
&callbacks, kTextEncodingMacRoman, NULL);
checkStatus(status);
}
JavaSession::~JavaSession()
{
if (mSession != NULL) {
OSStatus status = ::JMCloseSession(mSession);
checkStatus(status);
}
}
JNIEnv* JavaSession::getEnv()
{
return ::JMGetCurrentEnv(mSession);
}
static StringPtr c2p(const char* str, StringPtr pstr)
{
unsigned char len = strlen(str);
memcpy(pstr + 1, str, len);
*pstr = len;
return pstr;
}
jclass JavaSession::getClass(const char* className)
{
JNIEnv* env = getEnv();
jclass result = env->FindClass(className);
if (result == NULL) throw OSStatusException(fnfErr);
return result;
}
/**
* Adds a Mac-style path name to the MRJ class path.
*/
void JavaSession::addClassPath(const char* jarFilePath)
{
Str255 pJarFilePath;
FSSpec jarFileSpec;
OSStatus status = FSMakeFSSpec( 0, 0, // use "current working directory"
c2p(jarFilePath, pJarFilePath),
&jarFileSpec);
checkStatus(status);
status = JMAddToClassPath(mSession, &jarFileSpec);
checkStatus(status);
}
// OBLIGATORY JMSession callbacks.
static void java_stdout(JMSessionRef session, const void *message, UInt32 messageLengthInBytes)
{
char* msg = (char*)message;
while (messageLengthInBytes--) {
char c = *msg++;
if (c == '\r')
c = '\n';
fputc(c, stdout);
}
}
static void java_stderr(JMSessionRef session, const void *message, UInt32 messageLengthInBytes)
{
char* msg = (char*)message;
while (messageLengthInBytes--) {
char c = *msg++;
if (c == '\r')
c = '\n';
fputc(c, stderr);
}
}
static SInt32 java_stdin(JMSessionRef session, void *buffer, SInt32 maxBufferLength)
{
return -1;
}
static Boolean java_exit(JMSessionRef session, int value) { return false; }
static Boolean java_authenticate(JMSessionRef session, const char *url, const char *realm,
char userName[255], char password[255])
{
return true;
}
static void java_lowmem(JMSessionRef session)
{
}

Просмотреть файл

@ -1,46 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
JavaSession.h
Uses MRJ to open a Java VM.
by Patrick C. Beard
*/
#pragma once
#include <jni.h>
#include <JManager.h>
#include "OSStatusException.h"
class JavaSession {
public:
JavaSession();
~JavaSession();
JNIEnv* getEnv();
jclass getClass(const char* className);
void addClassPath(const char* jarFilePath);
private:
JMSessionRef mSession;
};

Просмотреть файл

@ -1,46 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
OSStatusException.h
MacOS OSStatus exception.
by Patrick C. Beard.
*/
#pragma once
#ifndef __TYPES__
#include <Types.h>
#endif
class OSStatusException {
public:
OSStatusException(OSStatus status) : mStatus(status) {}
OSStatus getStatus() { return mStatus; }
private:
OSStatus mStatus;
};
inline void checkStatus(OSStatus status)
{
if (status != noErr)
throw OSStatusException(status);
}

Двоичные данные
js/ref/liveconnect/macbuild/LiveConnectShell.mcp

Двоичный файл не отображается.

Просмотреть файл

@ -1,101 +0,0 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class netscape_javascript_JSObject */
#ifndef _Included_netscape_javascript_JSObject
#define _Included_netscape_javascript_JSObject
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: netscape_javascript_JSObject
* Method: initClass
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_initClass
(JNIEnv *, jclass);
/*
* Class: netscape_javascript_JSObject
* Method: getMember
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getMember
(JNIEnv *, jobject, jstring);
/*
* Class: netscape_javascript_JSObject
* Method: getSlot
* Signature: (I)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getSlot
(JNIEnv *, jobject, jint);
/*
* Class: netscape_javascript_JSObject
* Method: setMember
* Signature: (Ljava/lang/String;Ljava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setMember
(JNIEnv *, jobject, jstring, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: setSlot
* Signature: (ILjava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setSlot
(JNIEnv *, jobject, jint, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: removeMember
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_removeMember
(JNIEnv *, jobject, jstring);
/*
* Class: netscape_javascript_JSObject
* Method: call
* Signature: (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_call
(JNIEnv *, jobject, jstring, jobjectArray);
/*
* Class: netscape_javascript_JSObject
* Method: eval
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_eval
(JNIEnv *, jobject, jstring);
/*
* Class: netscape_javascript_JSObject
* Method: toString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_netscape_javascript_JSObject_toString
(JNIEnv *, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: getWindow
* Signature: (Ljava/applet/Applet;)Lnetscape/javascript/JSObject;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getWindow
(JNIEnv *, jclass, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: finalize
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_finalize
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif