How to declare SOPE methods.

What methods a SOPE object provides is specified in the product.plist of a SOPE "product bundle". For each method SOPE will register a callable "invocation" object in the appropriate SoClass. This is different to Objective-C and similiar to Python (methods are just regular objects!).
In addition, for Objective-C classes, the classes are scanned for methods.

TODO: write much more ;-)

If you want to learn more on how methods are invoked by different protocols, take a look at method dispatchers.

Automatic methods discovered by scanning

When an Objective-C class is registered as a SoClass, SOPE scans the class hierarchy for "action" methods, pretty much like in WODirectAction objects.
SOPE will expose all methods which end in "Action" or "Action:" like "doItAction:" or "saveAction".
Discovered methods will be registered in the peer SoClass as SoSelectorInvocation objects.
Note: automatic methods are discouraged in favor of explicit declarations in product.plist. But in practice they require less formal coding ;-)
This is implemented in NGObjWeb/SoObjects/SoObjCClass.m

Q: Why don't we expose _any_ method?

A: In theory we could export any method to the web, and actually this is done by Zope. The issue is that in this case all methods (like -dealloc or -retain!) must be properly protected by the security system which is tedious and error prone.
So we found it more "secure" to enforce some naming scheme or manual declaration in product.plist.

Tip: HTTP "methods"

The SoMethodDispatcher tries to invoke HTTP methods as SOPE methods if available. So you can implement "- GETAction:", "- DELETEAction:", etc to get triggered by the appropriate HTTP methods.
Note that if no HTTP method is found, SoMethodDispatcher will look for the "default method" and invoke that. This is usually preferred over direct HTTP implementation/

Argument Types

To further understand methods, one needs to be aware of different styles of passing arguments to methods. The two major types are "positional arguments" and "keyword arguments".

Keyword Arguments

For example if you submit an HTML form, parameters are passed in as keywords arguments where ordering is not relevant and the arguments are identified by their name:

http://myhost/myapp/so/doIt?a=5&b=3

This calls the method doIt with the arguments a and b. The ordering cannot be ensured (at least in no environment I know since everyone stores the query parameters in a hashtable which does not preserve the ordering).

Positional Arguments

XML-RPC is the example which only allows calls using positional arguments, eg:

c = server.add(5, 10);
Sidenote: Python methods

The handling of parameters is actually one of the reasons why Python matches Zope so extremely well. Python methods can be called in both styles. Sample:

def doIt(a, b)
doIt(b=10, a=5); # ordering is irrelevant, found by name
doIt(5, 10); # positional args

Further Python has support for optional positional and keyword arguments (*args and **kwargs) which is also great for dealing with additional "webservice" parameters.

Special Case

TODO: talk about SOAP XML input and WebDAV messages.

Builtin Method Types

SOPE has builtin invocation classes for the common cases (you can always add your own!). That is, it has classes to invoke WOComponent's as "methods" and to invoke selectors and WODirectAction's as methods.
The concept is a bit hard to grasp if you were thinking OO in terms of a specific language (like Java or ObjC) before. In SOPE a method can be anything which is "callable".
As a simple example take a "view" method which can be applied on all kinds of objects. Such a method exposed through the web would probably get implemented as a WOComponent.

SoSelectorInvocation / 'selector' key

Selector parameters are positional parameters by nature. Don't be confused by Objective-C keyword selectors, the keywords are actually part of the selector, not an argument name (eg "- addThis:5 toThat:8" is selector "addThis:toThat:" with two positional args 5 and 8).

methods = {
doIt = {
selector = "doIt:";
};
addIt = {
selector = {
name = "add:and:";
addContextParameter = NO;
};
};
addItMore = {
selector = {
name = "add:and:";
addContextParameter = NO;
arguments = {
SOAP = (
"Body/loginRequest/auth/username/!textValue",
"Body/loginRequest/auth/password/!textValue"
);
};
};
};
};

The first style with just the string as the value implies the addContextParameter parameter set to YES. That is, the "-doIt:" method will get no parameters but the WOContext as the argument.
The second style works with positional parameters, as submitted by the XML-RPC method dispatcher. It will receive two positional parameters and no context (you can add the context as a third argument by setting the addContextParameter to YES).

Finally the third option specifies how arguments are extracted from a SOAP request. It performs sope-xml/DOM queries on the SOAP envelope (which is passed in the context by the dispatcher).

Note: all that will be extended a lot. Basically we need to convert keyword parameters to a dictionary parameter or to positional parameters.
Stay tuned.

Instances are created in NGObjWeb/SoObjects/SoProductClassInfo.m (-makeInvocationForMethodNamed:manifest:)

SoPageInvocation / 'pageName' key

WOComponent parameters are keyword parameters by nature (parameters would be regular component values applied by KVC).

methods = {
edit = {
pageName = "AppointmentEditor";
};
save = {
pageName = "AppointmentEditor";
actionName = "save";
}
login = {
pageName = "LoginPage";
actionName = "login";
arguments = {
SOAP = {
login = "Body/loginRequest/auth/username/!textValue";
password = "Body/loginRequest/auth/password/!textValue";
};
};
};
};

Page invocations are created if the pageName key is found. The only optional argument is actionName which specifies the name of a selector to trigger in "direct action style".
That is, the "save" actionName will call a method called "- (id<WOActionResult>)saveAction" on the component.
Similiar to direct actions, defaultAction will be called if no actionName is present. The default implementation of this method just returns self which will result in the component being rendered.

Parameters are not automatically applied on WOComponents, at least not in the moment ;-) To retrieve keyword parameters you just use the WODirectAction methods - takeFormValuesForKeys:... etc or WORequest's - formValueForKey: methods.
Note: this may change in the future, probably we extend the declaration to include parameter specs

Update: added SOAP parameter handling to page invocations. It basically matches the selector invocation support, it will extract values from the XML and apply them to keyword parameters (via KVC).

Instances are created in NGObjWeb/SoObjects/SoProductClassInfo.m (-makePageInvocationForMethodNamed:manifest:)

WODirectActionPubInvocation

Hm, this is apparently unsupported in the moment?