W3C | OOP

A Post-Hoc Rationalization of the Object Oriented Design of the World Wide Web

(that's a fancy way to say "I told you so!" :-)

Abstract

By investigating the duality between APIs and network protocols, we re-discover the design of the web, and the relationship between mobile/distributed objects and knowledge sharing/exchange. For background, be sure to see "Toward A formalism for communication on the World Wide Web" posted to www-talk back in Feb 94.

Intro

The WWW/OOP Thesis: the hypermedia architecture of the web is isomorphic to--or perhaps a special case of--modern distributed object systems. URLs are symbols in the intertwingled GEB sense.

Motivation: Why Bother?

The Trivial Mapping

of HTTP into an RPC system:

procedure GET(path: String): ByteSequence;

Introducing Objects

interface Document {
	GET(): ByteSequence;
}
interface Server {
	docNamed(path: String): Document;
	};

We know GET can and should be cached. How do we tell the RPC infrastructure?

RPC Caching Facility: Functional Methods

interface Document {
	functional GET(): ByteSequence;
}

This looks like HTTP 0.9! What about error codes? Accept: headers for format negotiation?

Adding HTTP 1.0 (RFC822) Expressiveness

interface Document {
	GET(version: String, fields: FieldList):
		struct {
			version: String;
			status: Integer;
			header: FieldList;
			body: ByteSequence;
		}
	}

We don't want to think about versios at this level. Can we make the version implicit in the interface by using RPC facilities?

Can we exploit RPC exception facilities to avoid manually checking for error codes?

Using RPC Version, Exception Facilities

interface Document version "HTTP/1.0" {
	GET(path: String, version: String, fields: FieldList):
		struct {
			header: FieldList;
			body: ByteSequence;
		} raise(Partial, ClientError, ServerError)
	}
exception Partial, ClientError, ServerError {
	status: [0..99];
	message: String;
	header: FieldList;
	body: ByteSequence;
	};

Can we express more of the structure and semantics of the header fields?

Using Typed Arguments

in stead of string syntax: (ref 1.1 spec)

interface Document{
	GET(      Accept-Charset: CharSetMetrics, 
                      Accept-Encoding: Encodings,
                      Accept-Language: LanguageMetrics,
                      Authorization: Credentials,
                      From: String,
                      Host: String,
                      If-Modified-Since: Date,
                      If-Match: String,
                      If-None-Match: String[],
                      If-Range:
                      If-Unmodified-Since: Date,
                      Max-Forwards: int,
                      Proxy-Authorization: Credentials
                      Range: record start, end: int end,
                      Referer: Document,
                      User-Agent: Product) : Response;
type Response = struct
	struct { Age : Duration,
                       | Location: Document,
                       | Proxy-Authenticate: Challenge,
                       | Public: MethodList,
                       | Retry-After: Delay,
                       | Server: Product,
                       | Vary: VariantMap,
                       | Warning: String
                       | WWW-Authenticate: Challenge,
			body: ByteSequence;
		} raise(Partial, ClientError, ServerError)
	

Using RPC Authentication Facility

in stead of Authorization argument.

interface Document{
	GET(      Accept-Charset: CharSetMetrics, 
                      Accept-Encoding: Encodings,
                      Accept-Language: LanguageMetrics,
                      From: String,
                      If-Modified-Since: Date,
                      If-Match: String,
                      If-None-Match: String[],
                      If-Range:
                      If-Unmodified-Since: Date,
                      Max-Forwards: int,
                      Range: record start, end: int end,
                      Referer: Document,
                      User-Agent: Product) : Response;
type Response = struct
	struct { Age : Duration,
                       | Location: Document,
                       | Proxy-Authenticate: Challenge,
                       | Public: MethodList,
                       | Retry-After: Delay,
                       | Server: Product,
                       | Vary: VariantMap,
                       | Warning: String
                       | WWW-Authenticate: Challenge,
			body: ByteSequence;
		} raise(Partial, ClientError, ServerError)

Why do semantically void information such as From: and User-Agent: and Server show up at this level?

Using Context Handles

interface Document{
	GET(      Accept-Charset: CharSetMetrics, 
                      Accept-Encoding: Encodings,
                      Accept-Language: LanguageMetrics,
                      Host: String,
                      If-Modified-Since: Date,
                      If-Match: String,
                      If-None-Match: String[],
                      If-Range:
                      If-Unmodified-Since: Date,
                      Max-Forwards: int,
                      Range: record start, end: int end,
                      Referer: Document : Response;
type Response = struct
	struct { Age : Duration,
                       | Location: Document,
                       | Public: MethodList,
                       | Retry-After: Delay,
                       | Vary: VariantMap,
                       | Warning: String
			body: ByteSequence;
		} raise(Partial, ClientError, ServerError)

Does RPC marshalling facility require that the whole body be in memory?

Using Streams

interface Document extends IPersistStream{
	load(a: Anchor){
		bc = new BindingContext()
		// set up my bc with persistence formats that I know about
		loadFrom(a.openRead(bc));
	}
	displayOn(w: Window);
}

interface IPersisStream{
	loadFrom(s: InputStream);
	saveTo(s: OutputStream);
}


interface BindingContext{
	@@ captures semantics of following headers:
// data understandin capabilities
      Accept-Charset: CharSetMetrics, 
                      Accept-Encoding: Encodings,
                      Accept-Language: LanguageMetrics,
// freshness info
                      If-Modified-Since: Date,
                      If-Match: String,
                      If-None-Match: String[],
                      If-Range:
                      If-Unmodified-Since: Date,
// latency requirements
                      Max-Forwards: int,
}

interface Anchor { /* ala IMoniker, CosNaming::NamingContext */
	openRead(bc: BindingContext, referer: Anchor): InputStream; (* GET *)
	openWrite(bc: BindingContext, referer: Anchor): OutputStream; (* POST *)

        openAppend(bc: BincingContext, referer: Anchor): OutputStream; (* PUT *)
	delete(bc: BindingContext, referer: Anchor); (* DELETE *)
@@ mkdir? 9fs? DLS (link management)?

@@type Response = struct
	struct { Age : Duration,
                       | Location: Document,
                       | Public: MethodList,
                       | Retry-After: Delay,
                       | Vary: VariantMap,
                       | Warning: String
			body: InputStream;
		} raise(Partial, ClientError, ServerError)
}

Adding Filesystem Caching Semantics to Streams

interface Entity: InputStream {
	contentId(): URI; (* URN *)
	location(): URI; (* URL *)
	lastModified(): Date;
	validator(): ETag;
	md5();
	volume();
Age : Duration,
}

interface BindingContext{
	attribute CacheControl;
	maxForwards(): CARDINAL;
                      If-Modified-Since: Date,
                      If-Match: String,
                      If-None-Match: String[],
                      If-Range:
                      If-Unmodified-Since: Date,
                      Max-Forwards: int,
	Accept-Charset: CharSetMetrics, 
                      Accept-Encoding: Encodings,
                      Accept-Language: LanguageMetrics,
                      Range: record start, end: int end,

                       | Warning: String

}

interface Anchor : IMoniker{
	bindToStorage(bc: BindingContext, referer: Anchor): Stream
@@Hmm.... what about...
	                       | Public: MethodList,
                       | Vary: VariantMap,

raise(Partial, ClientError, ServerError)
	
	}

interface Document : IPersistStream{
	load(data: InputEntity);
	saveTo(data: OutputEntity);
}

	GET(      
type Response = struct
	struct { 
                       | Location: Document,
	body: InputStream;
		} 

Attaching Application Security Semantics to Entities

interface SignedEntity {
	prove(antecedent: Formulas, conclusion Formula) raise Undecidable (f: Formulas);
}
interface EncryptedEntity {
	decrypt(k: Key): Stream;
}

Intellegent Naming: Anchors, Symbols, Monikers

Evolvability, Interface Negotiation

Profiles: Name Services and Binding Revisited

Filters

Generic Object Interfaces

interface Bank{
	open(customerName: String): Account;
	};
interface Account{
	deposit(amount: Currency);
	withdraw(amount: Currency);
	balance(): Currency;
	};

HTTP mapping:

OPEN /bank HTTP/1.new
CustomerName: Fred Jones

	200 OK
	Content-Type: application/url

	http://server/account/1

Documents Aren't the Only Object

POST for DII, IDispatch

Business Cards and Magazine Subscriptions: Composeable Web Objects

Open Issues: CGI, CCI

References

9FS
versatile name/file service
ILU
DCOM


Connolly
$Date: 1996/12/09 03:30:15 $