CLIPS CORBA NETWORK PROTOCOL
(CCNP)


David Maluf
Marcus Chan
Stanford University
maluf@cs.stanford.edu


About Clips Corba Network Protocol

The main motivation of this project is to extend the capabilities of CLIPS by including a CORBA agent. This agent is capable of getting interfaces of objects registered in any CORBA server and dynamically invoke operations on these objects. CLIPS users then can use all the objects and operations defined in other CORBA servers. Interesting applications can be resulted from this tool by using the expert system capability of CLIPS, such as generating knowledge and rules based on the information return from all the CORBA servers connected together. Programs that reason with these information can also provide sophisticated interoperation services.


Disclaimer

In no event shall Stanford university and David Maluf be liable to any party for direct, indirect, special, incidental, or consequential damages arising out of the use of this software and its documentation, even if the university has been advised of the possibility of such damage.

Stanford university and David Maluf specifically disclaims any warranties,including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The software provided hereunder is on an "as is" basis, and Stanford university has no obligation to provide maintenance, support, updates, enhancements,or modifications.

Because the program is licensed free of charge, there is no warranty for the program, to the extent permitted by applicable law. We provide the program "as is" without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk of using this software is yours.


Downloading the current OSF1 version: ccnp-osf1.tar.gz


Introduction

In the first glance, C Language integrated Production System (CLIPS) and Common Object Request Broker Architecture(CORBA) seem like totally unrelated technologies. CLIPS is a type of computer language designed for writing applications called expert systems[1]. An expert system is a program which is specifically intended to model human experise or knowledge. CORBA is a tool to make the building of distributed, heterogeneous, object-oriented applications easier. The only glue that can link them together is the object-oriented technology.

CORBA has become one of the most commonly used object standard in the industry. A lot of people are using CORBA and there are a lot of CORBA servers on the Internet. Through the Interface Repository and Dynamic Invocation Interface mechanism defined by CORBA, we can make a tool, which is also a CORBA program, to talk to unregistered CORBA server in the network it can talk to, retrieve all the object interfaces registered in the server, and make connections and invoke operations on it.

The main goal of this project is to extend the capability of CLIPS by including this CORBA tool into it. In this way, a CLIPS user can get all the interfaces of objects registered in a CORBA server by running specific commands in CLIPS. Based on those definitions, CLIPS can make these object definitions available for users to create local objects. The users can invoke operations on these objects and the tool can invoke operations on the remote CORBA servers on behalf of the user.

In this way, CLIPS users can use all the objects and operations defined in other CORBA servers without knowing any of these information beforehand. Interesting applications can also be devised from this tool by using the expert system capability of CLIPS, such as generating knowledge and using rules on the information return from numerous CORBA servers connected together. Also, as suggest in [4], programs that reason with these information can also provide sophisticated interoperation services.

In the following sections of this report, I will first give overviews for CLIPS and CORBA respectively, as well as the technologies in both areas that are related to this project. After that, I will talk about the implementation details. Finally, I will conclude with the present state of the project and potential enhancements.


Overview of CLIPS

CLIPS stands for C Language Integrated Production System. CLIPS is an expert system tool developed by the Software Technology Branch (STB) , NASA/Lyndon B. Johnson Space Center.

CLIPS is designed to facilitate the development of software to model human knowledge or experise. There are three ways to represent knowledge in CLIPS[1]:

- Procedural Knowledge,
- Declarative Functions,
- Object-oriented Model.

The generic CLIPS interface is a simple, interactive, text-oriented, command prompt interface.


CLIPS Object-Oriented Language

In a pure object-oriented programming (OOP) language, all programming elements are objects which can only be manipulated via messages. In CLIPS, the definition of an object is much more constrained: floating-point and integer numbers, symbols, strings, multifield values, external-addresses, fact-addresses and instances of user-defined classes. All objects may be manipulated with messages, except instances of user-defined classes, which must be. For example, in a pure OOP system, to add two numbers together, you would send the message "add" to the first number object with the second number object as an argument. In CLIPS, you may simply call the "+" function with the two numbers as arguments, or you can define message-handlers for the NUMBER class which allow you to do it the purely OOP fashion.

There are several predefined CLIPS classes already, with OBJECT being the root of it. The pre-defined classes inheritance diagram is shown in [1].

Integration with External Functions

CLIPS has been designed for full integration with other languages such as C and Ada. In addition to being used as a stand-alone tool, CLIPS can be called from a procedural language, perform its function, and then return control back to the calling program. Likewise, procedural code can be defined as external functions and called from CLIPS. When the external code completes execution, control returns to CLIPS. This integration with external functions is actually the core of this project.


Overview of CORBA

CORBA stands for Common Object Request Broker Architecture, part of the Object management Architecture (OMA) being specified by the Object Management Group (OMG). It is basically a tool to make the building of distributed, heterogeneous, object-oriented applications easier. The applications are distributed in the sense that the various objects are hosted across a network of computers, or even several networks connected by gateways; there is no implication that any one single object is distributed though. Heterogeneous means that the network(s) will contain a diversity of platforms, different hardware, different operating systems, different networking technologies. The implementation may use several programming languages. Data formats may be different (big-endian vs little-endian; floating-point formats; character set encodings) and complex data-structures may be stored differently (packed or unpacked).

The objects in applications will have to communicate with each other. Heterogeneity magnifies the difficulties of communication. The goal of CORBA is to smooth over these problems. It has also been called an Object Bus, a software equivalent to a computer's hardware bus.

CORBA provides a lot of functionalities and services. However, in this section, I will just talk about the three of them: Object Request Broker, which is the underlying mechanism that allows clients invoke methods on remote objects; Interface Repository, which is an on-line database of object definitions; Dynamic Invocation Interface, which allows the dynamic construction of object invocations. The Interface Repository and Dynamic Interface Invocation are actually the heart of this project.

Object Request Broker

This is the basic concepts of the CORBA ORB. A client program wishes to invoke an operation on an object; in CORBA terminology, to make a request. The object will often reside on a remote system, in a different hardware and software environment from that of the client. The request and the response both pass through the ORB, which is responsible for mediating all the differences between the systems. Specifically, the ORB must:
  1. Marshall arguments for the call, that is assemble them into the proper format;
  2. Locate a server for the object;
  3. Transmit the request, via RPC or sockets or some other mechanism;
  4. If necessary, create a process at the server end to handle the request;
  5. Unmarshall the arguments into the format required by the server process;
  6. Marshall the return values or exception information constituting the response;
  7. Transmit the response;
  8. Unmarshall the response at the client end.
The term ORB is used generically for any software accomplishing these functions.

Conceptually, invoking a method on a remote object can take the following path: the client calls the stub, which does some processing and passes the message on down to the ORB, more specifically the client ORB runtime. This communicates with server ORB runtime, which passes the message up to the server stub, which massages the message some more before passing it up to the server. The reutrn value takes the same route in reverse.

CORBA Interface Repository

The CORBA Interface Repository is an on-line database of object definitions. These definitions may be captured directly from an IDL-compiler or through the new CORBA Interface Repository write functions. CORBA specification details how the information is organized and retrieved from the repository. It does this creatively by specifying a set of classes whose instances represent the information that's in the repository. The class hierarchy mirrors the IDL specification. The reuslt is a highly flexible object database that keeps track of collections of objects organized along the same lines as the IDL. Of course, all the objects in the repositroy are compiled versions of the information that's in an IDL source file.

Using the information in the Interface Repositroy, it is possible for a program to encounter an object whose interfaces was not known when the program was compiled, yet, be able to determine what operations are valid on the object and make an invocation on it.

Dynamic Invocation Interface

An interface is also available that allows the dynamic construction of object invocations, that is, rather than calling a stub routine that is specific to a particular operation on a particular object, a client may specify the object to be invoked, the operation to be performed, and the set of parameters for the operation through a call or sequence of calls. The client code must supply information about the operation to be performed and the types of the parameters being passed. The dynamic invocation provides maximum flexibility by allowing new object types to be added to the distributed system at run time.


Implementation

The heart of the project relies on the bridge that links CLIPS and CORBA together. On the CLIPS side, it is using the capability of CLIPS that can integrate with external functions; on the CORBA side, it is using the CORBA Interface Repository and Dynamic Invocation Interface. In this section, we are going to discuss how we bring CLIPS and CORBA together, and other related issues.

External Functions in CLIPS

One of the most important features of CLIPS is an ability to integrate CLIPS with external functions or applications. All external functions must be described to CLIPS so they can be properly accessed by CLIPS programs. User-defined functions are described to CLIPS by modifying the function UserFunctions, which is in the CLIPS main.c file. Within UserFunctions, a call should be made to the DefineFunction routine for every function which is to be integrated with CLIPS. The user's source code then can be compiled and linked with CLIPS.

Three new functions are defined:

get-corba-interfaces:

This function is to get all the interfaces from the Interface Repository of a CORBA server, whose name is the parameter of this function. It will get the necessary information through calls to the Interfaces Repository and interfaces. Moreover, this function will then define all the interfaces locally in CLIPS. Although all the attributes and operations of the remote objects will also be put in the definition of the local objects, they are not used to store or retrieve values at the point. An example will be:
(get-corba-interfaces "whale")

where whale is the CORBA server name.

make-corba-instance:

This function resembles the make-instance function of CLIPS. The reason a new function is needed for making instances of CORBA objects is that a new infomation is stored also as an attribute in the local objects. This information is called CorbaObjectNum, which provides the mapping between local CLIPS objects and CORBA object references on the server. This will be more cleared in the example section 4.7. Also, the full interface will be put in a string, which is also stored as an attribute. This function takes two parameters: the instance name and the class name.

An example will be:

(make-corba-instance "bank" "bank1")

where bank is the interface name and bank1 is the name you want to give to the instance that is going to be created.

invoke-corba-operations:

This function actually makes remote function call to the objects resided on the CORBA server. It takes in the CorbaObjectNum, which provides the mapping between local CLIPS objects and CORBA object references on the server; the name of the operation that the user wants to invoke; and finally a multifield value. This multifield contains first, the return type; then if the return is OBJREF, the return new object instance name and class name; and finally a list of type/value pairs of parameters. Types can be OBJREF, SHORT, LONG, USHORT, ULONG, FLOAT, DOUBLE, BOOLEAN, CHAR, or STRING. This function will call the necessary CORBA functions to perform the operation dynamically.

An example will be:

 
(invoke-corba-operations 
	(send [bank1] get-CorbaObjectNum) 
	"newAccount" 
	(explode$ "OBJREF account account1 STRING marcus")
)

This will become more clear in the example section 4.7.

Interface Repository and Dynamic Invocation Interface Functions

Given an object reference, the object's type and all information about that type can be determined at runtime by calling functions defined by the Interface Repository. In particular, it can determine:

- the module in which the interface was defined, if any,
- the name of the interface,
- the interface's attributes, and their definitions,
- the interface's operations, and their full definition, including parameter, context and exception definitions,
- the inheritance specification of the interface.

In this section, we are going to briefly describe the steps in getting information from the Interface Repository. For detail information, please refer to the Orbix Advanced Programmer Guide[5].

Getting Interfaces from Interface Repository

In order to get information from the Interface Repository on a CORBA server, you must first bind to it. A reference to a Repository object can be obtained by binding to it as follows:

 
Repository::_bind(":IR", host, IT_X); // in C++

The structure of the Repository object is:

 
interface Repository: Container {
	Contained lookup_id (in RepositoryID search_id);
	exception invalidLoad();
	void loadIDLAll();
	void loadIDLFile(in string fileName)
		raises (invalidLoad);
};
After that, calling the inherited function

 
contents(in InterfaceName restrict_type, in boolean exclude_inherited)

returns the list of Interface Repository objects contained by the object, and can be used to navigate through the hierarchy of definitions. The first parameter is used to restrict the return type. In this tool, It is set to be "InterfaceDef" because we are only interested in all the interfaces registered in the Interface Repository. The second parameter is used to determine if inherited objects are returned or not. In this case, it is set to true to return inherited objects also. One nice thing about Interface Repository is that it will return all parent objects first before it returns the objects that are inherited from the parents.

The containment hierarachy of the Interface Repository classes can be found in [5].

Getting Information from InterfaceDef Objects

Because I have set the first parameter of the content call to be "InterfaceDef", so it will only return a list of InterfaceDef objects. However, these objects are returned as a pointer to the object. So, a call to the function get_interface is necessary to actually get the interface reference, of type InterfaceDef from the object. The structure of an InterfaceDef object is:

 
interface InterfaceDef: Container, Contained {
	attribute sequence RepositoryId base_interfaces;
	struct FullInterfaceDescription {
		Identifie name;
		RepositoryID id;
		RepositoryID defined_in;
		sequence fOpeationDescription operation;
		sequence AttributeDescription attributes;
	};
	FullInterfaceDescription describe_interface();
};

Subsequently, the function InterfacDef::describe_interface() can be used to get a description of its constants, typedefs, exceptions, attributes, and operations. This call will return a FullInterfaceDescription structure defined inside the InterfaceDef object as shown above.

The list of parent interfaces is stored inside the attribute base_interfaces in the InterfaceDef object.

The list of attributes, together with all of information related such as name, type, and mode are stored in the attribute attributes in the InterfaceDef object. The structure of an AttributeDescription object is:

 
interface AttributeDescription {
	Identifier name;
	RepositoryID id;
	RepositoryID define_in;
	TypeCode type;
	AttributeDef::AttributeMode mode; 
		// normal or readonly
};

The list of operations, together with all of information related such as name, return type, parameters, and mode are stored in the attribute operations in the InterfaceDef object. The structure of an OperationDescription object is:

 
interface OperationDescription {
	Identifier name;
	RepositoryID id;
	RepositoryID define_in;
	TypeCode result;
	OperationMode mode;
	sequence contexts;
	sequence parameter;
	sequence exceptions;
};

These are also ParameterDescription, ExceptionDescription, ConstantDescription, TypeDescription, and other strucutures to store information for parameters, exceptions, constants, types, and others respecitively. I am not going to describe them all here. For detail information, please refer to the Orbix Advanced Programmer Guide [5].

Putting Information into CLIPS

As I mentioned before, for all the interfaces registered in the Interface Repository of the server, the tool will define the interfaces locally in CLIPS. For those who are inherited from other classes, that is, the base_interfaces in the InterfaceDef object is not empty, the tool will maintain the inheritance relationship in CLIPS also. For those who are not inherited from other classes, the tool will put them under INITIAL-OBJECT in the CLIPS object hierarchy.

All the attributes will also be created under the definition of the local objects. However, I put a `.' before all the names of attributes. So, if the attribute is called "a1" in the CORBA interface, it will be called ".a1" in the local definition of CLIPS. It is to avoid problems because CLIPS has more reserved words. For example, the string "name" is a very common attribute in objects, but it is also a key word in CLIPS. The mode of an attribute can either be "read-only" or "read-write", the tool will maintain the same mode in the local object definition also.

There is a new attribute in every local object that correspones to a remote CORBA object. This attribute is called CorbaObjectNum, which is a mapping between a local object and a remote object. The use of it will be shown in the example section 4.7.

All the methods will be created in local object definitions under the same name as in the remote objects.

Please note that if an object with the same name has been defined in CLIPS already, then it will not be redefined again, not even under a different name.

Lastly, CLIPS supports fewer than data types than CORBA, so we make those data types in CORBA which are not in CLIPS to be mapped some other compatible CLIPS types. The mapping is shown here:

 
CORBA TypeCode  	CLIPS Data Type
tk_null	   		NIL
tk_void  		*no suitable type*
tk_short  		INTEGER
tk_long  		INTEGER
tk_ushort    		INTEGER
tk_ulong  		INTEGER
tk_float  		FLOAT
tk_double  		FLOAT
tk_boolean  		INTEGER
th_char  		SYMBOL
tk_octet  		*no suitable type*
tk_any  		multislot
tk_TypeCode  		INTEGER
tk_Principal  		*no suitable type*
tk_objref  		the object name
tk_struct  		multislot
tk_union  		multislot
tk_enum  		multislot
tk_string  		STRING
tk_sequence  		multislot
tk_array  		multislot

Note that multislot is not a datatype in CLIPS. It means it makes the attribute to contain more than one element, with each element can be of different data type.

Making Instance of CORBA Objects in CLIPS

After the tool gets all the interfaces from the Interface Repository of the CORBA server and defines them locally, it is ready for the user to create instances of the interfaces. More than one instance of the same object can be created and each of them actually has its own context. Therefore, there is a need for a place that can keep track all the references to all the CORBA objects created and there is a need for a way that can let each local instance of a CLIPS object that corresponses to a remote CORBA object to reference back the actual CORBA object to retrieve attributes and invoke operations. The way that I used is to have an array that holds all the CORBA objects created. There is also a variable called ObjectCount to keep track of the new available object number. So, the first CORBA object created will have an object number of 0, and the next one will have a number of 1, etc.

Invoke Remote Opeartions on CORBA Objects

The Dynamic Invocation Interface (DII) allows requests to be built up and invoked dynamically by clients. The client needs to know interface-related information only at the invocation time; no prior knowledge at compile time is necessary. A DII request, like a static request, is composed of an operation name, an object reference, and a parameter list. There are two ways to pass in parameters. The first is to construct a name-value list, which is then inserted into the request. The other way is to use the `<<` operator defined for the Request object in Orbix to `pipe' the parameter into the request, and it will take the type of the parameter variable as the type of this parameter. In this tool, the second method is used.

To construct the request in CLIPS, the user needs to supply a multivalued list in which the first value will be the return type. Next, if the return type is OBJREF, the second and third values will be the object type name and the new object instance name that will be created as the operation returns. Then the type and the value of every parameter will follow. Again, it will be more clear in the section 4.7 example.

Integrating CLIPS with C++

One of the difficult part of this project is to put those C++ functions and CLIPS together. CLIPS is actually written in C, so putting these C++ functions into CLIPS source code and having them to be compiled together require some special steps, because normal C++ functions cannot see function that are written in C, and vice versa.
  1. First, all the CLIPS code except main.c are compiled with a standard C compiler. Then we built a libClips.a library to store all the object files from these source files.

  2. Second, we compile the main.C and all the functions required to do the CORBA work in C++ compiler. In order to do that, basically we need to know which functions that are written in C in the CLIPS source code will be used by the files that are written in C++. This include main.C, which uses InitializeCLIPS, RerouteStdin, and CommandLoop; and other CLIPS functions that the CORBA tool uses.

  3. After finding all those function, we need to go to the .h files that have those functions declared and make changes over there. What we want to do is to tell the C++ compiler that the functions are interfaced with C, so I used the discriminator:
     
    		extern "C" {
    		}
    
    which tells that everything inside of the two brackets is in C object code.

Please refer to Appendix A for a list of the header files that needs to put the 'extern' around the function definitions.

4. Finally, we compile main.C, corba.C, with libClips.a, and the clips files with modified header files into a final running program.

Embedding CLIPS Functions

CLIPS is designed to be embedded within other programs. Many capabilities available in the interactive interface are available through function calls. The tool needs to use these functions to perform CLIPS functions, such as creating instances, define classes definition. However, not all the CLIPS capabilities have function call intefaces, for example, there is no API for define classes, define message handlers. We may have to write another function that can perform the needed work.

Example

The best way to show how to use this tool is through an example. Consider the following interfaces:

 
// a simple description of a bank account
interface account {
    readonly attribute float balance;
    void makeLodgement (in float f);
    void makeWithdrawal (in float f);
};

// a bank simply manufactures accounts
interface ir_bank {
    exception reject {string reason;};
    account newAccount (in string name) raises (reject);
    currentAccount newCurrentAccount (in string name, 
				in float limit) raises (reject);
    void deleteAccount (in account a); 
};
First, the CLIPS user needs to get all the interfaces from the CORBA server.

 
CLIPS> (get-corba-interfaces "whale")
"CORBA objects created successfully!"

This call is to get all the interfaces from the CORBA server "whale".

The user can then see the objects have been defined after this call by using the CLIPS browse-classes function.

 
  USER
    INITIAL-OBJECT
      account
		currentAccount
      ir_bank

Assume that only three interfaces are registered in the CORBA server. This shows that currentAccount is a sub-class of account.

Then the user wants to create an object of ir_bank.

 
CLIPS> (make-corba-instance "ir_bank" "bank1")
"Object created successfully!"

The name of the object supplied by the user is bank1.

Through the full description of the interface, which is also stored in the object, the user knows that there is a "newAccount" operations which will return an "account" object. The input parameter is a string.

 
CLIPS> (invoke-corba-operations 
	(send [bank1] get-CorbaObjectNum)  
	"newAccount" 
	(explode$ "OBJREF account a1 STRING marcus")
   )
"CORBA function invoked successfully!"
a1 as an instance of object account is created.

(send [bank1] get-CorbaObjectNum) is to get the index into the CORBA object array to get the object reference. "newAccount" is the operation the user wants to invoke on the object.

(explode$ "OBJREF account a1 STRING marcus") is to create a multifield value. This multifield stores the information of the return type of the operation and information about the parameters. OBJREF signifies that the return type of the newAccount operation is an object, which is of type account (the second value). The name the user gives to this return object is a1. There is one parameter, which is a STRING with value "marcus".

In order to check that the return account object really exists. The user can use the function instances to see the objects the user has created.

 
CLIPS> (instances)
[bank1] of ir_bank
[a1] of account
For a total of 2 instances.

This shows the bank1 object the user created explicitly and the a1 object, which is created as the call to function "newAccount" returned.

 
CLIPS> (send [a1] get-CorbaObjectNum)
1

This shows that a1 corresponds to the CORBA object 1 in the array of all the CORBA objects created. This is because bank1 takes the object number 0.

Next, the user sees that from the interface of "account", there is a makeLodgement operation.

 
CLIPS> (invoke-corba-operations 
	(send [a1] get-CorbaObjectNum)  
	"makeLodgement" 
	(explode$ "VOID FLOAT 12.34")
   )
"CORBA function invoked successfully!"

Again, (send [a1] get-CorbaObjectNum) is to get the object number of a1.

"VOID FLOAT 12.34" means that the return value is void and there is only one parameter with type FLOAT and value 12.34.

Lastly, the user can check if the balance has been changed by using the following command:

 
CLIPS> (invoke-corba-operations  
	(send [a1] get-CorbaObjectNum) 
	"_get_balance" 
	(explode$ "FLOAT")
   )
Result is 12.34
"CORBA function invoked successfully!"

The result "12.34" matches the lodgement the user made before.

Note that before executing the program, the user has no knowledge about the interfaces of the objects in the CORBA server and all the operations. The user only knows the host name of the CORBA server. All the CORBA operations are also performed remotely on the CORBA server dynamically.

Notes

There are some requirements needed for the operability of this tool: - Not that runtime information is available on the definitions in an IDL file only if the -R switch is specified to the IDL compiler when the definitions are compiled.

- To use the Interface Repository, programs that make calls to the Interface Repository must be linked with the IRclt library.

- The Interface Repository must be installed.

- The default timeout of a connection is 10 seconds. In normal situation, it should be adequate. However, this tool remains connected to the CORBA server after the user has made to first call to the objects. After 10 seconds, if the user wants to make another call to the server, it will fail. This is undesirable. We want user to invoke operations anytime as long as the user is still in CLIPS. Therefore the server must change the default connection timeout period by the following function:

 
unsigned long connection Timeout(unsigned long, Environment &env = default_environment);


Providing Interoperation Services

As described in [4], traditional object-oriented interoperation technologies rely on procedural interface specifications, which do not address the semantics of the operations supported by the object. Traditional approaches actually provide limited support for automatic interoperation in a dynamic environemnt. For instance, a resource that is available at compile time may not be available at runtime, or a better resource may become available at runtime. Implementing objects that interact in dynamic runtime environments is a difficult task. We need to develop more sophisticated system services that assist object implementors in dealing with incomplete knowledge. Consider the following situation taken from [4], as shown in Firgure 9, where a client would like to print a file in Microsoft Word format. There is no server that can handle the request directly, but there are two servers that, when used together, can satisfy the request. There is a server that can handle requests to print a PostScript file and another object that can translate a Word file to PostScript. Through the tool described in [4], the system has the ability to combine these services together to satisfy the request. This saves the user's burden to figure this out manually through trial and guessing.

 
interface PrintServer {
	void PrintPostscript(in file theFile)
}

interface WordServices {
	void TranslateWordToPostscript (in file wordFile, 
			out file postscriptFile)
}

A similar tool can be made in CLIPS also, whcih makes use of the expert system capabilities provided by CLIPS.

Exposing CLIPS in CORBA and Microsoft OLE

Right now, the connection is one-way, meaning that only CLIPS can make use of the CORBA environment to use services and interfaces exposed by other CORBA servers. CLIPS is designed to be embedded within other programs, so it is possible that CLIPS can expose itself to the CORBA environment to let other CORBA clients to use it as a service. It will have a lot of potential uses since not many expert systems support object-oriented concepts, not to mention that CLIPS is designed to be embedded within other programs, and also designed to support integration with external functions.

However, in order to make CLIPS a CORBA server, the CLIPS source code must be modified a lot because there are some rules and steps that the server needs to take in order to be a CORBA server. Things get more complicated here since CLIPS is actually written in C.

Another area of interests is to expose CLIPS into the Microsoft Object Linking and Embedding (OLE) environment. OLE is a unified environment of object-based services with the capability of both customizing those services and arbitrarily extending the architecture through custom services.

Adding Security and Access Control

The client/server environment introduces new security threats beyond those found in traditional time-shared systems. In a distributed system, you can't trust any of the client operating systems to protect the server's resources from unauthorized access. Even if the client machines are totally secure, the network itself is highly accessible. You can never trust information in transit. One can easily record traffic between machines and introduce forgeries into the system. Distributed objects even adds more complications into this picture. Because of encapsulation, you cannot fully understand all the interactions that take place between the objects you invoke. There is too much "behind the scenes" activity. Also, objects are so flexible that it is easy to replace one object on the ORB with another that abides by the same interfaces. This makes it a dream situation for Trojan horses. The dynamic power of CORBA such as getting interfaces dynamically and invoke operations on something that you only know at run time is a great strength of objects, but it could also be a security nightmare. Objects come and go, how do you make a security scheme dynamic and scalable enough?

Right now, CORBA does not really have a complete security implementation, and so our system does not have any security scheme now. Everyone can access the information provided by the Interface Repository. If the server has registered itself under the Information Repository, then everyone can access use its service. In order to make this tool useful in a real world, a complete authentication, authorization, and access control scheme must exist. Users can only access what they are supposed to access; information can only be exposed to those who have privilege to retrieve; users can prove their idendities to servers so that they can invoke retricted operations; and servers also have a way to prove their idendities to clients.

After fully security services are provided in CORBA, the tool must be modified to include all the authentication, authorization, and access control functions.

Testing in a Distributed World

Right now, both the CLIPS client and CORBA server sit on the same machine, due to the fact that we only have one CORBA license on one machine. An important future work will be to test the tool in a real distributed world so that CLIPS client and CORBA servers are from different machines. It will be interesting to do a performance analysis comparing putting them onto the same machine and distribute them in the network.


References

[1] Software Technology Branch, Lyndon B. Johnson Space Center, "CLIPS Reference Manual: Volume I Basic Programming Guide, CLIPS Version 6.0", 1993.

[2] Software Technology Branch, Lyndon B. Johnson Space Center, "CLIPS Reference Manual: Volume II Advanced Programming Guide, CLIPS Version 6.0", 1993.

[3] The DARPA Knowledge Sharing Initiative External Interfaces Working Group, "Specification of the KQML Agent-Communication Language", 1994.

[4] N. Singh, M. Gisi, "Coordinating Distributed Objects with Declarative Interfaces", March 1995.

[5] "Orbix Advanced Programmer's Guide", IONA Technologies Ltd., 1995.

[6] R. Orfali, D. Harkey, J. Edwards, "The Essential Distributed Objects Survival Guide", John Wiley & Sons, Inc., 1996.

[7] M. Weiss, A. Johnson, J. Kiniry, "Distributed Computing: Java, CORBA, and DCE", Open Software Foundation Research Institute, 1996.


Appendix A

List of the header files that needs to put the 'extern' around the function definitions.

argacces.h classcom.h commline.h cstrcpsr.h evaluatn.h expressn.h exprnops.h exprnpsr.h extobj.h inscom.h msgpsr.h multifun pprint.h prcdrpsr.h prntutil.h router.h scanner.h strngrtr.h symbol.h sysdep.h


Bug report and recommendations

Please send bug reports to David Maluf Also if you like to see more features in this program please let me know and I will look into it.