示例#1
0
NS_IMETHODIMP
nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex,
                           const XPTMethodDescriptor *aMethodInfo,
                           nsXPTCMiniVariant *aParams)
{
#ifdef DEBUG_JAVAXPCOM
  const char* ifaceName;
  mIInfo->GetNameShared(&ifaceName);
  LOG(("---> (Java) %s::%s()\n", ifaceName, aMethodInfo->name));
#endif

  nsresult rv = NS_OK;
  JNIEnv* env = GetJNIEnv();
  jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID);

  nsCAutoString methodSig("(");

  // Create jvalue array to hold Java params
  PRUint8 paramCount = aMethodInfo->num_args;
  jvalue* java_params = nsnull;
  const nsXPTParamInfo* retvalInfo = nsnull;
  if (paramCount) {
    java_params = new jvalue[paramCount];
    if (!java_params)
      return NS_ERROR_OUT_OF_MEMORY;

    for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++)
    {
      const nsXPTParamInfo &paramInfo = aMethodInfo->params[i];
      if (!paramInfo.IsRetval()) {
        rv = SetupJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams,
                             aParams[i], java_params[i], methodSig);
      } else {
        retvalInfo = &paramInfo;
      }
    }
    NS_ASSERTION(NS_SUCCEEDED(rv), "SetupJavaParams failed");
  }

  // Finish method signature
  if (NS_SUCCEEDED(rv)) {
    methodSig.Append(')');
    if (retvalInfo) {
      nsCAutoString retvalSig;
      rv = GetRetvalSig(retvalInfo, aMethodInfo, aMethodIndex, aParams,
                        retvalSig);
      methodSig.Append(retvalSig);
    } else {
      methodSig.Append('V');
    }
    NS_ASSERTION(NS_SUCCEEDED(rv), "GetRetvalSig failed");
  }

  // Get Java method to call
  jmethodID mid = nsnull;
  if (NS_SUCCEEDED(rv)) {
    nsCAutoString methodName;
    if (XPT_MD_IS_GETTER(aMethodInfo->flags) ||
        XPT_MD_IS_SETTER(aMethodInfo->flags)) {
      if (XPT_MD_IS_GETTER(aMethodInfo->flags))
        methodName.AppendLiteral("get");
      else
        methodName.AppendLiteral("set");
      methodName.AppendASCII(aMethodInfo->name);
      methodName.SetCharAt(toupper(methodName[3]), 3);
    } else {
      methodName.AppendASCII(aMethodInfo->name);
      methodName.SetCharAt(tolower(methodName[0]), 0);
    }
    // If it's a Java keyword, then prepend an underscore
    if (gJavaKeywords->GetEntry(methodName.get())) {
      methodName.Insert('_', 0);
    }

    jclass clazz = env->GetObjectClass(javaObject);
    if (clazz)
      mid = env->GetMethodID(clazz, methodName.get(), methodSig.get());
    NS_ASSERTION(mid, "Failed to get requested method for Java object");
    if (!mid)
      rv = NS_ERROR_FAILURE;
  }

  // Call method
  jvalue retval;
  if (NS_SUCCEEDED(rv)) {
    if (!retvalInfo) {
      env->CallVoidMethodA(javaObject, mid, java_params);
    } else {
      switch (retvalInfo->GetType().TagPart())
      {
        case nsXPTType::T_I8:
          retval.b = env->CallByteMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_I16:
        case nsXPTType::T_U8:
          retval.s = env->CallShortMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_I32:
        case nsXPTType::T_U16:
          retval.i = env->CallIntMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_I64:
        case nsXPTType::T_U32:
          retval.j = env->CallLongMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_FLOAT:
          retval.f = env->CallFloatMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_U64:
        case nsXPTType::T_DOUBLE:
          retval.d = env->CallDoubleMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_BOOL:
          retval.z = env->CallBooleanMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_CHAR:
        case nsXPTType::T_WCHAR:
          retval.c = env->CallCharMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_CHAR_STR:
        case nsXPTType::T_WCHAR_STR:
        case nsXPTType::T_IID:
        case nsXPTType::T_ASTRING:
        case nsXPTType::T_DOMSTRING:
        case nsXPTType::T_UTF8STRING:
        case nsXPTType::T_CSTRING:
        case nsXPTType::T_INTERFACE:
        case nsXPTType::T_INTERFACE_IS:
          retval.l = env->CallObjectMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_VOID:
          retval.j = env->CallLongMethodA(javaObject, mid, java_params);
          break;

        default:
          NS_WARNING("Unhandled retval type");
          break;
      }
    }

    // Check for exception from called Java function
    jthrowable exp = env->ExceptionOccurred();
    if (exp) {
      // If the exception is an instance of XPCOMException, then get the
      // nsresult from the exception instance.  Else, default to
      // NS_ERROR_FAILURE.
      if (env->IsInstanceOf(exp, xpcomExceptionClass)) {
        jfieldID fid;
        fid = env->GetFieldID(xpcomExceptionClass, "errorcode", "J");
        if (fid) {
          rv = env->GetLongField(exp, fid);
        } else {
          rv = NS_ERROR_FAILURE;
        }
        NS_ASSERTION(fid, "Couldn't get 'errorcode' field of XPCOMException");
      } else {
        rv = NS_ERROR_FAILURE;
      }
    }
  }

  // Handle any 'inout', 'out' and 'retval' params
  if (NS_SUCCEEDED(rv)) {
    for (PRUint8 i = 0; i < paramCount; i++)
    {
      const nsXPTParamInfo &paramInfo = aMethodInfo->params[i];
      if (paramInfo.IsIn() && !paramInfo.IsOut() && !paramInfo.IsDipper()) // 'in'
        continue;

      // If param is null, then caller is not expecting an output value.
      if (aParams[i].val.p == nsnull)
        continue;

      if (!paramInfo.IsRetval()) {
        rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams,
                                aParams[i], java_params[i]);
      } else {
        rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams,
                                aParams[i], retval);
      }
    }
    NS_ASSERTION(NS_SUCCEEDED(rv), "FinalizeJavaParams/SetXPCOMRetval failed");
  }

  if (java_params)
    delete [] java_params;

#ifdef DEBUG
  if (env->ExceptionCheck())
    env->ExceptionDescribe();
#endif
  env->ExceptionClear();

  LOG(("<--- (Java) %s::%s()\n", ifaceName, aMethodInfo->name));
  return rv;
}
NS_IMETHODIMP
WSPPropertyBagWrapper::CallMethod(PRUint16 methodIndex,
                                  const XPTMethodDescriptor* info,
                                  nsXPTCMiniVariant* params)
{
  if (methodIndex < 3) {
    NS_ERROR("WSPPropertyBagWrapper: bad method index");
    return NS_ERROR_FAILURE;
  }

  nsresult rv = NS_OK;
  nsAutoString propName;

  rv = WSPFactory::C2XML(nsDependentCString(info->name), propName);
  if (NS_FAILED(rv)) {
    return rv;
  }

  nsCOMPtr<nsIVariant> val;
  rv = mPropertyBag->GetProperty(propName, getter_AddRefs(val));
  if (NS_FAILED(rv)) {
    return rv;
  }

  nsCOMPtr<nsIInterfaceInfo> iinfo;
  if (XPT_MD_IS_GETTER(info->flags)) {
    const nsXPTParamInfo& paramInfo = info->params[0];
    const nsXPTType& type = paramInfo.GetType();
    uint8 type_tag = type.TagPart();

    if (type_tag == nsXPTType::T_INTERFACE) {
      rv = mInterfaceInfo->GetInfoForParam(methodIndex, &paramInfo,
                                           getter_AddRefs(iinfo));
      if (NS_FAILED(rv)) {
        return rv;
      }
    }

    rv = WSPProxy::VariantToValue(type_tag, params[0].val.p, iinfo, val);
  }
  else if (info->num_args == 2) {
    // If it's not an explicit getter, it has to be an array getter
    // method.

    // The first parameter should be the array length out param
    const nsXPTParamInfo& paramInfo1 = info->params[0];
    const nsXPTType& type1 = paramInfo1.GetType();
    if (!paramInfo1.IsOut() || (type1.TagPart() != nsXPTType::T_U32)) {
      NS_ERROR("Unexpected parameter type for getter");
      return NS_ERROR_FAILURE;
    }

    // The second parameter should be the array out pointer itself.
    const nsXPTParamInfo& paramInfo2 = info->params[1];
    const nsXPTType& type2 = paramInfo2.GetType();
    if (!paramInfo2.IsOut() || !type2.IsArray()) {
      NS_ERROR("Unexpected parameter type for getter");
      return NS_ERROR_FAILURE;
    }

    nsXPTType arrayType;
    rv = mInterfaceInfo->GetTypeForParam(methodIndex, &paramInfo2,
                                         1, &arrayType);
    if (NS_FAILED(rv)) {
      return rv;
    }

    if (arrayType.IsInterfacePointer()) {
      rv = mInterfaceInfo->GetInfoForParam(methodIndex, &paramInfo2,
                                           getter_AddRefs(iinfo));
      if (NS_FAILED(rv)) {
        return rv;
      }
    }

    rv = WSPProxy::VariantToArrayValue(arrayType.TagPart(), params, params + 1,
                                       iinfo, val);
  }
  else {
    NS_ERROR("Unexpected method signature for property bag wrapper");
    return NS_ERROR_FAILURE;
  }

  return rv;
}