All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.backendless.rt.rso.SharedObjectImpl Maven / Gradle / Ivy

The newest version!
package com.backendless.rt.rso;

import com.backendless.BackendlessInjector;
import com.backendless.async.callback.AsyncCallback;
import com.backendless.exceptions.BackendlessException;
import com.backendless.exceptions.BackendlessFault;
import com.backendless.rt.ConnectListener;
import com.backendless.rt.MethodRequestHelper;
import com.backendless.rt.MethodTypes;
import com.backendless.rt.RTCallback;
import com.backendless.rt.RTCallbackWithFault;
import com.backendless.rt.RTClient;
import com.backendless.rt.RTMethodRequest;
import com.backendless.rt.SubscriptionNames;
import com.backendless.rt.command.Command;
import com.backendless.rt.command.CommandListener;
import com.backendless.rt.users.UserInfo;
import com.backendless.rt.users.UserStatus;
import com.backendless.utils.WeborbSerializationHelper;
import weborb.exceptions.AdaptingException;
import weborb.reader.ArrayType;
import weborb.types.IAdaptingType;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;


public class SharedObjectImpl implements SharedObject
{
  private static final Logger logger = Logger.getLogger( "SharedObject" );

  private final String name;
  private final RTClient rtClient = BackendlessInjector.getInstance().getRtClient();
  private final CopyOnWriteArrayList subscriptions = new CopyOnWriteArrayList<>();

  private Object invocationTarget;
  private AsyncCallback invocationCallback;

  private final ConnectListener connectListener;
  private final CommandListener commandListener = new CommandListener()
  {

    @Override
    public CopyOnWriteArrayList getSubscriptionHolder()
    {
      return subscriptions;
    }

    @Override
    public RSOSubscription createSubscription( RTCallback rtCallback )
    {
      return RSOSubscription.command( name, rtCallback );
    }

    @Override
    public SOCommandRequest createCommandRequest( RTCallback rtCallback )
    {
      return new SOCommandRequest( name, rtCallback );
    }

    @Override
    public boolean isConnected()
    {
      return connectListener.isConnected();
    }
  };

  SharedObjectImpl( final String name )
  {
    this.name = name;

    connectListener = new ConnectListener( name )
    {
      @Override
      public void connected()
      {
        for( RSOSubscription subscription : subscriptions )
        {
          rtClient.subscribe( subscription );
        }

        commandListener.connected();
      }

      @Override
      public RSOSubscription createSubscription( RTCallback callback )
      {
        return RSOSubscription.connect( name, callback );
      }
    };

    final RSOSubscription invocationSubscription = RSOSubscription.invoke( name, new RTCallbackWithFault()
    {
      @Override
      public AsyncCallback usersCallback()
      {
        return null;
      }

      @Override
      public void handleResponse( IAdaptingType response )
      {
        logger.fine( "handle invocation" );

        String methodName = WeborbSerializationHelper.asString( response, "method" );

        logger.fine( "invocation for method - " + methodName );

        ArrayType arg = (ArrayType) WeborbSerializationHelper.asAdaptingType( response, "args" );

        if( invocationTarget != null )
          try
          {
            Object result = InvocationHelper.invoke( invocationTarget, methodName, arg );
            logger.log( Level.FINE, "Invocation result {0}", new Object[] { result } );

            if( invocationCallback != null )
              invocationCallback.handleResponse( result );
          }
          catch( BackendlessException e )
          {
            logger.warning( "Invocation fault: " + e.getMessage() );
            if( invocationCallback != null )
              invocationCallback.handleFault( new BackendlessFault( e ) );
          }
          catch( NoSuchMethodException | IllegalAccessException | AdaptingException | InvocationTargetException e )
          {
            logger.warning( "Invocation fault: " + e.getMessage() );
            if( invocationCallback != null )
              invocationCallback.handleFault( new BackendlessFault( e.getMessage() ) );
          }
      }
    } );

    addListener( invocationSubscription );
  }

  @Override
  public void addConnectListener( AsyncCallback callback )
  {
    connectListener.addConnectListener( callback );
  }

  @Override
  public void removeConnectListener( AsyncCallback callback )
  {
    connectListener.removeConnectListener( callback );
  }

  @Override
  public void removeConnectListeners()
  {
    connectListener.removeConnectListeners();
  }

  @Override
  public void addChangesListener( final AsyncCallback callback )
  {
    checkCallback( callback );

    RTCallback rtCallback = new RTCallbackWithFault()
    {
      @Override
      public AsyncCallback usersCallback()
      {
        return callback;
      }

      @Override
      public void handleResponse( IAdaptingType response )
      {
        SharedObjectChanges sharedObjectChanges = new SharedObjectChanges();

        UserInfo userInfo = new UserInfo();

        sharedObjectChanges.setUserInfo( userInfo );

        userInfo.setConnectionId( WeborbSerializationHelper.asString( response, "connectionId" ) );
        userInfo.setUserId( WeborbSerializationHelper.asString( response, "userId" ) );

        final String key = WeborbSerializationHelper.asString( response, "key" );
        sharedObjectChanges.setKey( key );

        IAdaptingType data = WeborbSerializationHelper.asAdaptingType( response, "data" );

        final Object value = data.defaultAdapt();
        sharedObjectChanges.setValue( value );
        callback.handleResponse( sharedObjectChanges );
      }
    };

    addListener( RSOSubscription.changes( name, rtCallback ) );
  }

  private void checkCallback( AsyncCallback callback )
  {
    if( callback == null )
      throw new BackendlessException( "calback can not be null" );
  }

  @Override
  public void removeChangesListener( AsyncCallback callback )
  {
    removeSubscription( callback );
  }

  @Override
  public void removeChangesListeners()
  {
    removeSubscription( SubscriptionNames.RSO_CHANGES );
  }

  @Override
  public void addClearListener( final AsyncCallback callback )
  {
    checkCallback( callback );
    RTCallback rtCallback = new RTCallbackWithFault()
    {
      @Override
      public AsyncCallback usersCallback()
      {
        return callback;
      }

      @Override
      public void handleResponse( IAdaptingType response )
      {
        final UserInfo userInfo;
        try
        {
          userInfo = (UserInfo) response.adapt( UserInfo.class );
        }
        catch( AdaptingException e )
        {
          handleFault( new BackendlessFault( e.getMessage() ) );
          return;
        }

        callback.handleResponse( userInfo );
      }
    };

    addListener( RSOSubscription.cleared( name, rtCallback ) );
  }

  @Override
  public void removeClearListener( AsyncCallback callback )
  {
    removeSubscription( callback );
  }

  @Override
  public void removeClearListeners()
  {
    removeSubscription( SubscriptionNames.RSO_CLEARED );
  }

  @Override
  public void addCommandListener( AsyncCallback> callback )
  {
    commandListener.addCommandListener( String.class, callback );
  }

  @Override
  public  void addCommandListener( Class dataType, AsyncCallback> callback )
  {
    commandListener.addCommandListener( dataType, callback );
  }

  @Override
  public void removeCommandListener( AsyncCallback callback )
  {
    commandListener.removeCommandListener( callback );
  }

  @Override
  public void removeCommandListeners()
  {
    removeSubscription( SubscriptionNames.RSO_COMMANDS );
  }

  @Override
  public void addUserStatusListener( final AsyncCallback callback )
  {
    checkCallback( callback );

    RTCallback rtCallback = new RTCallbackWithFault()
    {
      @Override
      public AsyncCallback usersCallback()
      {
        return callback;
      }

      @Override
      public void handleResponse( IAdaptingType response )
      {
        try
        {
          UserStatus userStatus = (UserStatus) response.adapt( UserStatus.class );
          callback.handleResponse( userStatus );
        }
        catch( AdaptingException e )
        {
          callback.handleFault( new BackendlessFault( e.getMessage() ) );
        }
      }
    };

    addListener( RSOSubscription.userStatus( name, rtCallback ) );
  }

  @Override
  public void removeUserStatusListener( AsyncCallback callback )
  {
    removeSubscription( callback );
  }

  @Override
  public void removeUserStatusListeners()
  {
    removeSubscription( SubscriptionNames.RSO_USERS );
  }

  @Override
  public void set( final String key, final Object value, AsyncCallback callback )
  {
    new MethodRequestHelper( connectListener )
    {
      @Override
      public RTMethodRequest createMethodRequest( RTCallback rtCallback )
      {
        return new SOMethodRequest( name, MethodTypes.RSO_SET, rtCallback ).putMethodOption( "key", key ).putMethodOption( "data", value );
      }
    }.invoke( callback );
  }

  @Override
  public void set( String key, Object value )
  {
    set( key, value, null );
  }

  @Override
  public void get( String key, AsyncCallback callback )
  {
    get( key, String.class, callback );
  }

  @Override
  public  void get( final String key, Class dataType, AsyncCallback callback )
  {
    new MethodRequestHelper( connectListener )
    {
      @Override
      public RTMethodRequest createMethodRequest( RTCallback rtCallback )
      {
        return new SOMethodRequest( name, MethodTypes.RSO_GET, rtCallback ).putMethodOption( "key", key );
      }
    }.invoke( dataType, callback );
  }

  @Override
  public void clear( final AsyncCallback callback )
  {
    new MethodRequestHelper( connectListener )
    {
      @Override
      public RTMethodRequest createMethodRequest( RTCallback rtCallback )
      {
        return new SOMethodRequest( name, MethodTypes.RSO_CLEAR, rtCallback );
      }
    }.invoke( callback );
  }

  @Override
  public void clear()
  {
    clear( null );
  }

  @Override
  public void sendCommand( String type, Object value )
  {
    commandListener.sendCommand( type, value, null );
  }

  @Override
  public void sendCommand( String type, Object value, AsyncCallback callback )
  {
    commandListener.sendCommand( type, value, callback );
  }

  @Override
  public void invoke( String methodName, Object... args )
  {
    invoke( methodName, args, null, null );
  }

  @Override
  public void invoke( String methodName, Object[] args, AsyncCallback callback )
  {
    invoke( methodName, args, null, callback );
  }

  @Override
  public void invoke( final String methodName, final Object[] args, final Collection target, AsyncCallback callback )
  {
    new MethodRequestHelper( connectListener )
    {
      @Override
      public RTMethodRequest createMethodRequest( RTCallback rtCallback )
      {
        return new SOMethodRequest( name, MethodTypes.RSO_INVOKE, rtCallback ).putMethodOption( "method", methodName ).putMethodOption( "args", args ).putMethodOption( "targets", target );
      }
    }.invoke( callback );
  }

  @Override
  public void setInvocationTarget( Object target )
  {
    invocationTarget = target;
  }

  @Override
  public void setInvocationTarget( Object target, AsyncCallback callback )
  {
    setInvocationTarget( target );
    invocationCallback = callback;
  }

  @Override
  public void connect()
  {
    connectListener.connect();
  }

  @Override
  public void disconnect()
  {
    connectListener.disconnect();
  }

  @Override
  public boolean isConnected()
  {
    return connectListener.isConnected();
  }

  private void addListener( RSOSubscription subscription )
  {
    subscriptions.add( subscription );

    if( isConnected() )
      rtClient.subscribe( subscription );
  }

  private void removeSubscription( AsyncCallback callback )
  {
    for( RSOSubscription subscription : subscriptions )
    {
      if( subscription.getCallback() == callback )
        removeSubscription( subscription );
    }
  }

  private void removeSubscription( SubscriptionNames subscriptionName )
  {
    for( RSOSubscription subscription : subscriptions )
    {
      if( subscription.getSubscriptionName() == subscriptionName )
        removeSubscription( subscription );
    }
  }

  private void removeSubscription( RSOSubscription subscription )
  {
    //we can do it because it is CopyOnWriteArrayList so we iterate through the copy
    subscriptions.remove( subscription );

    if( isConnected() )
    {
      rtClient.unsubscribe( subscription.getId() );
    }
  }
}