Passing a Call Context from .NET Using J-Integra® for .NET |
This example demonstrates how to pass a Call Context from .NET. J-Integra® for .NET is a Java interoperability component that bridges Java/J2EE and Microsoft .NET. It provides bi-directional access of Java objects and .NET components.
Use this example as a guideline to show you how establish a call context before making a method call to a Java object exposed a .NET Singleton using J-Integra® for .NET. After subscribing to com.intrinsyc.janet.InvocationListener, a pre and post invocation method is called before and after the call to the actual Java method.
The Steps to Follow will show you how to deploy J-Integra® for .NET correctly for this example.
The CallContext class is used for holding data in a way similar to Thread Local Storage for method calls. It provides data slots that are unique to each logical thread of execution. The slots are not shared across call contexts on other logical threads. Objects can be added to CallContext as it travels down and back up the execution code path, and examined by various objects along the path.
When a remote method call is made to an object in another Application Domain, CallContext generates a LogicalCallContext instance that travels along with the remote call. Only objects that expose the ILogicalThreadAffinative interface and are stored in the CallContext are propagated outside the Application Domain in a LogicalCallContext. Objects that do not support this interface are not transmitted in LogicalCallContext instances with remote method calls.
J-Integra® for .NET exposes the class com.intrinsyc.janet.Credentials that, when run through GenNet, will generate a C# class that implements ILogicalThreadAffinative. The com.intrinsyc.janet.Credentials class is extremely simple - it contains public fields for a username and password.
A platform with Microsoft Visual Studio .NET 2003 (7.1.3088 or higher) installed, or at least the .NET Framework 1.0.3705 or higher. This will be known throughout the example as the .NET platform.
A platform with J-Integra® for .NET 1.5.1279 (or higher) installed. This will be known throughout the example as the Java platform.
A version of JDK (1.3.1 or higher) installed on the Java platform, and the bin directory included in the path. This is required to compile the Java class and run the J-Integra® for .NET server.
Verify that GenService is installed correctly on the .NET platform.
Perform this step on the Java platform.
In this step, you will need to configure J-Integra® for .NET as a server so it can respond to incoming TCP requests. This is done through the Janetor tool.
Launch Janetor from the Start Menu.
java -jar $USER_INSTALL_DIR$\lib\janetor.jar
Select File - Open and open janet.xml located in $USER_INSTALL_DIR$\examples\callcontext.
Install your J-Integra® for .NET product license. See Installing the J-Integra® for .NET license for further information.
Select java_server.Factory under Local Objects. Here you see that J-Integra® for .NET exposes this class as a Singleton at the at the given machine address and port using TCP.
Before you exit Janetor, save the configuration by going to File - Save.
Perform this step on the Java platform.
In this step, you will take a look at the java_server.Factory class source code to get an idea of how J-Integra® for .NET makes use of the .NET call context.
Open the file Factory.java located in $USER_INSTALL_DIR$\examples\callcontext.
Notice that the class implements com.intrinsyc.janet.InvocationListener, and in the constructor, it adds itself as a listener for any method invocations:
public Factory() throws RemoteException { Janet.addInvocationListener(this); }
The two methods that java_server.Factory inherits from com.intrinsyc.janet.InvocationListener are preInvocation and postInvocation. Each is called before and after the actual method call, respectively. Each of these methods take in a number of parameters, but the one we are most interested in is callContext. This is where the logical call context passed from .NET is stored. Take a look at preInvocation to see how the actual call context is retrieved from callContext:
Credentials c = (Credentials) callContext.get("JanetCredentials");
JanetCredentials is a hard-coded constant in the J-Integra® for .NET runtime and it must be used to get at the actual call context each time. This cannot be changed.
Similarly, notice that postInvocation modifies the data inside the call context before it is passed back to .NET.
Finally, to compile the source, change directory to $USER_INSTALL_DIR$\examples\callcontext and enter:
javac -classpath $USER_INSTALL_DIR$\lib\janet.jar;. java_server\Factory.java
Perform this step on the Java platform.
In this step, you will use the GenNet tool to generate .NET proxies for the Java classes.
Launch GenNet from the Start Menu.
Change directory to $USER_INSTALL_DIR$ and then enter:
java -jar lib\gennet.jar
The first screen of GenNet shows a list of machines that have GenService running (screenshot not shown). Select the appropriate one and click Next.
The next screen prompts for the components (JAR files or directories)
to be added to the CLASSPATH. Each of these components are required
in order for the Java runtime to resolve references to Java classes when
generating .NET proxies. You'll need to add the following component:
- $USER_INSTALL_DIR$\examples\callcontext\
Move on to the next step by clicking Next.
The next screen prompts for the specific Java classes that will
have .NET proxies generated for them. Click on Browse...
to add the following classes (use the CTRL key to select
multiple classes):
- java_server.Factory
- com.intrinsyc.janet.Credentials
Make com.intrinsyc.janet.Credentials a "marshal-by-value" object by clicking on Options... and checking Pass by value.
Click on the Filter button and choose not to generate any proxies for the referenced classes as shown below. This will eliminate the number of .NET proxies created.
Move on to the next step by clicking Next.
The next screen prompts you to specify the .NET Assembly name along with the output directory. The screenshot may show a different output directory than what Output Directory is, but it should be pointing to $USER_INSTALL_DIR$\examples\callcontext\csharp_client\bin\Debug.
You should see a message that the proxy generation was successful. Click Exit to exit GenNet.
Perform this step on the Java platform.
In this crucial step, you'll need to create an entry for com.intrinsyc.janet.Credentials in Janetor under Local Objects. This is required because this class is passed to Java as part of System.Runtime.Remoting.Messaging.CallContext. As a result, .NET Remoting assumes that com.intrinsyc.janet.Credentials is part of mscorlib. The special entry in Janetor ensures that J-Integra® for .NET sends the correct full assembly name, and not that of mscorlib.
Launch Janetor again, load the same configuration file as before, and right-click on Local Objects and select Add class....
The Add Configuration Class is displayed. Enter in com.intrinsyc.janet.Credentials and click OK.
Next, uncheck Pass by Reference so that com.intrinsyc.janet.Credentials will be marshalled by value.
Notice that the other fields are the same as the java_server.Factory node.
To determine the full name of the .NET Assembly generated by GenNet: if you did not check Generate Strong Named Assembly when generating the Assembly, then it is of the form:
[Assembly Name], Version=1.0.1376.17274, Culture=neutral, PublicKeyToken=null
Otherwise, you can use a .NET Framework provided tool like IDLASM to find it. Alternatively, the following two simple lines of C# code will give you the full name:
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(@"C:\temp\MyAssembly.dll"); Console.WriteLine(assembly.FullName);
Before you exit Janetor, save the configuration by going to File - Save.
Perform this step on the Java platform.
In this step, you will start the J-Integra® for .NET server.
To start the J-Integra® for .NET server, change directory to $USER_INSTALL_DIR$\examples\callcontext and enter:
java -cp $USER_INSTALL_DIR$\lib\janet.jar;. com.intrinsyc.janet.Main
Perform this step on the .NET platform.
In this final step, you will review the .NET client source code, configure the .NET client using a configuration file, then compile and run it.
Along with .NET proxies, GenNet generates .NET configuration files to be used as templates - one for the HTTP channel and one for the TCP channel. As the .NET client will be using .NET Remoting's TCP binary to connect to the Java server, we will modify remoting_tcp.config. You can find this in the same directory that the proxies were generated in.
Modify remoting_tcp.config to look like:
<configuration> <system.runtime.remoting> <application> <client> <wellknown url="tcp://localhost:8888/Server/java_server.Factory.soap" type="java_server.Factory, JanetExample""/> </client> <channels> <channel ref="tcp"> <clientProviders> <formatter ref="binary"/> </clientProviders> </channel> </channels> </application> </system.runtime.remoting> </configuration> |
Notice that tcp://localhost:8888/Server matches what was entered under java_server.Factory in Janetor. Change accordingly if necessary.
Load csharp_client.sln located in $USER_INSTALL_DIR$\examples\callcontext\csharp_client and view the Client class. In the contructor call to Factory, the Java code adds the current object instance as a listener (see Factory.java). Next, a call context is created by inserting the marshal-by-value Credentials object into a free slot:
System.Runtime.Remoting.Messaging.CallContext.SetData("JanetCredentials", cred);
Again, note that JanetCredentials is a hard-coded constant in the J-Integra® for .NET runtime and it must be used to set the call context data. This cannot be changed.
During postInvocation, the credentials are changed and placed back into the call context. After the actual method call is made, the .NET client code gets the call context data again and displays it's (changed) contents.
Press F5 to run the .NET client, or simply run the executable in the bin\Debug directory.
On the .NET platform, a console should come up and you should see the output:
Username is: janet Password is: janet After method call, username is now: janet_changed After method call, password is now: janet_changed
Press Enter to exit the .NET client.
Meanwhile, on the Java platform, before the method is actually invoked, the console should read:
[preInvocation] About to call method hello with username janet and password janet
After the method is invoked, the console should read:
[postInvocation] Called method hello with username janet and password janet. Changing crendentials to username janet_changed and password janet_changed.
© 2007 Intrinsyc Software International, Inc. All rights reserved. Legal |