Package com.betfair.cougar.core.impl.ev

Source Code of com.betfair.cougar.core.impl.ev.ServiceExecutableResolver

/*
* Copyright 2013, The Sporting Exchange Limited
*
* 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 com.betfair.cougar.core.impl.ev;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;

import com.betfair.cougar.api.ExecutionContext;
import com.betfair.cougar.api.LogExtension;
import com.betfair.cougar.api.LoggableEvent;
import com.betfair.cougar.api.RequestContext;
import com.betfair.cougar.api.RequestUUID;
import com.betfair.cougar.api.geolocation.GeoLocationDetails;
import com.betfair.cougar.api.security.IdentityChain;
import com.betfair.cougar.core.api.RequestTimer;
import com.betfair.cougar.core.api.ev.*;
import com.betfair.cougar.core.api.exception.CougarException;
import com.betfair.cougar.core.api.exception.CougarFrameworkException;
import com.betfair.cougar.core.api.exception.CougarServiceException;
import com.betfair.cougar.core.api.exception.ServerFaultCode;
import com.betfair.cougar.core.api.logging.EventLogger;
import com.betfair.cougar.core.impl.logging.RequestLogEvent;
import com.betfair.cougar.logging.CougarLogger;
import com.betfair.cougar.logging.CougarLoggingUtils;

/**
* Resolves the operation key to a service Executable. The resolver will resolve the executable
* from the resolvers that are registered with it, then return an Executable that ensures the wrapped
* executable receives a RequestContext, enabling event logging and other server-side functionality
* not available through the ExecutionContext interface.
*
*/
public class ServiceExecutableResolver extends CompoundExecutableResolverImpl {
    private static final CougarLogger logger = CougarLoggingUtils.getLogger(ServiceExecutableResolver.class);

  private EventLogger eventLogger;


  public void setEventLogger(EventLogger eventLogger) {
    this.eventLogger = eventLogger;
  }
 
  @Override
  public Executable resolveExecutable(OperationKey operationKey, ExecutionVenue ev) {
        if (!(ev instanceof ServiceRegisterableExecutionVenue)) {
            throw new IllegalStateException("I only support resolution from a service registerable EV");
        }
        ServiceRegisterableExecutionVenue srev = (ServiceRegisterableExecutionVenue) ev;
        ServiceLogManager manager = srev.getServiceLogManager(operationKey.getNamespace(), operationKey.getServiceName(), operationKey.getVersion());
    Executable executable = super.resolveExecutable(operationKey, ev);
    if (executable != null) {
      return new RequestContextExecutable(executable, manager);
    }
    return null;
  }

  private class RequestContextExecutable implements ExecutableWrapper {
    private final Executable executable;
    private final ServiceLogManager manager;
 
    public RequestContextExecutable(Executable executable, ServiceLogManager manager) {
      this.executable = executable;
      this.manager = manager;
    }
 
        @Override
        public void execute(final ExecutionContext ctx,
                            final OperationKey key,
                            final Object[] args,
                            final ExecutionObserver observer,
                            final ExecutionVenue executionVenue,
                            final TimeConstraints timeConstraints) {
            final ExecutionContextAdapter ctxAdapter = new ExecutionContextAdapter(key, ctx, observer, manager);
            try {
                executable.execute(ctxAdapter, key, args, ctxAdapter, executionVenue, timeConstraints);
            } catch (CougarException e) {
                ctxAdapter.onResult(new ExecutionResult(e));
            } catch (Exception e) {
                ctxAdapter.onResult(new ExecutionResult(
                        new CougarServiceException(ServerFaultCode.ServiceRuntimeException,
                                "Exception thrown by service method",
                                e)));
            }
        }

        @Override
        public Executable getWrappedExecutable() {
            return executable;
        }

        @Override
        public <T extends Executable> T findChild(Class<T> clazz) {
            return ExecutableWrapperUtils.findChild(clazz, this);
        }
    }

  private class ExecutionContextAdapter implements RequestContext, ExecutionObserver {
   
    private final ExecutionObserver observer;
    private final OperationKey key;
    private final ExecutionContext original;
    private final ServiceLogManager manager;

    private RequestTimer timer = new RequestTimer();
    private List<LoggableEvent> loggableEvents = new ArrayList<LoggableEvent>();
    private LogExtension logExtension;
        private LogExtension connectedObjectLogExtension;
    private AtomicBoolean complete = new AtomicBoolean(false);
        private RequestContext originalRequestContext;

        public ExecutionContextAdapter(final OperationKey key, final ExecutionContext original, final ExecutionObserver observer, ServiceLogManager manager) {
      this.key = key;
      this.original = original;
            if (original instanceof RequestContext) {
          this.originalRequestContext = (RequestContext) original;
            }
      this.observer = observer;
      this.manager = manager;
    }

        @Override
        public void onResult(ExecutionResult result) {
            if (key.getType() == OperationKey.Type.Request && !complete.getAndSet(true)) {
                timer.requestComplete();
                switch (result.getResultType()) {
                    case Fault:
                    case Success:
                        logEvents(result);
                        break;
                }
            }
            if (key.getType() == OperationKey.Type.ConnectedObject && !complete.getAndSet(true)) {
                timer.requestComplete();
                validateConnectedObjectLogExtension(result);

            }
            observer.onResult(result);
        }

        private void validateConnectedObjectLogExtension(ExecutionResult executionResult) {
            // need to validate the connected object extension, even though the logging's not done here but in the transport. a bit yucky
            if (connectedObjectLogExtension == null) {
                if (manager.getConnectedObjectLogExtensionClass() != null) {
                    if (executionResult.getResult() instanceof ConnectedResponse) {
                        throw new CougarFrameworkException("Connected object log extension expected but not found for " + key);
                    }
                }
            }
            else {
                if (manager.getNumConnectedObjectLogExtensionFields() != connectedObjectLogExtension.getFieldsToLog().length) {
                    throw new CougarFrameworkException("Connected object log extension class defined "+
                            connectedObjectLogExtension.getFieldsToLog().length+" fields. Expected" + manager.getNumConnectedObjectLogExtensionFields());
                }
            }
        }

        @Override
    public GeoLocationDetails getLocation() {
      return original.getLocation();
    }

    @Override
    public Date getReceivedTime() {
      return original.getReceivedTime();
    }

        @Override
        public Date getRequestTime() {
            return original.getRequestTime();
        }

        @Override
    public RequestUUID getRequestUUID() {
      return original.getRequestUUID();
    }

        @Override
        public boolean traceLoggingEnabled() {
            return original.traceLoggingEnabled();
        }

        @Override
        public int getTransportSecurityStrengthFactor() {
            return original.getTransportSecurityStrengthFactor();
        }

        @Override
        public boolean isTransportSecure() {
            return original.isTransportSecure();
        }

        @Override
    public void addEventLogRecord(LoggableEvent record) {
            if (originalRequestContext != null) {
                originalRequestContext.addEventLogRecord(record);
            }
      loggableEvents.add(record);
    }

    @Override
    public void setRequestLogExtension(LogExtension extension) {
            if (originalRequestContext != null) {
                originalRequestContext.setRequestLogExtension(extension);
            }
      this.logExtension = extension;
    }

        @Override
        public void setConnectedObjectLogExtension(LogExtension extension) {
            if (originalRequestContext != null) {
                originalRequestContext.setConnectedObjectLogExtension(extension);
            }
            this.connectedObjectLogExtension = extension;
        }

        public LogExtension getConnectedObjectLogExtension() {
            if (connectedObjectLogExtension != null) {
                return connectedObjectLogExtension;
            }
            if (originalRequestContext != null) {
                return originalRequestContext.getConnectedObjectLogExtension();
            }
            return null;
        }

        @Override
    public void trace(String msg, Object... args) {
            if (original.traceLoggingEnabled()) {
                if (original.getRequestUUID() == null) {
                    logger.log(Level.SEVERE, "You need to set a RequestUUID on the ExecutionContext to see trace messages!");
                } else {
                    logger.forceTrace(original.getRequestUUID().toString(), msg, args);
                }
            }
    }

    @Override
    public IdentityChain getIdentity() {
      return original.getIdentity();
    }
       
        public String toString() {
            StringBuilder sb = new StringBuilder("ExecutionContextAdaptor:");

            sb.append("geoLocationDetails=").append(getLocation()).append("|");
            sb.append("identityChain=").append(getIdentity()).append("|");
            sb.append("requestUUID=").append(getRequestUUID()).append("|");
            sb.append("receivedTime=").append(getReceivedTime()).append("|");
            sb.append("traceLoggingEnabled=").append(traceLoggingEnabled()).append("|");
            sb.append("requestLogExtension=").append(logExtension);
            sb.append("connectedObjectLogExtension=").append(connectedObjectLogExtension);

            return sb.toString();
        }

    private void logEvents(ExecutionResult executionResult) {
      String faultCode = "";
      if (executionResult.isFault() && executionResult.getFault().getFault() != null) {
        faultCode = executionResult.getFault().getFault().getErrorCode();
      }
            // now for the request logging
      Object [] fieldsToLog = null;
      if (logExtension == null) {
        if (manager.getLogExtensionClass() != null) {
          if (executionResult.isFault()) {
                        // As it was a fault, the service cannot have guaranteed to add the extension
                        // record, so we dummy one up with the correct number of fields
            fieldsToLog = new Object[manager.getNumLogExtensionFields()];
          } else {
            throw new CougarFrameworkException("Log extension expected but not found for " + key);
          }
        }
      } else {
        if (manager.getNumLogExtensionFields() != logExtension.getFieldsToLog().length) {
          throw new CougarFrameworkException("Log extension class defined "+
              logExtension.getFieldsToLog().length+" fields. Expected" + manager.getNumLogExtensionFields());
        }
        fieldsToLog = logExtension.getFieldsToLog();
      }
      RequestLogEvent operationEvent = new RequestLogEvent(
          manager.getLoggerName(),
          faultCode,
          timer.getReceivedTime(),
          key,
          original.getRequestUUID(),
          timer.getProcessTimeNanos());
      eventLogger.logEvent(operationEvent, fieldsToLog);
      for (LoggableEvent event : loggableEvents) {
        eventLogger.logEvent(event, null);
      }
    }
  }

}
TOP

Related Classes of com.betfair.cougar.core.impl.ev.ServiceExecutableResolver

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.