JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Remote Administration Daemon Developer Guide     Oracle Solaris 11.1 Information Library
search filter icon
search icon

Document Information

Preface

1.  Introduction

2.  Concepts

3.  Abstract Data Representation

4.  libadr

5.  Client Libraries

6.  Module Development

7.  rad Best Practices

When To Use rad?

How To Use rad?

API Guidelines

Target Audience

Legacy Constraints

Conservative Design

Component Guidelines

API Guidelines

Method Guidelines

Property Guideline

Event Guidelines

Module Location: Deciding between Proxy or Slave

Synchronous and Asynchronous Invocation

Duplication

Client Library Support

Naming Guidelines

Object Names

Case

Language-Specific Considerations

API Design Examples

User Management Example

A.  rad Binary Protocol

API Design Examples

Combining the tools described so far in this document to construct an API with a known design can be a challenge. Several possible solutions for a particular problem are often available. The examples in this section illustrate the best practices described in previous sections.

User Management Example

Object/interface granularity is subjective. For example, imagine an interface for managing a user. The user has a few modifiable properties:

Table 7-1 Example User Properties

Property
Type
name
string
shell
string
admin
boolean

The interface for managing this user might consist solely of a set of attributes corresponding to the above properties. Alternatively, it could consist of a single attribute that is a structure containing fields that correspond to the properties, possibly more efficient if all properties are usually read or written together. The object implementing this might be named as follows:

com.example.users:type=TheOnlyUser

If instead of managing a single user you need to manage multiple users, you have a couple of choices. One option would be to modify the interface to use methods instead of attributes, and to add a "user" argument to the methods, for example:

setUserAttributes(username, attributes) throws UserError
attributes getUserAttributes(username) throws UserError

This example is sufficient for a single user, and provides support to other global operations such as adding a user, deleting a user, getting a list of users and so on. You might want to give it a more appropriate name, for example:

com.example.users:type=UserManagement

However, suppose there were many more properties associated with the user and many more operations you would want to do with a user, for example, sending them email, giving them a bonus and so on. As the server functionality grows, the UserManagement's API grows increasingly cluttered. It would accumulate a mixture of global operation and per-user operations, and the need for each per-user operation to specify a user to operate on, and specify the errors associated with not finding that user, would start looking redundant.

username[] listUsers()
addUser(username, attributes)
giveRaise(username, dollars) throws UserError
fire(username) throws UserError
sendEmail(username, message) throws UserError
setUserAttributes(username, attributes) throws UserError
attributes getUserAttributes(username) throws UserError

A cleaner alternative would be to separate the global operations from the user-specific operations and create two interfaces. The UserManagement object would use the global operations interface:

username[] listUsers()
addUser(username, attributes)

A separate object for each user would implement the user-specific interface:

setAttributes(attributes)
attributes getAttributes()
giveRaise(dollars)
fire()
sendEmail(message)

Note that if fire operates more on the namespace than the user, it should be present in UserManagement where it would need to take a username argument.

Finally, the different objects would be named such that the different objects could be easily differentiated and be directly accessed by the client:

com.example.users:type=UserManagement
com.example.users:type=User,name=ONeill
com.example.users:type=User,name=Sheppard
...

This example also highlights a situation where the rad server may not want to enumerate all objects when a client issues a LIST request. Listing all users may not be particularly expensive, but pulling down a list of potentially thousands of objects on every LIST call will not benefit the majority of clients.