Added some message delegator util classes that
makes it easier to handle network messages. These delegators can introspect a delegate type to find message-type specific handler methods. This mapping can be done automatically or performed manually.
This commit is contained in:
parent
1fec72605f
commit
c9eaeeea12
@ -0,0 +1,313 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network.util;
|
||||||
|
|
||||||
|
import com.jme3.network.Message;
|
||||||
|
import com.jme3.network.MessageConnection;
|
||||||
|
import com.jme3.network.MessageListener;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MessageListener implementation that will forward messages to methods
|
||||||
|
* of a delegate object. These methods can be automapped or manually
|
||||||
|
* specified. Subclasses provide specific implementations for how to
|
||||||
|
* find the actual delegate object.
|
||||||
|
*
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public abstract class AbstractMessageDelegator<S extends MessageConnection>
|
||||||
|
implements MessageListener<S> {
|
||||||
|
|
||||||
|
static final Logger log = Logger.getLogger(AbstractMessageDelegator.class.getName());
|
||||||
|
|
||||||
|
private Class delegateType;
|
||||||
|
private Map<Class, Method> methods = new HashMap<Class, Method>();
|
||||||
|
private Class[] messageTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an AbstractMessageDelegator that will forward received
|
||||||
|
* messages to methods of the specified delegate type. If automap
|
||||||
|
* is true then reflection is used to lookup probably message handling
|
||||||
|
* methods.
|
||||||
|
*/
|
||||||
|
protected AbstractMessageDelegator( Class delegateType, boolean automap ) {
|
||||||
|
this.delegateType = delegateType;
|
||||||
|
if( automap ) {
|
||||||
|
automap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the array of messages known to be handled by this message
|
||||||
|
* delegator.
|
||||||
|
*/
|
||||||
|
public Class[] getMessageTypes() {
|
||||||
|
if( messageTypes == null ) {
|
||||||
|
messageTypes = methods.keySet().toArray(new Class[methods.size()]);
|
||||||
|
}
|
||||||
|
return messageTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the specified method is valid for the specified
|
||||||
|
* message type. This is used internally during automapping to
|
||||||
|
* provide implementation specific filting of methods.
|
||||||
|
* This implementation checks for methods that take either no
|
||||||
|
* arguments, the connection and message type arguments (in that order),
|
||||||
|
* or just the message type or connection argument.
|
||||||
|
*/
|
||||||
|
protected boolean isValidMethod( Method m, Class messageType ) {
|
||||||
|
|
||||||
|
if( log.isLoggable(Level.FINEST) ) {
|
||||||
|
log.log(Level.FINEST, "isValidMethod({0}, {1})", new Object[]{m, messageType});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameters must be S and message type or just message type
|
||||||
|
Class<?>[] parms = m.getParameterTypes();
|
||||||
|
if( parms.length != 2 && parms.length != 1 ) {
|
||||||
|
log.finest("Parameter count is not 1 or 2");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int connectionIndex = parms.length > 1 ? 0 : -1;
|
||||||
|
int messageIndex = parms.length > 1 ? 1 : 0;
|
||||||
|
|
||||||
|
if( connectionIndex > 0 && !MessageConnection.class.isAssignableFrom(parms[connectionIndex]) ) {
|
||||||
|
log.finest("First paramter is not a MessageConnection or subclass.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( messageType == null && !Message.class.isAssignableFrom(parms[messageIndex]) ) {
|
||||||
|
log.finest("Second paramter is not a Message or subclass.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if( messageType != null && !parms[messageIndex].isAssignableFrom(messageType) ) {
|
||||||
|
log.log(Level.FINEST, "Second paramter is not a {0}", messageType);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method that returns the message type as
|
||||||
|
* reflecively determined for a particular method. This
|
||||||
|
* only works with methods that actually have arguments.
|
||||||
|
* This implementation returns the last element of the method's
|
||||||
|
* getParameterTypes() array, thus supporting both
|
||||||
|
* method(connection, messageType) as well as just method(messageType)
|
||||||
|
* calling forms.
|
||||||
|
*/
|
||||||
|
protected Class getMessageType( Method m ) {
|
||||||
|
Class<?>[] parms = m.getParameterTypes();
|
||||||
|
return parms[parms.length-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Goes through all of the delegate type's methods to find
|
||||||
|
* a method of the specified name that may take the specified
|
||||||
|
* message type.
|
||||||
|
*/
|
||||||
|
protected Method findDelegate( String name, Class messageType ) {
|
||||||
|
// We do an exhaustive search because it's easier to
|
||||||
|
// check for a variety of parameter types and it's all
|
||||||
|
// that Class would be doing in getMethod() anyway.
|
||||||
|
for( Method m : delegateType.getDeclaredMethods() ) {
|
||||||
|
|
||||||
|
if( !m.getName().equals(name) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( isValidMethod(m, messageType) ) {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the specified method name is allowed.
|
||||||
|
* This is used by automapping to determine if a method
|
||||||
|
* should be rejected purely on name. Default implemention
|
||||||
|
* always returns true.
|
||||||
|
*/
|
||||||
|
protected boolean allowName( String name ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls the map(Set) method with a null argument causing
|
||||||
|
* all available matching methods to mapped to message types.
|
||||||
|
*/
|
||||||
|
protected final void automap() {
|
||||||
|
map((Set<String>)null);
|
||||||
|
if( methods.isEmpty() ) {
|
||||||
|
throw new RuntimeException("No message handling methods found for class:" + delegateType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifically maps the specified methods names, autowiring
|
||||||
|
* the parameters.
|
||||||
|
*/
|
||||||
|
public AbstractMessageDelegator<S> map( String... methodNames ) {
|
||||||
|
Set<String> names = new HashSet<String>( Arrays.asList(methodNames) );
|
||||||
|
map(names);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Goes through all of the delegate type's declared methods
|
||||||
|
* mapping methods that match the current constraints.
|
||||||
|
* If the constraints set is null then allowName() is
|
||||||
|
* checked for names otherwise only names in the constraints
|
||||||
|
* set are allowed.
|
||||||
|
* For each candidate method that passes the above checks,
|
||||||
|
* isValidMethod() is called with a null message type argument.
|
||||||
|
* All methods are made accessible thus supporting non-public
|
||||||
|
* methods as well as public methods.
|
||||||
|
*/
|
||||||
|
protected void map( Set<String> constraints ) {
|
||||||
|
|
||||||
|
if( log.isLoggable(Level.FINEST) ) {
|
||||||
|
log.log(Level.FINEST, "map({0})", constraints);
|
||||||
|
}
|
||||||
|
for( Method m : delegateType.getDeclaredMethods() ) {
|
||||||
|
if( log.isLoggable(Level.FINEST) ) {
|
||||||
|
log.log(Level.FINEST, "Checking method:{0}", m);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( constraints == null && !allowName(m.getName()) ) {
|
||||||
|
log.finest("Name is not allowed.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if( constraints != null && !constraints.contains(m.getName()) ) {
|
||||||
|
log.finest("Name is not in constraints set.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( isValidMethod(m, null) ) {
|
||||||
|
if( log.isLoggable(Level.FINEST) ) {
|
||||||
|
log.log(Level.FINEST, "Adding method mapping:{0} = {1}", new Object[]{getMessageType(m), m});
|
||||||
|
}
|
||||||
|
// Make sure we can access the method even if it's not public or
|
||||||
|
// is in a non-public inner class.
|
||||||
|
m.setAccessible(true);
|
||||||
|
methods.put(getMessageType(m), m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
messageTypes = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually maps a specified method to the specified message type.
|
||||||
|
*/
|
||||||
|
public AbstractMessageDelegator<S> map( Class messageType, String methodName ) {
|
||||||
|
// Lookup the method
|
||||||
|
Method m = findDelegate( methodName, messageType );
|
||||||
|
if( m == null ) {
|
||||||
|
throw new RuntimeException( "Method:" + methodName
|
||||||
|
+ " not found matching signature (MessageConnection, "
|
||||||
|
+ messageType.getName() + ")" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( log.isLoggable(Level.FINEST) ) {
|
||||||
|
log.log(Level.FINEST, "Adding method mapping:{0} = {1}", new Object[]{messageType, m});
|
||||||
|
}
|
||||||
|
methods.put( messageType, m );
|
||||||
|
messageTypes = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mapped method for the specified message type.
|
||||||
|
*/
|
||||||
|
protected Method getMethod( Class c ) {
|
||||||
|
Method m = methods.get(c);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented by subclasses to provide the actual delegate object
|
||||||
|
* against which the mapped message type methods will be called.
|
||||||
|
*/
|
||||||
|
protected abstract Object getSourceDelegate( S source );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the MessageListener's messageReceived()
|
||||||
|
* method that will use the current message type mapping to
|
||||||
|
* find an appropriate message handling method and call it
|
||||||
|
* on the delegate returned by getSourceDelegate().
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void messageReceived( S source, Message msg ) {
|
||||||
|
if( msg == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object delegate = getSourceDelegate(source);
|
||||||
|
if( delegate == null ) {
|
||||||
|
// Means ignore this message/source
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Method m = getMethod(msg.getClass());
|
||||||
|
if( m == null ) {
|
||||||
|
throw new RuntimeException("Delegate method not found for message class:"
|
||||||
|
+ msg.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if( m.getParameterTypes().length > 1 ) {
|
||||||
|
m.invoke( delegate, source, msg );
|
||||||
|
} else {
|
||||||
|
m.invoke( delegate, msg );
|
||||||
|
}
|
||||||
|
} catch( IllegalAccessException e ) {
|
||||||
|
throw new RuntimeException("Error executing:" + m, e);
|
||||||
|
} catch( InvocationTargetException e ) {
|
||||||
|
throw new RuntimeException("Error executing:" + m, e.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network.util;
|
||||||
|
|
||||||
|
import com.jme3.network.MessageConnection;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MessageListener implementation that will forward messages to methods
|
||||||
|
* of a specified delegate object. These methods can be automapped or manually
|
||||||
|
* specified.
|
||||||
|
*
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class ObjectMessageDelegator<S extends MessageConnection> extends AbstractMessageDelegator<S> {
|
||||||
|
|
||||||
|
private Object delegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a MessageListener that will forward mapped message types
|
||||||
|
* to methods of the specified object.
|
||||||
|
* If automap is true then all methods with the proper signature will
|
||||||
|
* be mapped.
|
||||||
|
* <p>Methods of the following signatures are allowed:
|
||||||
|
* <ul>
|
||||||
|
* <li>void someName(S conn, SomeMessage msg)
|
||||||
|
* <li>void someName(Message msg)
|
||||||
|
* </ul>
|
||||||
|
* Where S is the type of MessageConnection and SomeMessage is some
|
||||||
|
* specific concreate Message subclass.
|
||||||
|
*/
|
||||||
|
public ObjectMessageDelegator( Object delegate, boolean automap ) {
|
||||||
|
super(delegate.getClass(), automap);
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object getSourceDelegate( MessageConnection source ) {
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.network.util;
|
||||||
|
|
||||||
|
import com.jme3.network.HostedConnection;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MessageListener implementation that will forward messages to methods
|
||||||
|
* of a delegate specified as a HostedConnection session attribute. This is
|
||||||
|
* useful for handling connection-specific messages from clients that must
|
||||||
|
* delegate to client-specific data objects.
|
||||||
|
* The delegate methods can be automapped or manually specified.
|
||||||
|
*
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class SessionDataDelegator extends AbstractMessageDelegator<HostedConnection> {
|
||||||
|
|
||||||
|
static final Logger log = Logger.getLogger(SessionDataDelegator.class.getName());
|
||||||
|
|
||||||
|
private String attributeName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a MessageListener that will forward mapped message types
|
||||||
|
* to methods of an object specified as a HostedConnection attribute.
|
||||||
|
* If automap is true then all methods with the proper signature will
|
||||||
|
* be mapped.
|
||||||
|
* <p>Methods of the following signatures are allowed:
|
||||||
|
* <ul>
|
||||||
|
* <li>void someName(S conn, SomeMessage msg)
|
||||||
|
* <li>void someName(Message msg)
|
||||||
|
* </ul>
|
||||||
|
* Where S is the type of MessageConnection and SomeMessage is some
|
||||||
|
* specific concreate Message subclass.
|
||||||
|
*/
|
||||||
|
public SessionDataDelegator( Class delegateType, String attributeName, boolean automap ) {
|
||||||
|
super(delegateType, automap);
|
||||||
|
this.attributeName = attributeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the attribute name that will be used to look up the
|
||||||
|
* delegate object.
|
||||||
|
*/
|
||||||
|
public String getAttributeName() {
|
||||||
|
return attributeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called internally when there is no session object
|
||||||
|
* for the current attribute name attached to the passed source
|
||||||
|
* HostConnection. Default implementation logs a warning.
|
||||||
|
*/
|
||||||
|
protected void miss( HostedConnection source ) {
|
||||||
|
log.log(Level.WARNING, "Session data is null for:{0} on connection:{1}", new Object[]{attributeName, source});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the attributeName attribute of the supplied source
|
||||||
|
* HostConnection. If there is no value at that attribute then
|
||||||
|
* the miss() method is called.
|
||||||
|
*/
|
||||||
|
protected Object getSourceDelegate( HostedConnection source ) {
|
||||||
|
Object result = source.getAttribute(attributeName);
|
||||||
|
if( result == null ) {
|
||||||
|
miss(source);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user