There are two forms of filters: per-process and per-object filters. Per-process filters see all operation and attribute calls leaving or entering a client's or server's address space, irrespective of the target object. Per-object filters apply to individual objects. Both of these filter types are illustrated in Figure 21.1.
|
Note that use of the Dynamic Invocation Interface does not by-pass the filtering mechanism: calls made using the DII will result in the use of all appropriate outgoing and incoming filters, except the filter point in reply post marshal. This filter point must be handled explicitly by a DII programmer, as described in section 19.6.
21.1 Introduction to Per-process Filters
Per-process filters monitor all incoming and outgoing operation and attribute requests to and from an address space. Each process can have a chain of such filters, with each element of the chain performing its own actions. A new element can be added to the chain by carrying out the following two steps:
Filter (defined in package IE.Iona.Orbix2.CORBA).
All monitor points (eight marshalling points and two failure points) are shown in Figure 21.2.
|
in request pre marshal
out reply pre marshal
in reply pre marshal
Each filter point must indicate how the handling of the request should be continued once the filter point itself has completed. In particular, a filter point can determine whether or not OrbixWeb is to continue to process the request or to return an exception to the caller.
Since per-process filters are applied only when an invocation leaves or arrives at an address space, they are not informed of invocations between collocated objects.
Note that a special form of per-process filters can be used to pass authentication information from a client to a server. This type of filter is called an authentication filter, and it supports the verification of the identity of a caller, which is a fundamental requirement for security. Authentication filters are discussed in section 21.3.6.
21.2 Introduction to Per-Object Filters
Per-object filters are associated with a particular object, rather than with all objects in an address space as in per-process filtering. Unlike per-process filters, per-object filters apply even for intra-process operation requests. The following filtering points are supported:
Per-object filters are created by carrying out the following three steps:
Grid for an object which implements interface Grid).
An object can have a chain of pre-filters and/or a chain of post-filters. For example, a chain of pre-filters can be constructed by attaching a pre-filter to the object, then attaching a pre-filter to that filter, and so on.
Note that per-object filtering can only be used if it was enabled when the corresponding IDL interface was compiled by the IDL compiler (see section 21.4.1).
The parameters to an IDL operation request are readily available for both pre and post per-object filters. Any
in and inout parameters are valid for pre filters; in, out and inout parameters and return values are valid for post filters. In contrast, for per-process filters, parameters to the operation request are not in general available.21.3 Per-Process Filters
A per-process filter is installed by defining a derived class of class Filter, and re-defining one or more of its methods:
boolean value to indicate whether or not OrbixWeb should continue to make the request. For example
public boolean outRequestPreMarshal(Request r) throws IE.Iona.Orbix2.CORBA.SystemException;The failure methods,
outReplyFailure() and inReplyFailure(), have a void return type. The details of the request being made can be obtained by calling methods on the
Request parameter (class Request is defined in package IE.Iona.Orbix2.CORBA). Examples of this are shown in section 21.3.1.Full details of these methods are given inPart II, "Class and Interface Reference" of the OrbixWeb Reference Guide.
The constructor of class
Filter adds the newly created filter object into the per-process filter chain. Direct instances of Filter cannot be created (the constructor is protected to enforce this). Derived classes of Filter will normally have public constructors.Filter and redefine some subset of the filter point methods to carry out the required filtering. If any of the non-failure monitoring methods is not redefined in a derived class of Filter, then the following implementation is inherited in all cases:
// Java
{ return true; } // Continue the call.
The failure filter methods inherit the following implementation:
// Java
{ return; }
Note that the two `out reply' marshalling filter points are used only if the operation request is issued to the target object. The two `in reply' marshalling filter points are used only if the operation request is sent out of the caller's address space.
// Java
import IE.Iona.Orbix2.CORBA.Filter;
import IE.Iona.Orbix2.CORBA.Request;
import IE.Iona.Orbix2.CORBA.SystemException;
public class ProcessFilter extends Filter {
public boolean
outRequestPreMarshal (Request r) {
String s, o;
try {
s = (r.target ())._object_to_string ();
o = r.operation ();
}
catch (SystemException se) {
...
}
System.out.println ("Request outgoing to "
+ s + " with operation name "
+ o + ".");
return true; // continue the call
}
boolean inRequestPreMarshal (Request r) {
String s, o;
try {
s = (r.target ())._object_to_string ();
o = r.operation ();
}
catch (SystemException se) {
...
}
System.out.println ("Request incoming to "
+ s + " with operation name "
+ o + ".");
return true; // continue the call
boolean outReplyPreMarshal (Request r) {
String o;
try {
o = r.operation ();
}
catch (SystemException se) {
...
}
System.out.println ("Incoming operation "
+ o + " finished.");
return true; // Continue the call.
}
boolean inReplyPreMarshal (Request r) {
String o;
try {
o = r.operation ();
}
catch (SystemException se) {
...
}
System.out.println ("Outgoing operation "
+ o + " finished.");
return true; // Continue the call.
}
void outReplyFailure (Request r) {
String o;
try {
o = r.operation ();
}
catch (SystemException se) {
...
}
System.out.println ("Operation "
+ o + " raised exception.");
return;
}
void inReplyFailure (Request r) {
String o;
try {
o = r.operation ();
}
catch (SystemException se) {
...
}
System.out.println ("Operation "
+ o + " raised exception.");
return;
}
}
Such classes can have any name; but they must inherit from Filter. Filter has a protected default constructor; ProcessFilter is given a default (no parameter) public constructor by Java.The method
target() can be applied to a Request to find the object reference of the target object; and the method _object_to_string() can be applied to an object reference to get a string form of an object reference. The method operation() can be applied to a Request to find the name of the operation being called.
// Java ProcessFilter myFilter = new ProcessFilter ();This object will automatically add itself to the per-process filter chain.
inRequestPostMarshal() filter point can be changed to raise a NO_PERMISSION system exception:
public boolean outRequestPostMarshal(Request r){
if (...) {
IE.Iona.Orbix2.CORBA.NO_PERMISSION ex =
new IE.Iona.Orbix2.CORBA.NO_PERMISSION(0,
IE.Iona.Orbix2.CORBA.CompletionStatus.NO);
throw ex;
// The NO_PERMISSION system exception
// has been raised here, with a
// completion status of NO.
}
...
}
inReplyPostMarshal() filter point does not cause the exception to be propagated: at that stage, the invocation is essentially already completed and it is too late to raise an exception.
outReplyFailure() and inReplyFailure().
outRequestPreMarshal()outRequestPostMarshal()inRequestPreMarshal()inRequestPostMarshal()
outReplyFailure()inReplyFailure()
Request.isException() method, for example:
// Java
if (r.isException()) {
// Have exception already.
}
outReplyFailure() and inReplyFailure() are called for this invocation.
outRequest filter points in a client can add extra piggybacked data to an outgoing request bufferand this data will then be made available to the corresponding inRequest filter point on the server side. In addition, one of the `out reply' marshalling filter points on a server can add data to an outgoing replyand this data will then be made available to the corresponding inReply filter point on the client-side. At each of the four `out' marshalling monitor points, data can be added by using an appropriate
insert() method for the Request parameter, for example:
// Java
long l = 27;
...
try {
r.insertLong (l);
}
catch (IE.Iona.Orbix2.CORBA.SystemException se) {
...
}
This is the same insertion mechanism that is used in the DII (Chapter 19, "Dynamic Invocation Interface"). // Java
long j;
...
try {
j = r.extractLong ();
}
catch (IE.Iona.Orbix2.CORBA.SystemException se) {
...
}
Note that this is a subtle difference from the normal use of extract() for the Dynamic Invocation Interface, as described in Chapter 19, "Dynamic Invocation Interface". In the dynamic invocation interface, extract() is only used to determine the return value of an invocation. In particular, inout and out parameters are not obtained using extract(), but their values are instead established using the extractOutParams() method. In contrast here, extract() can be used to extract piggybacked data from an incoming request (or reply).
Care must be taken to correctly match the insertion and extraction points, as follows:
outRequestPreMarshal() matches inRequestPreMarshal()
outReplyPreMarshal() matches inReplyPreMarshal()
outRequestPostMarshal() matches inRequestPostMarshal()
outReplyPostMarshal() matches inReplyPostMarshal()
outRequestPreMarshal() must be extracted by inRequestPreMarshal(). Unmatched insertions and extractions will corrupt the request buffer and potentially cause a program crash.When only one filter is being used, its
outRequestPostMarshal() method can add piggybacked data that the corresponding inRequestPostMarshal() method, on the called side, does not remove. However this would cause problems if more that one filter was being used.
For example, it will be necessary to include the following code in
outRequestPreMarshal() and outRequestPostMarshal() (assuming the Request parameter is r):
// Java
// First find the server name:
String impl;
try {
impl = (r.target ())._get_implementation ();
}
catch (IE.Iona.Orbix2.CORBA.SystemException se) {
...
}
if (impl.equals ("some_server")) {
// Can add extra data.
}
else {
// Do not add any extra data.
}
The method _ObjectRef._get_implementation() returns the server name of an object reference (in this case, of the target object).A programmer should be particularly careful not to add data when communicating with the OrbixWeb daemon,
IT_daemon. The OrbixWeb classes may communicate with the daemon process, and programmers of filters should ensure that they do not pass extra data to the daemon.
Request, for example in order to display trace information about traffic between OrbixWeb applications. This information can be obtained by invoking the method getMessageLength() as follows:
// Java
int msgLen;
try {
msgLen = r.getMessageLength ();
}
catch (IE.Iona.Orbix2.CORBA.SystemException se) {
...
}
_bind()) and adds it to all requests at the server side. A server object can obtain the user name of the caller by calling the method:
// Java // in package IE.Iona.Orbix2.CORBA, // in class BOA. public String get_principal (IE.Iona.Orbix2.CORBA._ObjectRef oref) throws SystemException;on the
_CORBA.Orbix object. The first parameter, of type _ObjectRef, is not used and may be safely assigned the value null.The default authentication filter can be overridden by declaring a derived class of
AuthenticationFilter and creating an instance of this class. For example, an alternative authentication filter may use a ticket based authentication system rather than passing the caller's user name. On the client side, a derived
AuthenticationFilter class should override the outRequestPreMarshal() filter point. If this filter point alters the default behaviour, then the server-side authentication filter point inRequestPreMarshal() must be appropriately overridden in all servers with which the client communicates.
// IDL
interface Inc {
unsigned long increment(in unsigned long vin);
};
This may be implemented as follows:
// Java
public class IncImplementation
implements _IncOperations {
public int increment (int vin)
throws IE.Iona.Orbix2.CORBA.SystemException {
return (vin+1);
}
}
If we have two objects of this type created, as follows:
// Java
Inc.Ref i1, i2;
try {
i1 = new _tie_Inc (new IncImplementation ());
i2 = new _tie_Inc (new IncImplementation ());
}
catch (IE.Iona.Orbix2.CORBA.SystemException se) {
...
}
then we may wish to have pre and/or post filtering on, for example, the specific object referenced by i1. To achieve this, the programmer must define one or more additional classes and additional TIE classes.To perform pre-filtering, the programmer could define a class, say
FilterPre, to have the same methods and parameters as a normal implementation class of the corresponding IDL type, and which inherits from the generated class of the same name as the IDL type:
// Java
public class FilterPre
extends Inc {
public int increment (int vin)
throws IE.Iona.Orbix2.CORBA.SystemException {
System.out.println
("*** PRE call with parameter " + vin);
return 0; // Here any value will do.
}
}
Similarly, to perform post-filtering, the programmer could define a class, say FilterPost, as follows:
// Java
public class FilterPost
extends Inc {
public int increment (int vin)
throws IE.Iona.Orbix2.CORBA.SystemException {
System.out.println
("*** POST call with parameter " + vin);
return 0; // Here any value will do.
}
}
In the examples shown here, a per-object filter cannot access the object it is filtering. A filter can however do this by having a member variable which points to the object it is filteringand this member can be set up via a constructor parameter for the filter.To apply filters to a specific object, the following should be done:
// Java
// Create two filter objects.
Inc.Ref serverPre, serverPost;
try {
serverPre = new _tie_Inc (new FilterPre ());
serverPost = new _tie_Inc (new FilterPost ());
// Attach the two filter objects to
// the target object pointed to by i1.
i1._attachPre (serverPre);
i1._attachPost (serverPost);
Note that it is not always necessary to attach both a pre and a post-filter to an object.Attaching a pre-filter to an object which already has a pre-filter causes the old filter to be removed and the new one to be attached. The same applies to a post filter.
The methods
_attachPre() and _attachPost() return, respectively, the previous pre-filter and post-filter, if any, attached to the object. The methods _getPre() and _getPost() return an object's pre-filter and post-filter, respectively.To attach a chain of per-object pre-filters to an object,
_attachPre() can be used to attach the first pre-filter, and then it can be used again to attach a pre-filter to the first pre-filter, and so on. The same applies to post-filters.If a per-object pre-filter raises an exception in the normal way, then the actual operation call will not be made. Normally this exception is returned to the client to indicate the outcome of the invocation. However, if the pre-filter raises the exception
FILTER_SUPPRESS then no exception is returned to the caller1the caller cannot tell that the operation call has not been processed as normal.
In the example above, the same filter objects (those pointed to by
serverPre and serverPost) could be used to filter invocations to many objects. Other filters, for example a filter holding a pointer to the object it is filtering, can only be used to filter one object.21.4.1 IDL Compiler Switch to Enable Object Filtering
Per-object filtering can be applied to an IDL interface only if it has been compiled with the -F switch to the IDL compiler. By default, -F is not set, so object level filtering is not enabled.
FILTER_SUPPRESS exception can be raised as follows:
// Java import IE.Iona.Orbix2.CORBA.FILTER_SUPPRESS; import IE.Iona.Orbix2.CORBA.CompletionStatus; ... throw new FILTER_SUPPRESS(0, CompletionStatus.NO);