cometd-java/cometd-java-server/cometd-java-server-common/src/main/java/org/cometd/server/AbstractService.java
/**
     * <p>Maps the method of a subclass with the given name to a
     * {@link ServerChannel.MessageListener} on the given channel, so that the method
     * is invoked for each message received on the channel.</p>
     * <p>The channel name may be a {@link ServerChannel#isWild() wildcard channel name}.</p>
     * <p>The method must have a unique name and the following signature:</p>
     * <ul>
     * <li><code>myMethod(ServerSession from, ServerMessage message)</code></li>
     * </ul>
     * <p>Typically a service will be used to a channel in the <code>/service/**</code>
     * space which is not a broadcast channel.</p>
     * <p>Any object returned by a mapped method is delivered back to the
     * client that sent the message and not broadcast. If the method returns void or null,
     * then no response is sent.</p>
     * <p>A mapped method may also call {@link #send(org.cometd.bayeux.server.ServerSession, String, Object)}
     * to deliver message(s) to specific clients and/or channels.</p>
     * <p>A mapped method may also publish to different channels via
     * {@link ServerChannel#publish(Session, ServerMessage.Mutable, Promise)}.</p>
     *
     * @param channelName The channel to listen to
     * @param methodName  The name of the method on this subclass to call when messages
     *                    are received on the channel
     * @see #removeService(String, String)
     */
Maps the method of a subclass with the given name to a
ServerChannel.MessageListener on the given channel, so that the method
is invoked for each message received on the channel.
The channel name may be a  ServerChannel#isWild() wildcard channel name.
The method must have a unique name and the following signature:

myMethod(ServerSession from, ServerMessage message)

Typically a service will be used to a channel in the /service
space which is not a broadcast channel.
Any object returned by a mapped method is delivered back to the
client that sent the message and not broadcast. If the method returns void or null,
then no response is sent.
A mapped method may also call  #send(org.cometd.bayeux.server.ServerSession, String, Object)
to deliver message(s) to specific clients and/or channels.
A mapped method may also publish to different channels via
ServerChannel#publish(Session, ServerMessage.Mutable, Promise).

@param channelName The channel to listen to
@param methodName  The name of the method on this subclass to call when messages
are received on the channel
@see #removeService(String, String)
Maps the method of a subclass with the given name to a ServerChannel . MessageListener on the given channel so that the method is invoked for each message received on the channel . The channel name may be a ServerChannel#isWild () wildcard channel name . The method must have a unique name and the following signature : myMethod ( ServerSession from ServerMessage message ) Typically a service will be used to a channel in the / service space which is not a broadcast channel . Any object returned by a mapped method is delivered back to the client that sent the message and not broadcast . If the method returns void or null then no response is sent . A mapped method may also call #send ( org . cometd . bayeux . server . ServerSession String Object ) to deliver message ( s ) to specific clients and / or channels . A mapped method may also publish to different channels via ServerChannel#publish ( Session ServerMessage . Mutable Promise ) . @param channelName The channel to listen to @param methodName The name of the method on this subclass to call when messages are received on the channel @see #removeService ( String String )
protected void addService(String channelName, String methodName) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Mapping {}#{} to {}", _name, methodName, channelName);
        }
        Method candidate = null;
        Class<?> c = this.getClass();
        while (c != null && c != AbstractService.class) {
            Method[] methods = c.getDeclaredMethods();
            for (int i = methods.length; i-- > 0; ) {
                Method method = methods[i];
                if (methodName.equals(method.getName()) && Modifier.isPublic(method.getModifiers())) {
                    if (candidate != null) {
                        throw new IllegalArgumentException("Multiple service methods called '" + methodName + "'");
                    }
                    candidate = method;
                }
            }
            c = c.getSuperclass();
        }
        if (candidate == null) {
            throw new NoSuchMethodError("Cannot find public service method '" + methodName + "'");
        }
        int params = candidate.getParameterTypes().length;
        if (params != 2) {
            throw new IllegalArgumentException("Service method '" + methodName + "' must have 2 parameters");
        }
        if (!ServerSession.class.isAssignableFrom(candidate.getParameterTypes()[0])) {
            throw new IllegalArgumentException("Service method '" + methodName + "' does not have " + ServerSession.class.getName() + " as first parameter");
        }
        if (!ServerMessage.class.isAssignableFrom(candidate.getParameterTypes()[1])) {
            throw new IllegalArgumentException("Service method '" + methodName + "' does not have " + ServerMessage.class.getName() + " as second parameter");
        }
        ServerChannel channel = _bayeux.createChannelIfAbsent(channelName).getReference();
        Invoker invoker = new Invoker(channelName, candidate);
        channel.addListener(invoker);
        invokers.put(methodName, invoker);
    }
protected void addService ( String channelName , String methodName ) { if ( LOGGER . isDebugEnabled ( ) ) { LOGGER . debug ( "Mapping {}#{} to {}" , _name , methodName , channelName ) ; } Method candidate = null ; Class < ? > c = this . getClass ( ) ; while ( c != null && c != AbstractService . class ) { Method [ ] methods = c . getDeclaredMethods ( ) ; for ( int i = methods . length ; i -- > 0 ; ) { Method method = methods [ i ] ; if ( methodName . equals ( method . getName ( ) ) && Modifier . isPublic ( method . getModifiers ( ) ) ) { if ( candidate != null ) { throw new IllegalArgumentException ( "Multiple service methods called '" + methodName + "'" ) ; } candidate = method ; } } c = c . getSuperclass ( ) ; } if ( candidate == null ) { throw new NoSuchMethodError ( "Cannot find public service method '" + methodName + "'" ) ; } int params = candidate . getParameterTypes ( ) . length ; if ( params != 2 ) { throw new IllegalArgumentException ( "Service method '" + methodName + "' must have 2 parameters" ) ; } if ( ! ServerSession . class . isAssignableFrom ( candidate . getParameterTypes ( ) [ 0 ] ) ) { throw new IllegalArgumentException ( "Service method '" + methodName + "' does not have " + ServerSession . class . getName ( ) + " as first parameter" ) ; } if ( ! ServerMessage . class . isAssignableFrom ( candidate . getParameterTypes ( ) [ 1 ] ) ) { throw new IllegalArgumentException ( "Service method '" + methodName + "' does not have " + ServerMessage . class . getName ( ) + " as second parameter" ) ; } ServerChannel channel = _bayeux . createChannelIfAbsent ( channelName ) . getReference ( ) ; Invoker invoker = new Invoker ( channelName , candidate ) ; channel . addListener ( invoker ) ; invokers . put ( methodName , invoker ) ; }
<p>Maps the method of a subclass with the given name to a
 {@link ServerChannel.MessageListener} on the given channel, so that the method
 is invoked for each message received on the channel.</p>
 <p>The channel name may be a {@link ServerChannel#isWild() wildcard channel name}.</p>
 <p>The method must have a unique name and the following signature:</p>
 <ul>
 <li><code>myMethod(ServerSession from, ServerMessage message)</code></li>
 </ul>
 <p>Typically a service will be used to a channel in the <code>/service/**</code>
 space which is not a broadcast channel.</p>
 <p>Any object returned by a mapped method is delivered back to the
 client that sent the message and not broadcast.
<p > Maps the method of a subclass with the given name to a { @link ServerChannel . MessageListener } on the given channel so that the method is invoked for each message received on the channel . < / p > <p > The channel name may be a { @link ServerChannel#isWild () wildcard channel name } . < / p > <p > The method must have a unique name and the following signature : < / p > <ul > <li > <code > myMethod ( ServerSession from ServerMessage message ) < / code > < / li > < / ul > <p > Typically a service will be used to a channel in the <code > / service / ** < / code > space which is not a broadcast channel . < / p > <p > Any object returned by a mapped method is delivered back to the client that sent the message and not broadcast .