one€¦  · web viewif a single word could characterize the life of a programmer living in the...

51
One.box – Universal Inbox System Albert Wong ([email protected] ) Boris Stratsev ([email protected] ) Daniel Cheah ([email protected] ) Ian Shafer ([email protected] ) Sherif Fanous ([email protected] ) Computer Science And Engineering Department University Of Washington 1 - Abstract With the rapid development of high-speed networks and the increase in processing power available to common household appliances, it is likely that we will soon see the emergence of home networks that combine various services, thereby increasing their usefulness. Our goal was to write a distributed and pervasive service for such a home network that would provide users not only with the ability to use and administer the services on their network, but also give them a reliable and convenient remote access to said services. This paper delves into the design and implementation of the application, which was developed by two teams. One team used Java together with outside distributed computing technologies such as Jini and T Spaces, while the other team implemented the application within one.world, a pervasive computing architecture being developed here at UW CSE. 2 - General Introduction Given the current trend of technology, there are more and more devices that are network enabled. Devices such as laptops, palm pilots, printers, refrigerators, or anything that perhaps may find a use for sending information to other electronic devices are being made network aware. These “endpoints” of a network provide and subscribe to different services allowing a higher order of integration between different electronic components.

Upload: others

Post on 14-Jul-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

One.box – Universal Inbox SystemAlbert Wong ([email protected])Boris Stratsev ([email protected])

Daniel Cheah ([email protected])Ian Shafer ([email protected])

Sherif Fanous ([email protected])

Computer Science And Engineering DepartmentUniversity Of Washington

1 - AbstractWith the rapid development of high-speed networks and the increase in processing power available to common household appliances, it is likely that we will soon see the emergence of home networks that combine various services, thereby increasing their usefulness. Our goal was to write a distributed and pervasive service for such a home network that would provide users not only with the ability to use and administer the services on their network, but also give them a reliable and convenient remote access to said services. This paper delves into the design and implementation of the application, which was developed by two teams. One team used Java together with outside distributed computing technologies such as Jini and T Spaces, while the other team implemented the application within one.world, a pervasive computing architecture being developed here at UW CSE.

2 - General IntroductionGiven the current trend of technology, there are more and more devices that are network enabled. Devices such as laptops, palm pilots, printers, refrigerators, or anything that perhaps may find a use for sending information to other electronic devices are being made network aware. These “endpoints” of a network provide and subscribe to different services allowing a higher order of integration between different electronic components.

Think about a modern household and how many different electronic devices can be found within – televisions, VCRs, alarm clocks, cell phones, sprinkler systems, lights, etc. A productive association of all these devices may be a wonderful vision, but there is still something wrong with this picture: the user’s actions are bound by his physical location.

“So what?” one might ask, “Why would I concern myself with control of the resources in my house if I am currently away from it?”

Though, as with most things, the issue is not life-critical. Remote access to the resources available in one’s house through some commonly available medium could be a matter of great convenience and comfort. For example, while on vacation or a business trip, have you ever wondered if you remembered to turn off the oven? What about the security system – have you armed it? The chances are you forgot to turn down the heat… but the plane is leaving and it’s too late now. Well, with one.box installed on your home network, settling your fears or correcting your mistakes would be as simple as sending an email.

Page 2: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

3 - Design Document

3.1 Requirements OverviewThis section provides an overview of the basic functionality of the services of the one.box network.

3.1.1 one.boxOne.box will allow users to use email in the normal fashion and control services registered with one.box. Users will have full access to the capabilities of the one.box network including the ability to administer devices and set up access control.

3.1.2 Email ServiceA user can set this up to check his various existing email addresses for email. This allows any existing email accounts to be integrated into the one.box network.

3.1.3 Refrigerator ServiceThe refrigerator service will simulate a futuristic refrigerator. It’s abilities will include composing a shopping list based on the types of items currently in the fridge versus the types of items the user would like to have available at all times.

One.box will allow users to use email in the normal fashion and control services registered with one.box. Users will have full access to the capabilities of the one.box network including the ability to administer devices and set up access control.

3.2 Requirements DetailsThis section describes in greater detail the goals we have set and touches briefly on the reasons behind these goals.

3.2.1 StorageOne.box services need storage. Since this will be a fairly common requirement and it is a fairly complicated resource to manage, one.box will provide a core storage service.

The storage service will allocate storage to any service that makes a request for it. After the storage space is allocated, its use should be transparent to the registered service. This will simplify the creation and implementation of services capable of taking advantage of one.box storage.

If the user has more than one physical storage device available on the network, it presents an opportunity to improve the reliability of our system. To take advantage of this, our storage service will support replication of data.

With replication comes the problem of synchronization. To deal with this problem, one.box will assume eventual consistency. This will be tolerable on a one.box network because if one’s data (e.g. email) is not always completely synchronized, it is acceptable. This is based on our assumption of not having critical tasks and that data is read-only.

The storage service will be required to store data for services. It is not responsible for defining the internal structure of the stored data.

3.2.2 Messaging

Page 3: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

Within the one.box system, there are two general types of messages that will be used to communicate with the system. The first are human readable messages, whose intended recipients are people. The second are control messages, which will be received by services that will in turn interpret and perform an action based on the message.

A client is a standard email client available today (e.g. pine, outlook, emacs). These clients communicate to the various mail servers around the Internet via the SMTP and POP3 protocols. For these clients to communicate with one.box, they will send email to various email addresses that have been registered with the one.box email service. In addition, using XML, a sufficiently skilled user will be able to send control messages to the one.box system. In order to ensure that one.box is secure from the dangers of the outside world, it will authenticate the control messages that it receives from clients. In addition, one.box will be using access control lists that can restrict what a control message can do based on its source. This provides ubiquitous access to all the email and all applicable services a user has.

To handle service outages within the one.box network, if the recipient of the message is unavailable when the message arrives, something should be done to ensure that the recipient receives the message when it rejoins the one.box network (e.g. put the message into some well known space that a service looks at when it becomes available again).

3.2.3 Email ServiceUsers will register the email accounts that they wish to have monitored with the email service. Collecting messages involves polling the registered email accounts for new email messages and putting them into storage provided by one.box. The email service will also need to handle the email accounts of multiple users and ensure that email remains private to the user.

3.2.4 Refrigerator ServiceThe fridge will be expected to process incoming control messages, and if necessary reply to the specified users. The primary request for the refrigerator is the grocery list request.

The fridge will then check its state, compose a list accordingly and finally send the list to the specified user.

3.3 - ComponentsThis section lists the main components of a one.box network.

3.3.1 LookupThe lookup component allows any service entity joining the network to identify and locate published services on the network. When an entity joins the network, the lookup component will check to see if the entity is currently registered with the network. If not, the lookup component will determine a Globally Unique Identifier (GUID) and assign it to the entity. Having an assigned GUID, the entity can now be uniquely identified by other entities on the one.box network.

3.3.2 StorageSince most entities will require some amount of reliable storage for data, environment, state or whatever else, the one.box network aims to provide a transparent storage service for all entities.

Page 4: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

Currently, storage is to be implemented as a tuple store that looks and acts like a file system with tuple storage space for each registered service. Following conventional Unix-style directory notation, the organization can be thought of as: “/service/<unique id>/<stored tuple>” where “/” is the root of the filesystem and “<unique id>” is the specific tuple store in storage for an entity. In addition, the users will be allocated space structured as “/<one.box user id>/” in order to provide storage for personal services.

The interface to the storage system will consist of the following methods: put, get, find, delete. Find will search using a description based on the type of data searched for.

As for reliability, since this is a transparent interface, it is possible to implement replication, or other forms of backup without affecting interaction with other components.

Also there is a problem of wasted storage space. For example, the user buys a toaster, but returns it to the store the next day (after adding it once to the network); the storage space allocated to the service will remain indefinitely – a rather unfortunate side effect of storage transparency. We could, of course consider reclaiming allocated storage space when the service goes off the network. However, in a dynamic environment, such storage would be useless: the information would be lost every time a connection breaks down or is temporarily disconnected. Our solution to this is long-term leases. A service would lease storage for a certain number of days (let’s say a month) and try to renew that lease every 24 hours. If the lease expires, the space will be reclaimed.

3.3.3 FilterSince one of the main transport methods for one.box is e-mail, a filter component is required to process incoming e-mails and determine whether or not they are regular messages or one.box control messages and store them in the proper storage location for e-mail and send them to the router if they are control messages.

3.3.4 RouterThe router will be responsible for delivering control messages to the intended service. Messages will enter in XML format and be sent in to the service as an RPC. If the service is unavailable, the router will write the message to the storage space allocated to the destination service.

3.3.5 POP3This will a standard POP3 server.

4 - Case Study 1: The Jini Based System

4.1 IntroductionIn this section we’ll describe our implementation of one.box using Jini and related technologies such as Remote Method Invocation (RMI) and IBM’s TSpaces.

Jini is a set of APIs and runtime conventions that facilitate the building and deploying of distributed systems. Jini provides "plumbing" that takes care of common but difficult parts of distributed systems.

Jini consists of a programming model and a runtime infrastructure. By defining APIs and conventions that support leasing, distributed events, and distributed transactions, the

Page 5: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

programming model helps developers build distributed systems that are reliable, even though the underlying network is unreliable. The runtime infrastructure, which consists of network protocols and APIs that implement them, makes it easy to add, locate, access, and remove devices and services on the network.

Remote Method Invocation (RMI) enables the programmer to create distributed technology-based applications, in which the methods of remote Java objects can be invoked from other Java virtual machines, possibly on different hosts.

TSpaces provided our network storage backend. TSpaces stores Java objects inside tuples and alows service to persistently store and share any serialiazable Java object.

4.2 General FeaturesAll one.box core services are implemented as Jini Services. We followed the process of implementing a generic interface and then implementing it with an RMI proxy. This frees the interface from a dependence on RMI and allows further additions to the one.box network to use different techniques to implement their services such as using CORBA. Although we did leave space so that future additions can use any available technology we chose to use RMI as the messaging protocol between our services as we thought it was the most convenient mechanism available to implement a remote service.The system depends on the availability of a lookup service, which services register themselves to and clients query to find services they need. We used Sun’s implementation of a lookup service called REGGIE.

4.3 Services

This section will give a detailed description of the services that constitute the one.box system.

4.3.1 Setup ServiceThe Setup Service is basically the user interface that users use to communicate with their one.box network. Naturally users would want to set up their working environment only once but still have the ability to introduce changes as time passes. The ideas of setup once lead to the development of the Setup service. Through this service users can register with the one.box network, and add, update and delete email accounts to be collected by the POP3 client discussed below. The reason why this service was implemented as a Jini service is to give the users the ability to change their account status from almost any place where there is network connectivity.

Each user has only one setup tuple, which stores the following information: the user’s one.box username and password together with all the email accounts information the user has registered with the one.box system. Once the users have setup up their environment the setup file is passed to the core storage service where it is stored permanently until the users decided to update it.

To perform any of the setup operations a simple GUI interface is provided to the user. A specialized class called the LinkerService whose function is to abstract the logic from the GUI appearance carries out the operations of the GUI. Thus any change in account status takes place in the LinkerService, which communicates with storage to store the information.

JavaDocs can be found at http://www.cs.washington.edu/education/courses/490dp/01wi/one.box/javadoc/index.html

Page 6: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

User performs any of the setup operations from any place with network connectivity. The LinkerService carries out the operation of locating the storage service and performing the required actions.

4.3.2 POP3 ClientThe POP3 client is one of the core services in one.box. Its job is to collect emails from all email service providers that the user has registered with the one.box software. From its name it is obvious that it uses the Post Office Protocol – Version 3 (POP3) to communicate with the email service providers.

On startup the POP3 client registers itself with all available Lookup Services. It then waits for the user to add new email accounts to be collected. Once the user has added, deleted or updated an email account, the LinkerService triggers a remote event to notify the Pop3 Client of the change. In case of an addition a new thread is started that carries out the task of collecting the emails from the account’s INBOX. This process includes contacting the POP3 server, authenticating the user and then grabbing the emails. When the thread is done with collecting the emails, it passes them to the Router and then sleeps for at least 2 minutes before attempting to repeat its task. In case of an account deletion the responsible thread is stopped. Lastly for an update the responsible thread is stopped SAFELY then restarted with the updated information.

Page 7: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

POP3 Client collects emails and passes them to the router

Naturally if the POP3 Client crashes then all email collection stops. However when the POP3 Client recovers RMID will automatically reactivate it and a new thread will be started for every registered email account.

The POP3 client passes the emails to the router through an intermediary service that is an implementation of Sun’s TaskManager. The functionality of this service is to prevent the POP3 client thread from blocking until the router has accomplished its task. This is done by passing the emails to this intermediary service, which starts a new thread that is responsible for finding the router. The idea here is to protect the POP3 client thread from misbehaving router services. The intermediary service passes the emails to the router, or in the case where it cannot find a router, which would indicate that the router has crashed it places the emails in storage, so that the router can find them once it recovers.

For the router to be able to function correctly it expects the POP3 client to pass it the emails messages together with the body of every email. The contents of the body are the means through which the router can decide whether the email in question is a human readable email or a control message. Thus the POP3 client parses every email message header looking for important email fields such as the From, To, Date and Subject fields It also parses out the body to be used by the router.

4.3.3 Router ServiceThe router accepts an RPC call, which passes it an array of Email Messages. The function then loops through the array, enquires each message onto the MessageQueue, and adds a delivery task to the TaskManager, which is Sun's implementation of an animator. The delivery task decrypts the message (not implemented), checks if it is a control message and then delivers it.

Page 8: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

If the message is a control message, it is parsed until the service ID of the recipient service is extracted. The router then searches the lookup services for the service with the desired service ID. If the service is located, the router calls that service's function acceptMessage, as specified by the OneDotBoxInterface and passes the EmailMessage as a parameter. If the service is not located or the RemoteException is thrown by the service, the router appends the message to the list of messages in the undelivered file located in the appropriate storage directory.

If the message is not a control message, the delivery task for that message is to store said message in the inbox of the user that owns the account from which the message has been retrieved.

Router passes control emails to the intended service and stores human readable email in storage

Also the router periodically polls the storage to see if there are any messages that could not have been delivered to the router and were stored as undelivered. If there are any such messages, the router retrieves them and processes them as it would messages passed to it by a normal invocation.

The original design of the router called for a single thread per router invocation to perform all routing and delivery functions. So a new thread would be started due to RPC call and would completely process and deliver all messages in the passed array. The advantages here are that the router uses the absolute minimum number of threads it requires and no additional work needs to be done. However, the obvious disadvantage of such implementation is that anything using the Router (typically the POP3 Client) would be blocking until the Router has finished delivering the entire batch of emails. Though our system is not intended to be time-critical, this kind of design would be unnecessarily

Page 9: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

wasteful. What's worse is that the router communicates mostly with the services that are not part of the framework. We assume that the services using the one.box framework are not malicious, but we can't assume that they will function properly. Therefore, the design should be such that it minimizes the possibility of the entire network being rendered inoperable by a carelessly programmed service. Two solutions appeared to be available for this problem.

Asynchronous communication would eliminate the problem of being blocked by a service so the use of events for message deliveries became the primary candidate for the new router design. However, this presented a new set of problems. Exception handling, for instance, became more difficult. It would require services that threw an exception to do it in a form of an event. The event would have to either contain the original email message or it would be necessary for the router to somehow retain the message long enough to make sure that it is able to handle a thrown exception. Also, if the service is no longer connected to the network, it would not receive the event nor would it throw an exception. Such a service then would require an event mailbox. In fact, it seems that a more preferable option would be to always place messages into the storage and only send events to services to let them know that they have a new message. However, all this speculation came to an end when we discovered that the events in Jini were not truly asynchronous events but were merely simulated by callback functions. Thus, even if the router "sent out an event", it could still be blocked.

Alternative solution was to use an animator to take care of message delivery. This would minimize, but not avoid the chance of router being brought down by bad services. Furthermore, this design provided us with a convenient way to add periodic storage polling for the messages that might not have been delivered to router due to network problems. This was accomplished by creating a daemon thread whose job is simply to sleep for a specified amount of time and then add a StoragePolling task to the animator. The StoragePolling task causes the thread executing it to get the array of email messages from storage and pass it to processMessage function, which, of course, process the array as if invoked normally by a POP3 Client. One of the benefits of the design is that it became easier to add the functionality to the router – adding some logic to the run function of the daemon and creating appropriate tasks to be enqueued onto the animator could be a way implement many different changes.

4.3.4 Storage ServiceStorage is as simple as put, get, take, and update plus a couple of lease and lock methods. Clients of storage simply put tuples into storage and get them out by either reading them (storage returns a copy and keeps the tuple in storage) or taking them (storage returns the tuple and removes it from storage). Clients are encouraged to use the Storage Manager component as described below to handle all storage tasks.

Storage uses TSpaces. TSpaces is a network tuple storage backend provided by IBM. A TupleSpace is allocated for each "directory" in the storage service. Each directory stores some number of tuples. The tuples are indexed by name except in the case of email, described below.

A TupleSpace cache was implemented to make directory access fast. The cache implements a strict least recently used (lru) replacement policy. When a request to storage comes in, the directory is extracted from the path and that TupleSpace is requested from the cache. If the cache contains the requested TupleSpace the timestamp

Page 10: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

is updated and the TupleSpace is returned. If the TupleSpace is not in the cache, it is added to the cache and if the cache is over its size limit, the lru TupleSpace is removed.

Storage space is leased. The maximum lease time given to a tuple is 30 days. When a lease runs out, storage may or may not remove the tuple from the TupleSpace. Storage supports two methods for handling leases: getLeaseTimeRemaining() and renewLease(). Both these methods take the path of the tuple to query. renewLease() also takes the amount of time to renew the lease for. The Storage Manager component handles all this transparently.

Tuples in storage can be locked using the lock(), renewLock(), and unlock() methods. A lock can be granted for up to one minute. By setting a timeout on the locks, a client that holds a lock and terminates while holding that lock, will not block access to that tuple forever. Locks can be renewed as many times as the client wishes, as long as the client is alive to renew the lock.

Email StorageEmail storage uses the same TSpaces that storage uses. Its purpose is to enable specialized access into storage to facilitate handling email storage.

Emails are different than other tuples that are stored in storage because they are not named, and are referred to by their message number. Emails for a user are stored in a single directory (TupleSpace). This directory contains a sub-directory ordered by message number containing references to the corresponding email tuples.

Methods supported by email storage are put, get, and delete email tuples. Also implemented are methods to support the POP3 commands top, stat, and list.

Email storage is not leased, it will only be removed if the user specifically deletes it.

Storage ManagerThe storage manager takes care of storage for clients that require the storage service. By using the storage manager, clients do not have to worry about renewing leases or whether storage is up or not. The storage manager supports the same interface as storage, so it can be used transparently.

The storage manager maintains a list of the tuples whose leases need to be renewed. This list is added to when a tuple is put into storage via the storage manager. Storage manager spends the majority of its time in a sleep state. It is only woken up when it is time to renew a lease, or when a tuple has been added and its lease renewal time is earlier than the lease that the storage manager is currently waiting on.

Tuples are removed from the list of files to manage when an tuple is taken out of storage.

4.3.5 POP3 ServerThe POP3 server is a generic POP3 server. It supports all required POP3 commands and the optional top, apop, and uidl. The POP3 server interfaces with email storage.

4.3.6 Fridge ServiceThe fridge component abstracts a real fridge. It stores it contents persistently in storage, and in the event of a crash, will read its contents from storage when it starts back up again. The fridge can generate grocery lists according to a preferred contents list (the

Page 11: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

preferred items to have in the fridge). The preferred contents list is also stored in storage. The fridge is accesed via a fridge GUI that allows one to set the prefered contents, add items to the fridge, take items out of the fridge, and chang the amount of an item in the fridge (eat some of it).

4.3.7 Overall System Diagram

Under Normal Operation

Page 12: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

Router Down. POP3 Client stores emails in router’s undelivered space

Page 13: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

Router Recovers. Collects undelivered emails then resumes normal operation

4.4 Overall Evaluation And ExperiencesDuring our development we ran into several interesting situations. We discuss these situations here. At the beginning we had problems understanding the Jini infrastructure and what the core services provided by Sun exactly did. The role of RMI was somewhat ambiguous and confusing especially when it came to understand what exactly was passed to the client requesting a service and how the client got the stubs and from where it got them. Next starting the services provided by Sun wasn’t as easy as one would imagine. Command line arguments are long and tedious and it took us about a week to figure out how to start all the services correctly.

The use of multicast presented some interesting findings, we saw Jini services from all the over the place as shown in the figure below:

Page 14: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

Running out of memory was a big problem we encountered whenever we tried to start several services on 1 machine. We would get lots of OutOfMemoryException after starting around 3 or 4 services. Fortunately this problem was caused by the memory hogging nature of Jini services; it was not a consequence of memory leaks in our code, yet it took quite a while to figure that out.

Once we got a hang of Jini and understood what happens under the covers, converting normal services to Jini services came out to be nothing more than adding a few lines of code that would register the service with the Lookup service, the same ease was experienced when a client was looking for a service. This was one of the major advantages we found in Jini, as it didn’t require that much thought or change in the code.

Because of Jini’s synchronous nature we opted to use the TaskManger class provided by Sun to avoid our services from blocking on remote method calls. The problem with synchronous calls is that a misbehaving service could cause one of our core services to block forever.

Remote Events were very useful in Jini. They allowed the lookup service to notify clients of the appearance of services. For Example if a client was looking for the storage service but the storage service had crashed, the client would not be able to find the storage service. Through remote events, the lookup service would notify the client when the storage service recovered and reregistered itself with the lookup service. Remote events provided a mechanism to perform callbacks. When the setup file changed a remote event was passed to the POP3 client, which would react according to the nature of the event.

Some of Sun’s decisions were incomprehensible. For example the ClientLookupManager class, which was in the net.jini.lookup package, was fairly buggy, it would hang if there were two matching services running when the client started. Sun’s solution was to change the class name to ServiceFinderManager and place it in the same package. However this was only a change of name not a change of implementation!! The other striking discovery was the unavailability of any documentation concerning the TaskManager and ReliableLog classes. At the beginning we thought these classes had been removed from the Jini specification and decided to implement our own classes. Thankfully a month after thinking the classes had disappeared, while looking through the source code provided by Sun we came across both the classes!! The only reasonable explanation for having no documentation provided is that both classes are not part of the Jini specification, despite their importance.

Page 15: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

Last but not least Activation turned out to be more involved than originally anticipated. Because most of the one.box core services would be inactive only for short intervals, it was not worth using LeaseRenewalManager and LookupDiscoveryManager. Instead we had hoped to use activation as a means of improving the reliability of the one.box network, as it would restart crashed services. However it turned out that RMID doesn’t seem to re-activate a particular service more than once per RMID session. That is, a crashed and re-incarnated service would not be re-incarnated again unless RMID restarts. This behavior has been observed when running Reggie as well as our own services. A Sun employee has later duplicated this problem, confirming that it is a bug in RMID (when running on Linux, according to him). Per his suggestion, we started using Java 1.3.1 beta. However, that version has proved to have its own problems and, since these new problems were unpredictable, we have returned to using 1.3.0, preferring known and consistent failures.

Hours Lines Lines/Hours524 3727 7.1

5 - Case Study 2: one.world5.1 IntroductionThe second case study involves the implementation of the one.box system using the one.world framework (from which the name “one.box” originated). One.world is an experimental research framework for building distributed systems being developed at the University of Washington. It differs from the Jini mentality mainly in that it imposes many more restrictions on the programmer in hopes of allowing for a simpler, but more full featured API.

Because one.world is still under development, the implementation of the one.box system under this framework had to deal with issues of changing interfaces as well additions of new features and bug fixes during the course of implementation. This dynamic nature of working with a development framework had a fairly large influence on design decisions of one.box under one.world as new features that arose during the development made obsolete some design decisions that were based on the assumptions of missing features or bugs in code.

Also, being one of the first project to use the one.world interface, there lacked a standardized design philosophy for component creation and interaction. Thus, one of the largest battles in the implementation of the one.box was coming up with consistent patterns of design. Whereas in Jini, one would write a component as a standard Java object and then “Jinify” it, under the one.world framework, there was no such pattern and code designs morphed from pattern to pattern eventually necessitating a mid-implementation refactoring of the main component hierarchy. The resulting design and motivations for their creation are presented below.

5.2 Component OverviewBefore getting into the design issues, the final component breakdown should be reviewed as it is slightly different from the original design specification as well as the resulting design by the Jini team.

Page 16: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing
Page 17: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

5.2.1 Pop3The Pop3 component is actually what is known as a SubComponent (see 5.10.3 SubComponent) and thus is meant to be run by other components. It’s purpose is to implement the pop3 protocol and facilitate pop3 connections from inside the one.box network to the outside world. The main issue with the Pop3 sub-component is that has to translate between the outside world and the one.box network. However, since this transition is from a synchronous environment to an asynchronous environment, this is not too difficult. The Pop3-Server component which goes the other direction (asynchronous to synchronous) has many more problems with this issue.

5.2.2 MonitorThe Monitor is responsible for querying the various e-mail accounts that have been registered from the system and downloading the e-mail from them. It then passes on this information to the Filter for sorting.

First, the Monitor authenticates itself with the Auth component. Then it retrieves the list of e-mail accounts and passwords from Auth and begins to download mail using the Pop3 sub-component. It then acts as a double-blind intermediary between the Pop3 sub-component and the Filter. This allows for implementations of other protocols as sub-components which can be used by Monitor for collecting e-mail unbeknownst to Filter.

5.2.3 AuthThe initial design was to have Inbox contain authentication information. This however made management of sensitive information difficult, as it would mean that the data would distributed over the entire network.

Auth was introduced to simplify this. Its main task is to be a repository of authentication information for the system including passwords and other information that may be required for communicating with the outside world.

Eventually it may also serve to authenticate services that come online by implementing some form of the Kerberos authentication scheme. In addition, it is also hoped that communication with Auth will eventually be done over communication securing technologies like SSL.

5.2.4 StorageThe Storage sub-component is an abstraction for the idea of a tuple store. The eventual idea is that the Storage sub-component could serve as an interface to different forms of replication and secure data (like a RAID cluster or some other form of backup) and that one could link in whatever form of data-security technology one desired without components knowing about it – it serves a purpose like monitor in that way. Currently, it just wraps SioResource.

5.2.5 FilterThe Filter component takes an e-mail message as an input, determines if it is a human readable message or a control message meant for a component and dispatches it accordingly. The filter uses perl regular expressions to parse mail headers and thus it has the capability to load a bunch of filtering rules and do something similar to procmail. It keeps a list of inboxes sorts into each inbox according to a given set of rules.

5.2.6 Router

Page 18: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

The Router is responsible for taking a control message, finding the service that it was meant for and sending it off to that service.

In effect, the router is really a simple version of the filter. The original motivation for breaking the Router and Filter into two separate components was that Discovery was not available and was not projected to be available during the quarter. However, Discovery was added to one.world release 0.4 and this component was greatly simplified.

5.2.7 InboxThe Inbox component serves as the endpoint for user data. Currently it only stores a user’s email, but it could potentially be used for any used for any form of user data in the system. It differs from Auth in that Auth is meant to only contain sensitive information.

Inbox was designed with the idea of clustering in mind. It is possible to start up multiple Inboxes for a single user and use this to implement some form of data replication above Storage itself. This could be useful if one were to want to run multiple inboxes on different networks to provide continuous connectivity if an Inbox node failed.

5.2.8 Pop3-ServerThe Pop3-Server is the interface for getting e-mail from the Inbox. It is meant to allow any e-mail client to be able to access and control components in the one.box network.

The Pop3-Server was the most complicated component in the one.box core component set. The reason for this was that the pop3 protocol is a synchronous protocol and the one.world interface only allows for asynchronous events. There was no association between two requests from the same connection.

5.2.9 Mover/WatchDog (not implemented yet)Robert Grimm gave the original idea of the Mover component. This component would enable services to move and be moved around a network. The hope was to use this to make services mobile. As an extension of this idea, at regular intervals, services will checkpoint themselves. The checkpoints will be stored both on the service local node as well at the Watchdog service. The watch dog will monitor the health of the system and if necessary bring the latest checkpoint of the service up on another node thus providing a service similar to Activation in Jini.

5.3 On coding, patterns and general life in one.world If a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing a component, it is already a noticeable that a huge overhead is required for just making a component talk with the surrounding one.world environment. Upon the attempt at writing another component, it becomes very obvious that most of the code is exactly the same except for a word here or there.

If it becomes possible to write ComponentA, copy ComponentA.java to ComponentB.java, do a global search and replace, thus finishing 75% of the code bulk for ComponentB, something is really wrong. If they are that similar, why repeat it? If Java can be converted to C# with a global search and replace, what’s the point of C#.

Much of the internal design was centered around building a framework to prevent unnecessary code repetition, allow for more easily maintainable policies of component

Page 19: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

interactions and attempt to retard the progression of Daniel and Albert’s respective RSIs (Repetitive Stress Injuries).

5.4 Component Hierarchy5.4.1 ConceptionThe first, largest and most complete attempt at a resolution to this was the component hierarchy written by Daniel. The initial goal of this hierarchy was to avoid the coding overhead associated with registering a one.world object with its associated environment. Some of this code was already being automatically generated by the Skeletor utility provided with one.world. However, upon inspection, it becomes apparent that the Skeletor is basically a fancy cut/paste followed by a global replace. If code is that similar, general modular program designs rules suggest that it should be factored out somehow and in object orient designs, it would seem ideal to factor this into an abstract class. Thus BasicComponent, MainComponent, SubComponent and were born.

5.4.2 ProliferationThese component not only factored out a large segment of the code for binding to the environment, they also provided convenience features such as a more fully developed debug output system with different debugging levels as well as simulated c-style assert statements. Eventually, it was decided that all components in the one.box core system should be descendents of this class hierarchy as this would provide uniformity and allow for easier assimilation into the one.world collective.

5.4.3 EvolutionAs development progressed, components eventually began to become more complicated. Remote Event Passing(REP) became the normal method for communication between two components. There arose a need to refactor the system since much of the REP code was again getting repeated over and over across different components. As a result, RemoteMainComponent was created as a descendant of MainComponent and became the main parent class for components which wished to communicate via REP.

These four components (BasicComponent, MainComponent, SubComponent, RemoteMainComponent) did much to abstract away the overhead required by a one.world interface. However, as a standard methods and patterns were converged upon by Daniel and Albert, repetitive code that was not directly caused by the one.world API began to appear as well. In the last two days of the project a ServiceComponent was added on by Albert which took some radical design changes an incorporated many of the more advanced ideas that were being bounced between him and Daniel. However, there is only one component using this interface and it remains mainly untested.

5.4.4 DivergenceConcepts such as patterns for event handling, dispatching, association, error recovery, were developed and implemented. However, as before, each component had their own implementation of the same concepts making for huge amounts of code bloat.

Even worse, there was little or no formalism for most of these concepts. Thus, though similar ideas were shared by Daniel and Albert, their implementations diverged and multiple systems/conventions were established – especially where the two disagreed on how things should be done.

This did not affect the development of one.box much as each component was designed to be mostly autonomous so the differences in internal implementation did not cause too

Page 20: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

much of a stir. However, the resulting fragmentation and lack of standard necessitates a third refactoring – though this was never done since time ran out.

The following is an attempt to describe the different components and concepts that arose during design. It will be somewhat confused since it will be describing more than one system of thinking.

5.5 System Design Issues: Constructs and ConceptsBefore delving into the class hierarchy, it may be helpful to talk about the concepts and constructs which are used in the final object hierarchy. This may be a bottom up approach, but in this case, the class hierarchy was designed and extended while these concepts were still forming so that there is not a consistent theme across the different creations. Thus it would probably be more clear to understand each atomic component and show the compositions of them later.

5.5.1 Event DispatchingOne.world is an almost entirely event driven system, thus the bulk of the component code is written around dispatching events. In the supplied one.world paradigm, events are handled by a subclass of AbstractHandler. Each of these handlers are then bound to the environment via ExportedDescriptors (now RemoteDescriptors) and ExportDescriptors.

In a standard C++/Java object, one would go about designing it by defining the public functions that it would have. Designing a distributed component, even in the one.world environment is similar. To design a component, one must first design its interface. In the case of one.world this involves which manner in which it will connect to the world (Will it connect via the Discovery Server? The RemoteManager? The local Environment?) and what events it will react on.

It may seem that there would be reason to export multiple interfaces to the RemoteManager, DiscoveryServer or the Local Environment. However, if any single handler is able to receive multiple types of events and must demultiplex according to the event received, then what is the purpose of having multiple exported handlers for any particular method of connection? A more solid design is to have a single exported interface for receiving events. Then after the receiving the event, pass it onto a dispatching or demultiplexing system of some kind. This makes for a simpler component design and causes less pollution of the export namespace (no that it really matters in a small home network like the one that one.box is meant for).

Conceivably there may be a good split there between events gotten from a remote source via REP and events generated locally, or some sort of similar split. However, again, what benefit is there of splitting up between the different sources of events? There does not seem to be much reason to treat an event from a local interface differently than if it were received from a remote interface. However, maybe there could be a reason somewhere. This is a point of uncertainty in the design. The final ServiceComponent design that Albert implemented was based on the assumption that there is no reason for the split and thus all event interfaces pipe into the same event dispatching mechanism.

5.5.2 Dispatch PatternsThe question comes here is what to do when an event comes in. Should it be handled on the spot? Should it be passed off to handler function or class? If so, in what way should it be passed off and who’s in charge of what handlers deal with what events? How will this work when put in an object hierarchy?

Page 21: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

The answer to these questions vary depending on the situation. Event handling really can be split into two parts, the initial reception of the event, and then the dispatching to respective demultiplexing/dispatching systems. Currently, the method which seems to be the norm for one.world programs is to handle this all in one spot with a large block of if statements where each condition checks to see if the received event is an instance of a specific type. This is ugly. What really is needed is “MultiJava: Modular Open Classes and Symmetric Multiple Dispatch in Java.” However, this is current a research project by Todd Millstein and Craig Chambers, so the patterns that Daniel and Albert hacked out before seeing this poster will have to make due.

The two, having grown a general distaste for large blocks of if statements, came up with a number of patterns which eventually helped to facilitate this potentially ugly piece of code. These patterns effectively factored out the large block of if statements into smaller more manageable portions. The following will be a discussion of the major patterns.

5.5.3 Multiple Dispatch versus Single DispatchEach pattern will deal with two forms of event dispatching, Single Dispatch and Multiple Dispatch. In Single Dispatch, if an event is handled, then no other handlers are notified of that event. In Multiple Dispatch, an event is pushed to all possible handlers and if any one handlers is able to process the event, then the dispatch is said to have succeeded since something in the system was able to effectively interpret the event.

Multiple Dispatch is a more powerful concept as it allows multiple reactions to one event. However, it also holds the potential to be a debugging nightmare. It cannot be excluded since it provides a good deal more power (You can isolate dispatch systems so that changes to one system do not effect the other. This could be very useful in class hierarchies), but it should be used with caution.

Single dispatch can also cause other hidden problems as well. If somewhere on a list of event handlers, a handler handles an event, event prorogation is terminated. Thus in a class hierarchy, it is possible for an ancestor class to block events from reaching a descendent class. This could be potentially be very confusing if an event is sent, but is blocked internally before making it to the descendent event handler. It would seem as if the event just disappeared.

5.5.4 Meta HandlersA Meta Handler can be thought of as an array of event handlers. The property of a Meta Handler is that it is essentially a Multiple Dispatch handler. A set of handlers connected using Multiple Dispatch can be thought of as one big handler. The distinction is a bit trivial, but the formalization of the concept is important. 5.5.5 ChainingEvent propagation, or ‘chaining,’ is the process by which when an event comes in, rather than getting shunted off to one piece of event handling code, it can be passed along to other pieces of code as desired. It is the fundamental idea between linking multiple event handlers together.

In Single Dispatch, when an event is handled, traversal of a handler chain is ended. This is the way the current method (the large blocks of if/instanceof combinations) behaves.

Page 22: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

In Multiple Dispatch, an event is propagated to the next handler on the chain regardless of whether or not the current handler was able to process the event successfully. This way, one event can be handled in multiple ways.

The chaining of the event handlers could be used in a number of situations, especially in Multiple Dispatch mode. If a component object hierarchy was created, instead of overriding the parent class’s environment handler, a child class would just hook itself onto the end of the chain and events would propagate down.

Another use of chaining would be to implement a breakdown of logical handler units and chain them together off a single source of events.

Though chaining implies a list type structure, it could also be very easily extended to be a tree. A more fancy implementation of the Multiple Dispatch version of chaining could be achieved by replacing the list with an N-Arity tree where each node is an event handler which broadcasts the event down to all of its children. This is similar to a multicast broadcast of events and can be useful if there needs to multiple registered handlers for a single type of event.

Extending the idea even further, each child node could potentially be either another tree implementation, or a list implementation which could be Single or Multiple Dispatch in nature.

5.5.6 Waterfall Propagation PatternIn the simplest implementation, the waterfall propagation pattern is basically a chain of Meta Handlers where each Meta Handler is predefined and static. That is, the set of events each Meta Handler will be able to process is immutable.

The behavior of this pattern is pretty much the same as the chain pattern. In fact, the chain pattern was created as a generalization of this pattern. When an event enters, it is given to the event handler at the head of the chain. If this event can be processed it is done. If not, then the event is passed onto the next handler in the chain, propagating from handler to handler. The Single Dispatch and Multiple Dispatch differ in the same way that it is in generalized chaining.

The waterfall method is very well suited to an environment where one knows the types of all the incoming events. Certain optimizations could be made because of this foreknowledge that would allow for extremely fast dispatching (e.g. using a HashMap to route off to handlers).

The biggest weakness in the waterfall method is the potential propagation delay of the chain. In the average case, however, the propagation delay should be negligible since chains would probably not grow to a significant length.

The Waterfall Propagation Pattern and the chaining concept were created and used by Daniel to implement his Component Hierarchy and is mainly mentioned as a separate pattern from chaining because it is the original pattern that was created to be the backend of main Component Hierarchy.

5.5.7 Mutable Dispatch PatternMutable Dispatch attempts to address two issues in the Waterfall Propagation Pattern: propagation delay and immutable Meta Handlers.

Page 23: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

Essentially, the Mutable Dispatch pattern is one large Meta Handler which attempts to be large enough to cover all desired events. It is similar in that respect to the large block of if-statements that we were trying to avoid. The bonus of this is that there would be no propagation delay due to chaining.

Unlike the static block of if-statements, the Mutable Dispatch would allow for registration and deregistration of handlers dynamically. This solves the problem of allowing child classes to add or remove handlers.

As for being able to break up the class hierarchy into logical groupings of handlers, this can also be done, except in this pattern, the split would be in where the functions are registered.

The major downfall of this method is that there is inherently a larger overhead per lookup than in the Waterfall Propagation Pattern since a lock would be required in any threaded environment due to the dynamic nature of the pattern. Thus, while it is more dynamic, the Waterfall system is still probably better suited for a system with well-defined events and interactions.

Also, unlike the Waterfall/Chaining pattern, the Single Dispatch versus the Multiple Dispatch version of this pattern vary quite a bit. In a Single Dispatch version, it could conceivably be implemented using a HashMap and be fast.

However, in the Multiple Dispatch version, it would have to iterate across all possibilities with ability to optimize or prune off branches.

The Mutable Dispatch Pattern was created as a result of an argument between Daniel and Albert and fits into ServiceComponent because of its flexibility.

Properties Mutable Dispatch Waterfall/ChainingPropagation Delay xDynamic Modification xJava Reflection Overhead xFaster Single Dispatch x

5.5.8 Application and Implementation one.worldNone of the previously mentioned patterns are mutually exclusive or dependant. They can be used separately or in tandem. In respect to the implementation of the one.box core components using one.world, the Waterfall Propagation pattern was the main pattern implemented by the original components four root components of one.world (BasicComponent, MainComponent, SubComponent and RemoteMainComponent) as events were well defined and supported at the language level (by type checking).

However, the patterns took on a some interesting implementations. They have been mutating slowly as more experience is gained in programming one.world components.

The dispatching patterns are actually used mostly as demultiplexing classes that handle events after they are received by a handler. These classes are separate from the event handler and probably should be since event handlers may not be the only ones calling the

Page 24: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

classes (they may dispatch to one another forming more of a graph than a tree). This is displayed in Daniel’s Demux classes and Albert’s Dispatch classes.

There is not one yet, but the eventual convergence would seem to point to a dispatch interface with single and multiple dispatch variants. Then any dispatch method could be swapped in or out as pleased.

The current implementation of the Waterfall Propagation pattern is to use small blocks of if statements. Whereas the pattern points to static Meta Handlers in the Waterfall chain, Daniel’s implementation allowed for some more flexibility by allowing descendent classes to preempt the default handlers provided by the ancestor classes.

Mutable Dispatch was implemented using a HashMap of Method references and various other java.lang.reflect classes for querying class information to dispatch to the correct method. Mutable Dispatch was the preferred dispatch method used by Albert.

However, creating Method references in Java is ugly since it requires the programmer type in the name of the desired method as a String as well as requiring a listing of parameters as well as a reference to the instance of the class containing the method. This did not allow for errors as simple as typos to be caught until runtime and generally took up a block of three lines to create the reference. Function pointers would have been ideal but Java in it’s “safeness” does not have such useful syntactic sugar.

This made the initial implementations of the Mutable Dispatch method just ugly in general as large blocks of code were dedicated to just registering functions. During the last two days of the project however, while attempting to write the ServiceComponent, a new implementation for how to register handlers came about. The new dispatch implementation called AutoEventDispatch took in an instance of a class containing only event handlers and registered all of the handlers. This made the use of Mutable Dispatch much more tasteful and should probably obsolete the other Mutable Dispatch implementations. Also there are arguments that Mutable Dispatch is slow because it uses the Java Reflection API. However, it does little more than a getClass() and an invoke; both of these should be really fast.

5.6 Component interaction philosophies5.6.1 Strongly Typed EventsAs a rule, the events that get passed around remote services are proper defined types within the system. Largely this is because REP allows for this. This allows services to implicitly know the type of service a message came from. For example, if a service receives a FilterOutputEvent, it knows that this event is probably in response to a FilterInputEvent that was sent to a filter component in the system. This allows for easier localization and organization of interactions with different components.

5.6.2 “Smart sender, dumb receiver”One popular design principle that has been incorporated is the idea of “smart sender, dumb receiver.” The basic idea is that sender will perform all the necessary work in handling errors. The main error that we were concerned about is the communication breakdown that occurs within distributed system. The receiver does not care about the issue of handling errors.

Page 25: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

For most inter-service communication, the following set of events occur,

1. Sender sends message to the receiver to do something.2. Receiver upon getting the message sends a PENDING to the receiver.3. After the receiver finishes processing the message, the sender is sent back a

TRUE/FALSE depending on whether the message request was handled properly.

The important thing to note here is that the receiver does not care whether the sender got the PENDING or TRUE/FALSE. This simplifies error handling on the receiver side. The sender cares about whether the PENDING, TRUE/FALSE gets back to it.

The idea of the PENDING, TRUE/FALSE handshake is to build a application layer on top of the RemoteEvent transport. While the PENDING may seem a bit extraneous, it is useful for bookkeeping purposes. Since internal messages are passed using a strongly typed system, a PENDING response will be sent in the corresponding type for the given situation. This gives more of a clue as to what the PENDING is meant for and thus can be helpful for organizing connection state information. Currently for most services, PENDING is not handled properly yet. The intention is to use the PENDING message for optimizations later on.

To handle the TRUE/FALSE response properly, a timeout scheme was implemented (See 5.6.3 ActiveLists). Ideally a timer event is associated with every message that is sent out. When the timer goes off, the status of messages are checked. If the message no longer exists in the system, it is safe to assume that is was processed correctly.

If a timedout event is found, an attempt is made to perform the necessary recovery procedure (i.e. resend, throw an exceptional event). The asynchronous framework of one.world makes this sort of natural error processing much easier to do. However this scheme is still fairly complex (especially for high volume of messages), so to first approximation that is being used is a coarse grained timer that does some aging on outstanding messages within the system and which also triggers error recovery for the

Page 26: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

messages that are too old. The main caveat to this scheme is that receiver must be idempotent to receiving the same message multiple times.

5.6.3 Event RelationsActive ListsGiven the idea of “Smart Sender Dumb Receiver,” and the proposed handshake, it becomes necessary to keep track of the connection state handing timing out of events as well as sudden loss of connection.

To deal with this problem the idea of an Active List was brought up and implemented by Daniel. Every time an event is sent out by a component, it is placed on the Active List registered by its GUID. The GUID is also placed in the closure of the remote event. Thus when a response is received, the closure can be used to track which event triggered the response.

The Active List idea was a quick implementation of the idea of connection tracking. It was later extended by Albert to include timeouts and a timeout handler to deal with timeout events.

The initial use of this was purely for insuring that every event that was sent received the proper set of handshakes. However the idea is much, much more powerful.

Event contexts and continuationsOne of the main problems of event passing is that an event is very myopic. There is usual no context for which an event happens. If an event is generated to request some sort of action of another component, then it probably has no context other than where it comes from. However, if an event is generated in response to another one, then there needs to be a way to match which event the response is for.

Rudimentary connection tracking is implemented by an Active List where every event that is sent out is registered on the Active List by its Guid. This idea can be extended to contain the state information for a given event. Thus, when an event is sent, not only does it register itself with the Active List, but it should also register any other context information that may be necessary for a correct handling of a response to the event. This way it is possible to create a small connection context for a given event sequence. This could further be extended by using a sufficiently unique identification number rather than the Guid for connection tracking (like TCP segment numbers) as this would allow multiple events to share the same connection context.

An even more powerful concept is the idea of placing a continuation in for the event context. This way, an event response could pick where a previous event left off. This can, in some ways, simulate a blocking function call.

This form of event tracking has an initial, completely untested implementation in the ServiceComponent interface.

5.7 Component Creation and InitializationOne.world currently lacks a well defined set of ideas about where creation and initialization of an object takes places. Contrary to the normal object idea of having creation and initialization take place in the constructor, it would seem that the constructor actually should do very little creation directly in a one.world component. The main

Page 27: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

question is how many states should be factored out in a one.world component for where internal representations need to be created and initialized. The current breakdown by Albert is:

object creation (construction) object initial activation (Initial activation) object reactivation (if stopped or something) object restoration (state has been destroyed)

Given these different points of potential creation and initialization, what classifications of state exist? It may be tempting to break down a program to persistent and non-persistent state, but this is not sufficient because of the problem of reactivating a component. If a component has a display up, and the component is stopped, ideally, the display would be taken down and all resources associated with it removed. However, when the component is restarted, though the display resources need to be reacquired, the information displayed should be kept across the stop and restart. It seems currently that it may be sufficient to split state up into three types of state:

Persistent State Session State Runtime State

Persistent State is state that should be kept across check pointing (like the current options in a program)

Session State is state that only exists per session and has nothing to do with other sessions. This includes state such as locks, perhaps active send lists, etc.

Runtime State is state that only exists for a specific activation of a component. This would include things like swing instances for a component. They should have no assumptions of previous runtime states.

All states should be creatable if just given the higher up state. Session state should not contain anything that cannot be reproduced if only given information from Persistent state. Runtime state should not have any state that cannot be recreated given the session state.

Given also that a component does not exist isolated from other components, the first two state types – persistent and session – should have associated with them a verification function which verifies the validity of the state and handles anything changes that may occur. Runtime state has no other states based off of it thus it does not need to be validated since it should be created on the fly from the other states (which have been validated thus it must be valid).

5.8 Utilization of one.world features5.8.1 Use of Late BindingLate binding is an extremely powerful mechanism that makes the use of Mover/WatchDog possible. Since a resources is not discovered and event is sent, this makes the moving of resource around the network practical. Furthermore, the exception mechanism makes it easy to deal with the resource not being available for the short period in which is unavailable.

Page 28: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

5.8.2 Use of Exceptional EventsThe use of exceptional events within the system makes it easier to handle exceptional situations. For bookkeeping, there is the throwable and closure fields which allow for identification of both the cause and the offender of an exception.

For example, when a resource in one.world cannot be discovered, one.world gives a ExceptionalEvent with an UnknownResourceException in the throwable field and the Guid of the offending event in the closure. By using this, it is possible to try to send the message. This makes error recovery for discovered services much simpler.

5.8.3 MainComponents are CheckpointableThis is a necessary prerequisite for the Mover/WatchDog components possible. Moving a component requires that it be checkpointable, thus all MainComponents that can exist in the one.box system must be checkpointable otherwise they would not be able to be moved. If a component cannot be relocated, then the WatchDog would not be able to spawn a new component in the event of a node going down.

5.9 Miscellaneous coding devicesThough Java plus one.world overhead seems to be an inherent contradiction with the term “readable code”, much effort has been put in trying to factor out parts of one.world components so that the code is both readable and easily maintainable.

The inherent problem with the code is plain bulk. Java’s idea of not separating the implementation file from the specification file has the interesting effect of making your source files huge. Albert has been finding emacs’s hideshow to be an indispensable tool for navigating his own code. The sheer number of cases and conditions that needed to be handled caused the code to bloat quite a bit. To keep things more organized, it was necessary to formulate some organizational devices in the code to keep it manageable. Following is a description of the devices.

5.9.1 whoamiThough the BasicComponent provided a simple debugging output function, it did not specify who or what the output came from. Thus Daniel came up with the “whoami” convention. Initially, this was a variable assigned in the constructor, but it eventually evolved into a overridden function which returned a description – usually the class name – for whatever scope the function happened to be in. Then by convention, the result of the whomai function was prepended to each debugging message. This made it much easier to track which component a debug message came from.

Ofcourse it would have been easier to have used getClass().toString(), but why use predefined interfaces if it is possible to reinvent the wheel?

5.9.2 Debug Output FacilitiesLog levels and assert functionality was implemented to facilitate debugging output.

5.9.3 Trailing underscoresTo differentiate between the hordes of local variables and the member variables of a class, the convention of appending an underscore to all member variables was adopted.

5.9.4 Jakarta.oro

Page 29: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

The Jakarta.oro libraries were used to match and filter mail using Perl5 regular expressions.

5.10 Component HierarchyBelow is the description of the component hierarchy which implemented much of the ideas mentioned above. Their composition is not necessarily consistent as they were designed at different stages in the impementation.

5.10.1 BasicComponentThere lacked a quick (typing-wise) method for creating debugging output. One.world provided ‘SystemUtilities.debug’, but that was a handful to type and did not differentiate between different levels of debugging messages. Also, having both developers, having had a strong C background, felt a distinct lack of the ‘assert’ macro. BasicComponent was created to provide these functions.

Each component derived from BasicComponent has a ‘debug’ function that takes two parameters, the log level of the message and the message itself. For convenience, a version of the function that just takes debug message and assigns it the lowest priority log level is provided. The log levels are defined constants and can be set via the ‘setLogLevel’ function. The debug function is a simple if-statement wrapper which checks if the message is at a high enough log level and calls SystemUtilities.debug for you if it is.

An ‘assert’ function which simulates a C-style assert macro is also provided which takes a boolean expression and a string and creates a one.world ‘Bug’ if the expression is false.

There are other convenience functions provided for logging information or displaying errors, but they are either spin-offs of the above or not used.

5.10.2 MainComponentWhile the added debugging facilities of the BasicComponent are convenient, the main reason for creating these classes was to factor out the common overhead of creating a one.world component. Ideally, creating a component should be as easy as subclassing and instantiating. This was Main Component’s goal, but due to some of the particular assumptions that one.world made about the order with which things are done during object creation, a fully abstracted interface for the common overhead was not attainable.

Every one.world component requires at least 3 steps to be able to be functional in a one.world environment:

Creating references to components (such as itself, the system timer, etc) Handling events – especially basic ones like stop events from the environment Linking in various components

Though it is possible to create many references and statically link in each component in one environment, the cases generally reduce to having one import descriptor for the current environment, one import descriptor for a timer since it is needed for many system maintenance tasks, and one export descriptor for the component’s main event handler.The MainComponent also provides a facility for binding and export ExportDescriptor with the environment and some default behaviors for common events such as ‘ACTIVATED’ or ‘STOPPED’ as well as the ability to substitute a different event

Page 30: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

handler in place of the default. The MainComponent implemented the Waterfall Propagation dispatch pattern.

The central difficulty in the design of the MainComponent is that one.world expects linking to the environment to happen only after everything has already been exported, etc. This makes a clean inheritance structure where derived classes can just tack on more ExportedDescriptors without knowledge of the super class’s implementation all but impossible. The linking step to the environment must be done as the very last step in the last constructor, otherwise one.world complains that the exported interface of a component is being changed after it has been bound to the environment. This makes it so that it would be impossible to derive a new component from any component. The existence of this restricts raises the question of whether or not one.world was designed to be object-oriented, or was there a specific design intention to discourage this sort of design. Currently, a hacked workaround is done using dynamic dispatch. Classes derived from MainComponent must call a ‘linkComponent’ function after they have exported all their handlers in the constructor. This function can be overridden to include more environment links if necessary, but the overriding function must chain up the class hierarchy by calling its parent class’s version of ‘linkComponent’. It is less than ideal, but was a good compromise for now.

Complicating the issue some more in the introduction of the ‘init’ function, the activation events, serialization and deserialization. Normally in an object-oriented program, initialization of an object is done in the constructor. In one.world, it can happen in at least three places, and do slightly different things in all there. This is discussed later on in 5.7 Component Creation and Initialization.

5.10.3 SubComponentThe SubComponent is derived off of BasicComponent and is meant for creating components that will never be created independently of another component. It provides the basic required exports and imports, but does not have any built-in facilities exporting itself as a remote service, etc. Think of it as a stripped down MainComponent.

5.10.4 RemoteMainComponentMainComponent by itself provided a large amount of abstraction for many of the more mundane and unnecessary code repetition. However, if a component is meant to do Remote Event Passing (REP), there are still more assumptions that can be made about its interface. The RemoteMainComponent extends MainComponent and adds a few more interfaces and methods. In particular, it adds two simplified interfaces for registering remote descriptors, requires a RemoteEvent handler and a LeaseNotify handler. The RemoteMainComponent is also build with the Waterfall Propagation dispatch pattern. Furthermore, it has multiple event handlers which distinguish implicitly, via their connection, between different sources of events.

The main benefit of the RemoteMainComponent is that it has a simple interface for exporting a descriptor to the environment’s RemoteManager. When discovery was made available, this interface was beat up a bit to register with the DiscoveryServer.

5.10.5 ServiceComponentServiceComponent was the last component to be written. It is very different from the rest of the components in a number of ways. First, it was written by Albert instead of Daniel. Second, it was written at the very end of the development process and thus contains many of the experimental ideas that popped up during the end phase of the project –

Page 31: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

specifically with an Albert twist as there were many disagreements on implementation mechanisms by the end. Third, it is almost completely untested having only one component based off of it.

The ServiceComponent was designed around the idea that a component is really one giant event handler. Thus much of it was designed around making event handling easy from anywhere in the code. This resulted in the selection of having one event handler as this unified the source of events entering the system. Events were then passed onto a dispatcher class which would dispatch the events to the correct handler.

Programming with events is essentially programming via side-effect. In this case, a fully object oriented system is not the most ideal model for sanity. What would be more effective is a large function library like what one would see for C. In that spirit, the respond helper functions of the RootHandler (the single event handler of the service component) were exposed to the rest of the class allowing for creation of handler functions anywhere and allowing for reaction to an event to occur anywhere in the code.

Event Dispatching was done using the newly created AutoEventDispatch mechanism. The hopes were to have a private Multiple Dispatch system that ran directly from the RootHandler. Then a protected Single Dispatch mechanism could be chained from the Multiple Dispatch mechanism so that one can add default handlers that can be overridden as well as handlers that cannot be overridden (Overridable handlers would go in the Single Dispatch chain and non-overidable handlers would go in the Multiple Dispatch chain). Also, there is an assumption that adding and removing event handlers only happens during construction, though there currently exists no mechanism to enforce this. The reasoning for this is to avoid having to lock the handler registry per event lookup.

Futhermore, the EventDispatching system was designed to support contexts for events. Each event is dispatched into the system with a context Object (which can be null). With this in mind, default implementations of things such as unwrapping of RemoteEvents can be done since the RemoteEvent itself can be passed back into the dispatching system with the RemoteEvent given as the context. Other default implementations for environment events, are also given.

A safe-event passing method is implemented in the form of a trackedSend function which creates a sufficiently unique send ID and stores the event in the registry of waiting events. When an event is received, it can be looked up in this table for extra context information or whatnot.

Initialization of a ServiceComponent is also done differently. Subclasses of ServiceComponent are actually discouraged from putting object creation and initialization within the constructor proper. Instead, it is encouraged to try and follow the breakdown of three category breakdown of state (see section 5.7 Component Creation and Initialization) into Persistent State, Session State and Runtime State with their associated creation, destruction, initialization and uninitialization sections. This means that persistent variables should be created in the createPersistentState functions and initialized in the initPersistentState function. These functions are called at appropriate times by the default event handlers (Persistent state is created in initialized in the constructor. Session state is created in the constructor and initialized on the first ACTIVATED event. Runtime state is created, initialized, uninitialized and destroyed on ACTIVATAED and STOP events).

Page 32: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

Linking a ServiceComponent to the environment is not done with the link command. Instead, a the programmer schedules links and they are preformed in a batch thus avoiding the problem of exporting extra interfaces after linking to the environment.

A global lock variable is provided for you as well as a scheme environment which contains a binding to the current instance of the component. The scheme environment allows for dynamic configuration and reprogramming of a component which could be used for things like easily building dummy component interfaces as suggested by Bret in the Quero paper. It also allows of scheme style manipulations of internal variables and creation of sub environment where variable contexts can be bound and passed around (for use with passing event contexts and continuations).

The ServiceComponent is by no means correctly done, but it does take a large step in providing much of the common functionality that most components require. It removes most of the overhead involved in writing a component. The single service written using the ServiceComponent interface took a total of 72 lines NCSS. Granted, it was a very simple service, but 72 lines is still shows the results of removing the one.world overhead.

Hours: 385Lines Framework: 1292Lines one.box: 7950Lines test: 350

6 - Conclusion6.1 Points of Comparison6.1.1 Asynchronous Events Vs Synchronous InvocationsJini provides synchronous invocation which is similar to a function call where a call to a method blocks until the called method is able to give a valid response. That means that the request and response are localized to the same runtime context and are thus implicityly associated.

On the other hand one.world uses asynchronous events where after a request is sent there is no implicit association with its response. Furthermore, all events are handled through event handlers which deal with the dispatching of events to their respective handlers. An event and its response are often of different types, thus though the two events are related, they are generally handled in different segments of the source code. Add this to the implicit lack of contextual state, it makes healing with handshakes and other persistent connections incredibly difficult. The only possible way to reliably do it is to implement some form of context passing or continuation.

The use of asynchronous events requires state to be kept for every request that has been made. The reasoning for this is that when the response comes back, information in the request is needed in order to complete the process. In order to maintain state it is necessary to build a lot of book keeping structure. This book keeping structure doesn’t add to the functionality of the component but adds substantially to the amount of code written.

Jini’s synchronous invocation is very simple and does not incur any of the above overhead because the request and response are received at the same point. The problem with synchronous invocation is that the calling method can block for a very long time and delay critical actions. Even worse, if the called method was badly written, (eg. never

Page 33: One€¦  · Web viewIf a single word could characterize the life of a programmer living in the one.world framework, it would be ‘repetition.’ On the first attempt at writing

timing out) then the caller would block forever and the system would appear to have hung. This was solved by using Sun’s TaskManager class, which mimics a one.world animator by implementing a thread pool that pulls events off a queue allowing the caller (who is using the TaskManager) to resume its actions.

6.1.2 One.Worldizing Vs JinifyingJinifying is the process of taking a normal class (e.g. a class that can run in a conventional local environment) and turning it into a Jini service (i.e. it discovers, joins, and possibly looks up other services). From our experience, this process is simple once we got the hang of it. Jinifying involves modifying a main() method with about five lines of code and possibly using a class that implements the DiscoveryListener interface to look up other services.

On the otherhand, fitting an application into the one.world framework is quite difficult. This is because requires a different design philosophy for the applications. Most application are written expecting to be able to provide information to a function and get a processed result back. This is not easily doable in one.world. And because of this, the whole component interaction section would need to be rewritten. Since a large portion of any distributed program is how it interacts with other components, this requirement in effect causes almost a full rewrite of the whole component.

However, even though it is very easy to take a regular Java class and Jinify it, this may not be the best approach. Conventional programming practices are generally not the way to go about designing a distributed application because it does not take into account unstable connections, or unreliable resources. Thus, it may be easier to get a program to be “distributed,” but to make it behave well in a distributed environment, it would be recommended that the application was designed with a distributed framework in mind.

The plus of doing it in one.world is that it requires one to at least deal with the concept of unreliable resources and asynchronous events. It is similar to Java’s exceptions in the way that programmers are forced to catch exceptions. Though a programmer could ofcourse just ignore the exceptions, at least they will know that a potentional problem exists.

6.1.3 One.World Integration Vs Jini IntegrationThough both Jini and one.world provide methods for accessing remote resources and provide a framework for creating distributed applications, the philosophies behind the two systems are quite different. This is reflected in the coding styles and issues encountered by the different case studies.

Jini allowed the programmer much more flexibility in his code while one.world imposed more constraints.