diff options
-rw-r--r-- | src/main/java/org/openslx/thrifthelper/ThriftHandler.java | 76 | ||||
-rw-r--r-- | src/main/java/org/openslx/thrifthelper/ThriftManager.java | 216 |
2 files changed, 173 insertions, 119 deletions
diff --git a/src/main/java/org/openslx/thrifthelper/ThriftHandler.java b/src/main/java/org/openslx/thrifthelper/ThriftHandler.java index ed66678..0d30ccb 100644 --- a/src/main/java/org/openslx/thrifthelper/ThriftHandler.java +++ b/src/main/java/org/openslx/thrifthelper/ThriftHandler.java @@ -11,91 +11,101 @@ import org.apache.log4j.Logger; import org.apache.thrift.TException; import org.apache.thrift.transport.TTransportException; -public class ThriftHandler<T extends Object> implements InvocationHandler { +class ThriftHandler<T extends Object> implements InvocationHandler +{ - private final static Logger LOGGER = Logger.getLogger(ThriftHandler.class); - - public interface ClientCreationCallback<T> { - public T get(); + private final static Logger LOGGER = Logger.getLogger( ThriftHandler.class ); + + public interface EventCallback<T> + { + public T getNewClient(); + + public void error( Throwable t, String message ); } private final ThreadLocal<T> clients = new ThreadLocal<T>(); - private final ClientCreationCallback<T> callback; + private final EventCallback<T> callback; - public ThriftHandler(final Class<T> clazz, ClientCreationCallback<T> cb) { + public ThriftHandler( final Class<T> clazz, EventCallback<T> cb ) + { callback = cb; - thriftMethods = Collections.unmodifiableSet(new HashSet<String>() { + thriftMethods = Collections.unmodifiableSet( new HashSet<String>() { private static final long serialVersionUID = 8983506538154055231L; { Method[] methods = clazz.getMethods(); - for (int i = 0; i < methods.length; i++) { + for ( int i = 0; i < methods.length; i++ ) { boolean thrift = false; Class<?>[] type = methods[i].getExceptionTypes(); - for (int e = 0; e < type.length; e++) { - if (TException.class.isAssignableFrom(type[e])) + for ( int e = 0; e < type.length; e++ ) { + if ( TException.class.isAssignableFrom( type[e] ) ) thrift = true; } String name = methods[i].getName(); - if (thrift && !name.startsWith("send_") && !name.startsWith("recv_")) { - add(name); + if ( thrift && !name.startsWith( "send_" ) && !name.startsWith( "recv_" ) ) { + add( name ); } } } - }); + } ); } private final Set<String> thriftMethods; - public Object invoke(Object tproxy, Method method, Object[] args) throws Throwable { + public Object invoke( Object tproxy, Method method, Object[] args ) throws Throwable + { // first find the thrift methods - if (!thriftMethods.contains(method.getName())) { + if ( !thriftMethods.contains( method.getName() ) ) { try { - return method.invoke(method, args); - } catch (InvocationTargetException e) { + return method.invoke( method, args ); + } catch ( InvocationTargetException e ) { // TODO Auto-generated catch block Throwable cause = e.getCause(); - if (cause == null) { + if ( cause == null ) { throw new RuntimeException(); } throw cause; } } - LOGGER.debug("Proxying '" + method.getName() + "'"); + LOGGER.debug( "Proxying '" + method.getName() + "'" ); - T client = getClient(false); + T client = getClient( false ); Throwable cause = null; - for (int i = 0; i < 3; i++) { + for ( int i = 0; i < 3; i++ ) { try { - return method.invoke(client, args); - } catch (InvocationTargetException e) { + return method.invoke( client, args ); + } catch ( InvocationTargetException e ) { cause = e.getCause(); - if (cause instanceof TTransportException) { - LOGGER.debug("Transport error - re-initialising ..."); + if ( cause instanceof TTransportException ) { + LOGGER.debug( "Transport error - re-initialising ..." ); // new client - client = getClient(true); + client = getClient( true ); } } } + + // Uh oh + callback.error( cause, "Could not reconnect to thrift server - network or server down?" ); - if (cause != null) + if ( cause != null ) throw cause; return null; } - private T getClient(boolean forceNew) { + private T getClient( boolean forceNew ) + { T client = clients.get(); - if (client != null && !forceNew) { + if ( client != null && !forceNew ) { return client; } - client = callback.get(); - if (client == null) { + client = callback.getNewClient(); + if ( client == null ) { // TODO own exception throw new RuntimeException(); } - clients.set(client); + clients.set( client ); return client; } } diff --git a/src/main/java/org/openslx/thrifthelper/ThriftManager.java b/src/main/java/org/openslx/thrifthelper/ThriftManager.java index c6d8986..6072030 100644 --- a/src/main/java/org/openslx/thrifthelper/ThriftManager.java +++ b/src/main/java/org/openslx/thrifthelper/ThriftManager.java @@ -1,8 +1,6 @@ package org.openslx.thrifthelper; import java.lang.reflect.Proxy; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.apache.log4j.Logger; import org.apache.thrift.protocol.TBinaryProtocol; @@ -13,135 +11,181 @@ import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TTransportException; import org.openslx.imagemaster.thrift.iface.ImageServer; import org.openslx.sat.thrift.iface.Server; -import org.openslx.thrifthelper.ThriftHandler.ClientCreationCallback; +import org.openslx.thrifthelper.ThriftHandler.EventCallback; -public class ThriftManager { +public class ThriftManager +{ - private final static Logger LOGGER = Logger.getLogger(ThriftManager.class); - - /** - * Public variables to represent client types - * TODO: Public needed? - */ - public static enum ClientType { - MASTER, SATELLITE + private final static Logger LOGGER = Logger.getLogger( ThriftManager.class ); + + public interface ErrorCallback + { + /** + * Called if connecting/reconnecting to the thrift server failed. + * + * @param t the exception that occured last (may be null) + * @param message an optional message describing the circumstances + */ + public void thriftError( Throwable t, String message ); } + + private static ErrorCallback _errorCallback = null; + /** - * Private singleton instances of itself and the satellite/master clients + * Private members for master connection information */ - private static Server.Iface _satClient = (Server.Iface) Proxy.newProxyInstance( - Server.Iface.class.getClassLoader(), - new Class[] { Server.Iface.class }, new ThriftHandler<Server.Client>(Server.Client.class, new ClientCreationCallback<Server.Client>() { + private static final String MASTERSERVER_ADDRESS = "bwlp-masterserver.ruf.uni-freiburg.de"; + private static final int MASTERSERVER_PORT = 9090; + private static final int MASTERSERVER_TIMEOUT = 15000; - @Override - public Server.Client get() { - // first check if we have a sat ip - if (SATELLITE_IP == null) { - LOGGER.error("Satellite ip adress was not set prior to getting the sat client. Use setSatellite(<ip>)."); - return null; - } - // ok lets do it - TTransport transport = - new TSocket(SATELLITE_IP, SATELLITE_PORT, SATELLITE_TIMEOUT); - try { - transport.open(); - } catch (TTransportException e) { - LOGGER.error("Could not open transport to thrift's server with IP: " + SATELLITE_IP); - return null; - } - final TProtocol protocol = new TBinaryProtocol(transport); - // now we are ready to create the client, according to ClientType! - LOGGER.info("Satellite '" + SATELLITE_IP + "' reachable. Client initialised."); - return new Server.Client(protocol); - } - })); + /** + * Private members for satellite connection information + */ + private static String SATELLITE_IP = null; + private static final int SATELLITE_PORT = 9090; + private static final int SATELLITE_TIMEOUT = 15000; - private static ImageServer.Iface _masterClient = (ImageServer.Iface) Proxy.newProxyInstance( + /** + * Sat connection. Initialized when we know the sat server IP. + */ + private static Server.Iface _satClient = null; + + /** + * Master connection. As its address is known in advance, create the object right away. + */ + private static ImageServer.Iface _masterClient = (ImageServer.Iface)Proxy.newProxyInstance( ImageServer.Iface.class.getClassLoader(), - new Class[] { ImageServer.Iface.class }, new ThriftHandler<ImageServer.Client>(ImageServer.Client.class, new ClientCreationCallback<ImageServer.Client>() { + new Class[] { ImageServer.Iface.class }, new ThriftHandler<ImageServer.Client>( ImageServer.Client.class, new EventCallback<ImageServer.Client>() { @Override - public ImageServer.Client get() { + public ImageServer.Client getNewClient() + { // ok lets do it - TTransport transport = - new TFramedTransport(new TSocket(MASTERSERVER_IP, MASTERSERVER_PORT, MASTERSERVER_TIMEOUT)); + TTransport transport = + new TFramedTransport( new TSocket( MASTERSERVER_ADDRESS, MASTERSERVER_PORT, MASTERSERVER_TIMEOUT ) ); try { transport.open(); - } catch (TTransportException e) { - LOGGER.error("Could not open transport to thrift's server with IP: " + MASTERSERVER_IP); + } catch ( TTransportException e ) { + LOGGER.error( "Could not open transport to thrift's server with IP: " + MASTERSERVER_ADDRESS ); + transport.close(); return null; } - final TProtocol protocol = new TBinaryProtocol(transport); + final TProtocol protocol = new TBinaryProtocol( transport ); // now we are ready to create the client, according to ClientType! - return new ImageServer.Client(protocol); + return new ImageServer.Client( protocol ); } - })); - /** - * Private members for master connection information - */ - private static final String MASTERSERVER_IP = "132.230.4.16"; - private static final int MASTERSERVER_PORT = 9090; - private static final int MASTERSERVER_TIMEOUT = 30000; - - - /** - * Private members for satellite connection information - */ - private static String SATELLITE_IP = null; - private static final int SATELLITE_PORT = 9090; - private static final int SATELLITE_TIMEOUT = 10000; - + + @Override + public void error( Throwable t, String message ) + { + synchronized ( LOGGER ) { + if ( _errorCallback != null ) + _errorCallback.thriftError( t, message ); + } + } + } ) ); + /** * IP Validation Regex */ - private static final String IP_VALID_PATTERN = - "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + - "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + - "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + - "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"; + private static final String IP_VALID_PATTERN = + "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"; /** * Sets the IP of the satellite to connect to + * * @param ip the ip of the satellite as String * @return true if setting the ip worked, false otherwise */ - public static boolean setSatellite(String ip) { - if (ip.isEmpty()) { - LOGGER.error("Given IP for satellite is empty."); + public static boolean setSatellite( String ip ) + { + if ( ip.isEmpty() ) { + LOGGER.error( "Given IP for satellite is empty." ); return false; } // validate - Matcher matcher = Pattern.compile(IP_VALID_PATTERN).matcher(ip); - if (!matcher.matches()) { - LOGGER.error("Given form of IP is invalid: " + ip); + if ( !ip.matches( IP_VALID_PATTERN ) ) { + LOGGER.error( "Given form of IP is invalid: " + ip ); return false; } // finally set it SATELLITE_IP = ip; - // last check: try to connect - if (getSatClient() == null) { - // init failed - LOGGER.error("Could not initialise new client to satellite: " + SATELLITE_IP); - return false; - } - // TODO final last: get version from server + // Create monster proxy class from interface + _satClient = (Server.Iface)Proxy.newProxyInstance( + Server.Iface.class.getClassLoader(), + new Class[] { Server.Iface.class }, new ThriftHandler<Server.Client>( Server.Client.class, new EventCallback<Server.Client>() { + + @Override + public Server.Client getNewClient() + { + // first check if we have a sat ip + if ( SATELLITE_IP == null ) { + LOGGER.error( "Satellite ip adress was not set prior to getting the sat client. Use setSatellite(<ip>)." ); + return null; + } + // ok lets do it + TTransport transport = + new TSocket( SATELLITE_IP, SATELLITE_PORT, SATELLITE_TIMEOUT ); + try { + transport.open(); + } catch ( TTransportException e ) { + LOGGER.error( "Could not open transport to thrift's server with IP: " + SATELLITE_IP ); + transport.close(); + return null; + } + final TProtocol protocol = new TBinaryProtocol( transport ); + // now we are ready to create the client, according to ClientType! + LOGGER.info( "Satellite '" + SATELLITE_IP + "' reachable. Client initialised." ); + return new Server.Client( protocol ); + } + + @Override + public void error( Throwable t, String message ) + { + synchronized ( LOGGER ) { + if ( _errorCallback != null ) + _errorCallback.thriftError( t, message ); + } + } + } ) ); return true; } - /** + + /** * Returns the singleton client of the thrift connection to the satellite + * * @return the thrift client to the satellite server */ - public static Server.Iface getSatClient() { - return _satClient; + public static Server.Iface getSatClient() + { + return _satClient; } - + /** * Returns the singleton client of the master thrift connection + * * @return the thrift client to the master server */ - public static ImageServer.Iface getMasterClient() { + public static ImageServer.Iface getMasterClient() + { return _masterClient; } + + /** + * Set the callback class for errors that occur on one of the + * thrift connections. + * + * @param cb + */ + public static void setErrorCallback( ErrorCallback cb ) + { + synchronized ( LOGGER ) { + _errorCallback = cb; + } + } } |