Package org.jboss.errai.otec.client

Source Code of org.jboss.errai.otec.client.AbstractOTEngine$DefaultOTOperationsFactory

/*
* Copyright 2013 JBoss, by Red Hat, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jboss.errai.otec.client;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import org.jboss.errai.otec.client.mutation.CharacterMutation;
import org.jboss.errai.otec.client.mutation.Mutation;
import org.jboss.errai.otec.client.mutation.MutationType;
import org.jboss.errai.otec.client.mutation.StringMutation;
import org.jboss.errai.otec.client.operation.OTOperation;
import org.jboss.errai.otec.client.operation.OTOperationImpl;
import org.jboss.errai.otec.client.operation.OTOperationsFactory;
import org.jboss.errai.otec.client.operation.OTOperationsListBuilder;
import org.jboss.errai.otec.client.util.GUIDUtil;

/**
* @author Mike Brock
*/
public abstract class AbstractOTEngine implements OTEngine {
  protected final String engineId;
  protected final PeerState peerState;
  protected final OTEntityState entityState = new OTEntityStateImpl();
  protected volatile OTEngineMode mode = OTEngineMode.Offline;
  protected String name;

  public AbstractOTEngine(final String name, final PeerState peerState) {
    engineId = GUIDUtil.createGUID();
    if (name == null) {
      this.name = engineId;
    }
    else {
      this.name = name;
    }
    this.peerState = peerState;
  }

  @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
  protected OTOperation applyFromRemote(final OTOperation remoteOp) {
    final OTEntity entity = getEntityStateSpace().getEntity(remoteOp.getEntityId());
    synchronized (entity) {
      try {
        getPeerState().flushEntityStreams(entity.getId());
        if (peerState.hasConflictResolutionPrecedence()) {
          return Transformer.createTransformerLocalPrecedence(this, entity, remoteOp).transform();
        }
        else {
          return Transformer.createTransformerRemotePrecedence(this, entity, remoteOp).transform();
        }
      }
      catch (OTException e) {
        return null;
      }
    }
  }

  @Override
  public String getId() {
    return engineId;
  }

  @Override
  public String toString() {
    return getName();
  }

  @Override
  public String getName() {
    return name;
  }

  @Override
  public InitialStateReceiveHandler getInitialStateReceiveHandler(final String peerId, final int entityId) {
    final OTPeer peer = getPeerState().getPeer(peerId);
    assertPeerNotNull(peer);

    return new InitialStateReceiveHandler() {
      @SuppressWarnings("unchecked")
      @Override
      public void receive(final State obj) {
        final OTEntity newEntity = new OTEntityImpl(entityId, obj);
        entityState.addEntity(newEntity);
        getPeerState().associateEntity(peer, entityId);
      }
    };
  }

  @SuppressWarnings("unchecked")
  @Override
  public void syncRemoteEntity(final String peerId, final int entityId, final EntitySyncCompletionCallback callback) {
    final OTPeer peer = getPeerState().getPeer(peerId);
    assertPeerNotNull(peer);
    peer.beginSyncRemoteEntity(peerId, entityId, callback);
  }

  @Override
  public void notifyOperation(OTOperation operation) {
    notifyRemotes(applyLocally(operation));
  }

  public OTOperation applyLocally(OTOperation operation) {
    final OTEntity entity = getEntityStateSpace().getEntity(operation.getEntityId());

    if (operation.getRevision() == -1) {
      operation = operation.getBasedOn(entity.getRevision());
    }

    operation.apply(entity);

    return operation;
  }

  public void notifyRemotes(final OTOperation operation) {
    if (!operation.shouldPropagate()) {
      return;
    }

    if (mode == OTEngineMode.Online) {
      for (final OTPeer peer : getPeerState().getPeersFor(operation.getEntityId())) {
        peer.send(operation);
      }
    }
  }

  @Override
  public OTOperationsFactory getOperationsFactory() {
    return new DefaultOTOperationsFactory(this);
  }

  @Override
  public OTEntityState getEntityStateSpace() {
    return entityState;
  }

  @Override
  public PeerState getPeerState() {
    return peerState;
  }

  @Override
  public void associateEntity(final String peerId, final int entityId) {
    final OTPeer peer = getPeerState().getPeer(peerId);
    if (peer == null) {
      throw new OTException("no peer for id: " + peerId);
    }

    final OTEntity entity = getEntityStateSpace().getEntity(entityId);
    if (entity == null) {
      throw new OTException("no entity for id: " + entityId);
    }

    getPeerState().associateEntity(peer, entityId);
  }

  @Override
  public void disassociateEntity(final String peerId, final int entityId) {
    final OTPeer peer = getPeerState().getPeer(peerId);
    if (peer == null) {
      throw new OTException("no peer for id: " + peerId);
    }

    final OTEntity entity = getEntityStateSpace().getEntity(entityId);
    if (entity == null) {
      throw new OTException("not entity for id: " + entityId);
    }

    getPeerState().disassociateEntity(peer, entityId);
  }

  @Override
  public void registerPeer(final OTPeer peer) {
    getPeerState().registerPeer(peer);
  }

  protected void setMode(final OTEngineMode mode) {
    if (this.mode == OTEngineMode.Offline && mode == OTEngineMode.Online) {
      transmitDeferredTransactions();
    }
    this.mode = mode;
  }

  private static void assertPeerNotNull(final OTPeer peer) {
    if (peer == null) {
      throw new OTException("could not find peer for id: " + peer);
    }
  }

  private void transmitDeferredTransactions() {
    final Map<Integer, Set<OTPeer>> entityPeerRelationshipMap = getPeerState().getEntityPeerRelationshipMap();
    for (final Map.Entry<Integer, Set<OTPeer>> entry : entityPeerRelationshipMap.entrySet()) {

      for (final OTPeer peer : entry.getValue()) {
        final Integer key = entry.getKey();

        final OTEntity entity = getEntityStateSpace().getEntity(key);

        final TransactionLog transactionLog = entity.getTransactionLog();
        synchronized (transactionLog.getLock()) {
          final List<OTOperation> log = transactionLog.getLog();
          final int lastTransmittedSequence = peer.getLastTransmittedSequence(entry.getKey());
          final List<OTOperation> toSend = new ArrayList<OTOperation>();

          final ListIterator<OTOperation> iter = log.listIterator(log.size());
          while (iter.hasPrevious()) {
            final OTOperation previous = iter.previous();

            toSend.add(previous);

            if (previous.getRevision() == lastTransmittedSequence) {
              Collections.reverse(toSend);
              break;
            }
          }

          for (final OTOperation op : toSend) {
            if (getPeerState().shouldForwardOperation(op)) {
              peer.send(op);
            }
          }

          transactionLog.cleanLog();
        }
      }
    }
  }

  protected static class DefaultOTOperationsFactory implements OTOperationsFactory {
    private final AbstractOTEngine otEngine;

    public DefaultOTOperationsFactory(final AbstractOTEngine otEngine) {
      this.otEngine = otEngine;
    }

    @Override
    public OTOperationsListBuilder createOperation(final OTEntity entity) {
      return new OTOperationsListBuilder() {
        List<Mutation> mutationList = new ArrayList<Mutation>();

        @Override
        public OTOperationsListBuilder add(final MutationType type, final int position, final char data) {
          mutationList.add(
              CharacterMutation.of(type, position, data)
          );
          return this;
        }

        @Override
        public OTOperationsListBuilder add(final MutationType type, final int position, final String data) {
          mutationList.add(
              StringMutation.of(type, position, data)
          );
          return this;
        }

        @Override
        public OTOperation build() {
          return OTOperationImpl.createOperation(otEngine, otEngine.getId(), mutationList, entity.getId(), -1, null, null, -1);
        }

        @Override
        public void submit() {
          otEngine.notifyOperation(build());
        }
      };
    }
  }
}
TOP

Related Classes of org.jboss.errai.otec.client.AbstractOTEngine$DefaultOTOperationsFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.