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

com.gemstone.gemfire.distributed.internal.ReplyException Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * 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. See accompanying
 * LICENSE file.
 */

package com.gemstone.gemfire.distributed.internal;

import com.gemstone.gemfire.GemFireCheckedException;
import com.gemstone.gemfire.GemFireException;
import com.gemstone.gemfire.InternalGemFireException;
import com.gemstone.gemfire.SerializationException;
import com.gemstone.gemfire.distributed.DistributedMember;
import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;

/**
 * Exception thrown when a DistributionMessage is processed to be propagated
 * back to the sender of the message.
 * @author Eric Zoerner
 *
 */
public class ReplyException extends GemFireException {
  private static final long serialVersionUID = -4410839793809166071L;
  private static final String REMOTE_MEMBER_TOKEN = "Remote Member";
  private transient InternalDistributedMember sender;
  
  /**
   * Creates a new instance of ReplyException without detail message.
   * 
   * Used by serialization
   */
  public ReplyException() {
  }
  
  
  /**
   * Constructs an instance of ReplyException with the specified detail message.
   * @param msg the detail message.
   */
  public ReplyException(String msg) {
    super(msg);
  }
  
  /**
   * Constructs an instance of ReplyException with the specified detail message
   * and cause.
   * @param msg the detail message.
   * @param cause the causal Throwable
   */
  public ReplyException(String msg, Throwable cause) {
    super(msg, cause);
  }
  
  /**
   * Constructs an instance of ReplyException with the specified cause.
   * @param cause the causal Throwable
   */
  public ReplyException(Throwable cause) {
    super(cause);
  }
  
  /** After expected reply exceptions have already been handled, 
   * call this method to handle this exception as unexpected,
   * i.e. converts to an appropriate runtime exception and throws it.
   * If there is a a causal exception, then this method will
   * throw that instead of the ReplyException.
   */
  public void handleAsUnexpected() {
    Throwable c = getCause();
    if (c == null) {
      throw new InternalGemFireException(LocalizedStrings.ReplyException_UNEXPECTED_EXCEPTION_ON_MEMBER_0.toLocalizedString(getSender()), this);
    }
    if (c instanceof RuntimeException) {
      fixUpRemoteEx(c);
      throw (RuntimeException)c;
    }
    if (c instanceof Error) {
      fixUpRemoteEx(c);
      throw (Error)c;
    }
    if (c instanceof ClassNotFoundException) {
      //for bug 43602
      throw new SerializationException("Class not found", c);
    }
    throw new InternalGemFireException(LocalizedStrings.ReplyException_UNEXPECTED_EXCEPTION_ON_MEMBER_0.toLocalizedString(getSender()), c);
  }

  /**
   * Fixes a remote exception that this ReplyException has wrapped. Adds the 
   * local stack frames. The remote stack elements have the sender id info. 
   * 
   * @param t Remote exception to fix up
   * @since 5.1
   */
  public void fixUpRemoteEx(Throwable t) {
    fixUpRemoteEx(t, getSender());
  }

  /**
   * Fixes a remote exception that this ReplyException has wrapped. Adds the 
   * local stack frames. The remote stack elements have the sender id info. 
   * 
   * @param t Remote exception to fix up
   * @since 5.1
   */
  public static void fixUpRemoteEx(Throwable t, DistributedMember sender) {
    GemFireCacheImpl cache = GemFireCacheImpl.getInstance();
    if (sender == null || (cache != null && sender.equals(cache.getMyId()))) {
      return;
    }

    String senderId = sender.toString();
    addSenderInfo(t, senderId);

    StackTraceElement[] remoteStack = t.getStackTrace();
    StackTraceElement[] localStack  = Thread.currentThread().getStackTrace();

    int localStartIdx = 0;
    if (localStartIdx < localStack.length) {
      // pop off the fixUpRemoteEx frame
      localStartIdx++;
      if (localStartIdx < localStack.length) {
        // pop off the handleAsUnexpected frame
        localStartIdx++;
      }
    }

    // do not consider localStartIdx no. of elements.
    StackTraceElement[] newStack =  new StackTraceElement[remoteStack.length + 
                                                         localStack.length - 
                                                         localStartIdx];
   
    int i = 0;
    for (; i < remoteStack.length; i++) {
      newStack[i] = remoteStack[i];
    }
    for (int j=2; i < newStack.length; j++, i++) {
      newStack[i] = localStack[j];
    }
   
    t.setStackTrace(newStack);
    // also set the origin in the underlying exception
    if (t instanceof GemFireException) {
      ((GemFireException)t).setOrigin(sender);
    }
    else if (t instanceof GemFireCheckedException) {
      ((GemFireCheckedException)t).setOrigin(sender);
    }
  }

  /**
   * Adds the sender information to the stack trace elements of the given
   * exception. Also traverses recursively over the 'cause' for adding this
   * sender information.
   * 
   * @param toModify
   *          Throwable instance to modify the stack trace elements
   * @param senderId
   *          id of the sender member
   */
  private static void addSenderInfo(Throwable toModify, String senderId) {
    StackTraceElement[] stackTrace = toModify.getStackTrace();
   
    StackTraceElement element = null;
    for (int i = 0; i < stackTrace.length; i++) {
      element = stackTrace[i];
      if (!element.getClassName().startsWith(REMOTE_MEMBER_TOKEN)) {
        stackTrace[i] = new StackTraceElement(
                          REMOTE_MEMBER_TOKEN + " '"+ senderId + 
                          "' in " + element.getClassName(), 
                          element.getMethodName(), 
                          element.getFileName(), 
                          element.getLineNumber());
      }
    }
   
    toModify.setStackTrace(stackTrace);
    Throwable cause = toModify.getCause();
   
    if (cause != null) {
      addSenderInfo(cause, senderId);
    }
  }

  /**
   * Sets the member that threw the received exception
   * @param sendr the member that threw the exception
   * @since 6.0
   */
  public synchronized void setSenderIfNull(InternalDistributedMember sendr) {
    if (this.sender == null) {
      this.sender = sendr;
    }
  }

  /**
   * Gets the member which threw the exception
   * @return the throwing member
   * @since 6.0
   */
  public synchronized InternalDistributedMember getSender() {
    return this.sender;
  }

  @Override
  public String getMessage() {
    InternalDistributedMember s = getSender();
    String m = super.getMessage();
    return (s!=null) ? ("From " + s + ": " + m) : m;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy