Package er.rest.util

Source Code of er.rest.util.ERXRestTransactionRequestAdaptor

package er.rest.util;

import com.webobjects.appserver.WOApplication;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOResponse;
import com.webobjects.appserver.WOSession;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSMutableDictionary;

import er.extensions.appserver.ERXSession;
import er.extensions.eof.ERXEC;
import er.extensions.foundation.ERXProperties;
import er.rest.routes.ERXRouteRequestHandler;

/**
* EXPERIMENTAL.
*
* @property ERXRest.transactionsEnabled (default 'false')
* @property ERXRestTransaction.transactionManager (default '50')
*
* @author mschrag
*/
public class ERXRestTransactionRequestAdaptor {
  private static final String CLIENT_ID_HEADER_KEY = "Client-Id";
  private static final String SEQUENCE_ID_HEADER_KEY = "Seq-Id";
  private static final String TRANSACTION_HEADER_KEY = "Transaction";
  private static final String OPEN_TRANSACTION_HEADER_VALUE = "open";
  private static final String COMMIT_TRANSACTION_HEADER_VALUE = "commit";

  private static final String EXECUTING_TRANSACTION_KEY = "er.rest.ERXRestTransaction.transaction";
  private static final String TRANSACTION_MANAGER_KEY = "er.rest.ERXRestTransaction.transactionManager";
  private static ERXRestTransactionRequestAdaptor _defaultAdaptor;

  private boolean _transactionsEnabled;
  private int _maxEventsPerTransaction;
 
  public static synchronized ERXRestTransactionRequestAdaptor defaultAdaptor() {
    if (_defaultAdaptor == null) {
      _defaultAdaptor = new ERXRestTransactionRequestAdaptor();
    }
    return _defaultAdaptor;
  }

  public ERXRestTransactionRequestAdaptor() {
    _transactionsEnabled = ERXProperties.booleanForKeyWithDefault("ERXRest.transactionsEnabled", false);
    _maxEventsPerTransaction = ERXProperties.intForKeyWithDefault("ERXRest.maxEventsPerTransaction", 50);
  }

  protected EOEditingContext newEditingContext() {
    return ERXEC.newEditingContext();
  }

  public boolean transactionsEnabled() {
    return _transactionsEnabled;
  }
 
  public boolean hasSequence(WOContext context, WORequest request) {
    return request.headerForKey(ERXRestTransactionRequestAdaptor.SEQUENCE_ID_HEADER_KEY) != null;
  }

  public boolean hasTransaction(WOContext context, WORequest request) {
    return request.headerForKey(ERXRestTransactionRequestAdaptor.TRANSACTION_HEADER_KEY) != null;
  }

  public boolean isExecutingTransaction(WOContext context, WORequest request) {
    return executingTransaction(context, request) != null;
  }
 
  public ERXRestTransaction executingTransaction(WOContext context, WORequest request) {
    ERXRestTransaction transaction = null;
    @SuppressWarnings("unchecked")
    NSDictionary<String, Object> userInfo = request.userInfo();
    if (userInfo != null) {
      transaction = (ERXRestTransaction)userInfo.objectForKey(ERXRestTransactionRequestAdaptor.EXECUTING_TRANSACTION_KEY);
    }
    return transaction;
  }
 
  protected void setExecutingTransaction(ERXRestTransaction transaction, WOContext context, WORequest request) {
    @SuppressWarnings("unchecked")
    NSDictionary<String, Object> immutableUserInfo = request.userInfo();
    NSMutableDictionary<String, Object> userInfo = (immutableUserInfo == null) ? new NSMutableDictionary<String, Object>() : immutableUserInfo.mutableClone();
    userInfo.setObjectForKey(transaction, ERXRestTransactionRequestAdaptor.EXECUTING_TRANSACTION_KEY);
    request.setUserInfo(userInfo);
  }
 
  public ERXRestTransaction transaction(WOContext context, WORequest request) {
    ERXRestTransaction transaction = null;
    if (transaction == null) {
      ERXRestTransactionManager transactionManager = transactionManager(context, request);
      transaction = transaction(context, request, transactionManager);
    }
    return transaction;
  }

  public boolean willHandleRequest(WOContext context, WORequest request) {
    boolean shouldDispatchRequest = true;
    Integer sequenceIDInteger = sequenceID(request);
    if (sequenceIDInteger != null) {
      int sequenceID = sequenceIDInteger.intValue();
      ERXRestTransactionManager transactionManager = transactionManager(context, request);
      transactionManager.addSequenceID(sequenceID);

      ERXRestTransaction.State state = state(request);
      if (state != null) {
        ERXRestTransaction transaction = transaction(context, request, transactionManager);
        transaction.addEvent(sequenceID, state, request);
        shouldDispatchRequest = false;

        if (transaction.size() > _maxEventsPerTransaction) {
          transactionManager.removeTransaction(transaction);
          throw new IllegalArgumentException("You exceeded the maximum number of events for a single transaction.");
        }
      }
    }
    return shouldDispatchRequest;
  }
 
  public boolean didHandleRequest(WOContext context, WORequest request) {
    boolean shouldHandleRequest = true;
    ERXRestTransactionManager transactionManager = transactionManager(context, request);
    ERXRestTransaction transaction = transaction(context, request, transactionManager);
    if (transactionManager.isTransactionReady(transaction)) {
      shouldHandleRequest = false;

      // MS: This is sketchy -- basically we're about to execute a pile of requests on the same thread and we can't
      // check out the session again on the same thread, so we're going to forcefully check it back in
      if (context._session() != null) {
        // MS: Should we sleep it? Should we just not do this at all?
        // wosession._sleepInContext(null);
        WOApplication.application().sessionStore().checkInSessionForContext(context);
        context._setSession(null);
        ERXSession.setSession(null);
      }
      try {
        EOEditingContext editingContext = transaction.editingContext();
        try {
          for (Object record : transaction.records()) {
            WORequest recordRequest = (WORequest)record;
            setExecutingTransaction(transaction, context, recordRequest);
            recordRequest.removeHeadersForKey(ERXRestTransactionRequestAdaptor.CLIENT_ID_HEADER_KEY);
            recordRequest.removeHeadersForKey(ERXRestTransactionRequestAdaptor.SEQUENCE_ID_HEADER_KEY);
            recordRequest.removeHeadersForKey(ERXRestTransactionRequestAdaptor.TRANSACTION_HEADER_KEY);
           
            ERXRouteRequestHandler requestHandler = (ERXRouteRequestHandler)WOApplication.application().handlerForRequest(recordRequest);
            WOResponse response = requestHandler.handleRequest(recordRequest);
            if (response.status() < 200 || response.status() > 299) {
              throw new RuntimeException("Transaction failed: " + response.contentString());
            }
          }
          editingContext.saveChanges();
        }
        finally {
          transactionManager.removeTransaction(transaction);
          editingContext.dispose();
        }
      }
      finally {
        context.session();
      }
    }
    return shouldHandleRequest;
  }

  protected String clientID(WORequest request) {
    return request.headerForKey(ERXRestTransactionRequestAdaptor.CLIENT_ID_HEADER_KEY);
  }

  protected Integer sequenceID(WORequest request) {
    Integer sequenceID = null;
    String sequenceIDStr = request.headerForKey(ERXRestTransactionRequestAdaptor.SEQUENCE_ID_HEADER_KEY);
    if (sequenceIDStr != null) {
      sequenceID = Integer.parseInt(sequenceIDStr);
    }
    return sequenceID;
  }

  protected ERXRestTransaction.State state(WORequest request) {
    String stateStr = request.headerForKey(ERXRestTransactionRequestAdaptor.TRANSACTION_HEADER_KEY);
    ERXRestTransaction.State state;
    if (stateStr == null) {
      state = null;
    }
    else if (ERXRestTransactionRequestAdaptor.COMMIT_TRANSACTION_HEADER_VALUE.equals(stateStr)) {
      state = ERXRestTransaction.State.Commit;
    }
    else if (ERXRestTransactionRequestAdaptor.OPEN_TRANSACTION_HEADER_VALUE.equals(stateStr)) {
      state = ERXRestTransaction.State.Open;
    }
    else {
      throw new IllegalArgumentException("Unknown transaction state: " + stateStr);
    }
    return state;
  }

  protected ERXRestTransactionManager transactionManager(WOContext context, WORequest request) {
    WOSession session = context.session();
    ERXRestTransactionManager transactionManager = (ERXRestTransactionManager) session.objectForKey(ERXRestTransactionRequestAdaptor.TRANSACTION_MANAGER_KEY);
    if (transactionManager == null) {
      transactionManager = new ERXRestTransactionManager();
      session.setObjectForKey(transactionManager, ERXRestTransactionRequestAdaptor.TRANSACTION_MANAGER_KEY);
    }
    return transactionManager;
  }

  protected ERXRestTransaction transaction(WOContext context, WORequest request, ERXRestTransactionManager transactionManager) {
    WOSession session = context.session();

    String clientID = clientID(request);
    if (clientID == null) {
      clientID = session.sessionID();
    }

    return transactionManager.transactionForID(clientID);
  }
}
TOP

Related Classes of er.rest.util.ERXRestTransactionRequestAdaptor

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.