veyron2/ipc: 3 of n. 'Invoker and Signature' rationalisation.

- implement the changed ipc.Serve signature
- transition all code to use it and ipc.ServeDispatcher
- get rid of the ugliness around calling Serve multiple
  times to publish under multiple names in the mount table
  and instead provide AddName/RemoveName methods.

Change-Id: Ic5edd709d28e2670369986a5b0fce4cd22e3cafd
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 44ae7ab..943a71b 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -47,7 +47,11 @@
 	stoppedChan      chan struct{}                     // closed when the server has been stopped.
 	ns               naming.Namespace
 	servesMountTable bool
-	reservedOpt      options.ReservedNameDispatcher
+	// TODO(cnicolaou): remove this when the publisher tracks published names
+	// and can return an appropriate error for RemoveName on a name that
+	// wasn't 'Added' for this server.
+	names       map[string]struct{}
+	reservedOpt options.ReservedNameDispatcher
 	// TODO(cnicolaou): add roaming stats to ipcStats
 	stats *ipcStats // stats for this server.
 }
@@ -533,51 +537,66 @@
 	}
 }
 
-func (s *server) Serve(name string, obj interface{}) error {
+func (s *server) Serve(name string, obj interface{}, authorizer security.Authorizer) error {
 	if obj == nil {
-		// nil is an allowed value for obj.
-		return s.ServeDispatcher(name, ipc.Dispatcher(nil))
+		// The ReflectInvoker inside the LeafDispatcher will panic
+		// if called for a nil value.
+		return fmt.Errorf("A nil object is not allowed")
 	}
-	// TRANSITION: this will be disallowed when the transition is complete.
-	if disp, ok := obj.(ipc.Dispatcher); ok {
-		return s.ServeDispatcher(name, disp)
-	}
-	// TRANSITION: We may fail the dispatcher type test, but still be a
-	// dispatcher becase our Lookup method returns ipc.Invoker and not a
-	// raw object. This code here will detect that case and panic as an aid
-	// to catching these cases early.
-	typ := reflect.TypeOf(obj)
-	if lookup, found := typ.MethodByName("Lookup"); found {
-		if lookup.Type.NumIn() == 3 && lookup.Type.NumOut() == 3 {
-			inv := lookup.Type.Out(0)
-			if inv.Name() == "Invoker" {
-				panic(fmt.Sprintf("%q has a Lookup that returns an Invoker", lookup.Name))
-			}
-		}
-	}
-	// TRANSITION: this will go away in the transition.
-	panic("should never get here")
+	return s.ServeDispatcher(name, ipc.LeafDispatcher(obj, authorizer))
 }
 
 func (s *server) ServeDispatcher(name string, disp ipc.Dispatcher) error {
-	defer vlog.LogCall()()
 	s.Lock()
 	defer s.Unlock()
 	if s.stopped {
 		return errServerStopped
 	}
-	if s.disp != nil && disp != nil && s.disp != disp {
-		return fmt.Errorf("attempt to change dispatcher")
+	if disp == nil {
+		return fmt.Errorf("A nil dispacther is not allowed")
 	}
-	if disp != nil {
-		s.disp = disp
+	if s.disp != nil {
+		return fmt.Errorf("Serve or ServeDispatcher has already been called")
 	}
+	s.disp = disp
+	s.names = make(map[string]struct{})
 	if len(name) > 0 {
 		s.publisher.AddName(name)
+		s.names[name] = struct{}{}
 	}
 	return nil
 }
 
+func (s *server) AddName(name string) error {
+	s.Lock()
+	defer s.Unlock()
+	if s.stopped {
+		return errServerStopped
+	}
+	if len(name) == 0 {
+		return fmt.Errorf("empty name")
+	}
+	s.publisher.AddName(name)
+	// TODO(cnicolaou): remove this map when the publisher's RemoveName
+	// method returns an error.
+	s.names[name] = struct{}{}
+	return nil
+}
+
+func (s *server) RemoveName(name string) error {
+	s.Lock()
+	defer s.Unlock()
+	if s.stopped {
+		return errServerStopped
+	}
+	if _, present := s.names[name]; !present {
+		return fmt.Errorf("%q has not been previously used for this server", name)
+	}
+	s.publisher.RemoveName(name)
+	delete(s.names, name)
+	return nil
+}
+
 func (s *server) Stop() error {
 	defer vlog.LogCall()()
 	s.Lock()