public String toXMLString() {
   StringBuilder sb = new StringBuilder();
   if (OrderTotal != null) {
     sb.append("<ebl:OrderTotal");
     sb.append(OrderTotal.toXMLString());
     sb.append("</ebl:OrderTotal>");
   }
   if (ReturnURL != null) {
     sb.append("<ebl:ReturnURL>").append(SDKUtil.escapeInvalidXmlCharsRegex(ReturnURL));
     sb.append("</ebl:ReturnURL>");
   }
   if (CancelURL != null) {
     sb.append("<ebl:CancelURL>").append(SDKUtil.escapeInvalidXmlCharsRegex(CancelURL));
     sb.append("</ebl:CancelURL>");
   }
   if (TrackingImageURL != null) {
     sb.append("<ebl:TrackingImageURL>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(TrackingImageURL));
     sb.append("</ebl:TrackingImageURL>");
   }
   if (giropaySuccessURL != null) {
     sb.append("<ebl:giropaySuccessURL>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(giropaySuccessURL));
     sb.append("</ebl:giropaySuccessURL>");
   }
   if (giropayCancelURL != null) {
     sb.append("<ebl:giropayCancelURL>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(giropayCancelURL));
     sb.append("</ebl:giropayCancelURL>");
   }
   if (BanktxnPendingURL != null) {
     sb.append("<ebl:BanktxnPendingURL>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(BanktxnPendingURL));
     sb.append("</ebl:BanktxnPendingURL>");
   }
   if (Token != null) {
     sb.append("<ebl:Token>").append(SDKUtil.escapeInvalidXmlCharsRegex(Token));
     sb.append("</ebl:Token>");
   }
   if (MaxAmount != null) {
     sb.append("<ebl:MaxAmount");
     sb.append(MaxAmount.toXMLString());
     sb.append("</ebl:MaxAmount>");
   }
   if (OrderDescription != null) {
     sb.append("<ebl:OrderDescription>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(OrderDescription));
     sb.append("</ebl:OrderDescription>");
   }
   if (Custom != null) {
     sb.append("<ebl:Custom>").append(SDKUtil.escapeInvalidXmlCharsRegex(Custom));
     sb.append("</ebl:Custom>");
   }
   if (InvoiceID != null) {
     sb.append("<ebl:InvoiceID>").append(SDKUtil.escapeInvalidXmlCharsRegex(InvoiceID));
     sb.append("</ebl:InvoiceID>");
   }
   if (ReqConfirmShipping != null) {
     sb.append("<ebl:ReqConfirmShipping>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(ReqConfirmShipping));
     sb.append("</ebl:ReqConfirmShipping>");
   }
   if (ReqBillingAddress != null) {
     sb.append("<ebl:ReqBillingAddress>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(ReqBillingAddress));
     sb.append("</ebl:ReqBillingAddress>");
   }
   if (BillingAddress != null) {
     sb.append("<ebl:BillingAddress>");
     sb.append(BillingAddress.toXMLString());
     sb.append("</ebl:BillingAddress>");
   }
   if (NoShipping != null) {
     sb.append("<ebl:NoShipping>").append(SDKUtil.escapeInvalidXmlCharsRegex(NoShipping));
     sb.append("</ebl:NoShipping>");
   }
   if (AddressOverride != null) {
     sb.append("<ebl:AddressOverride>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(AddressOverride));
     sb.append("</ebl:AddressOverride>");
   }
   if (LocaleCode != null) {
     sb.append("<ebl:LocaleCode>").append(SDKUtil.escapeInvalidXmlCharsRegex(LocaleCode));
     sb.append("</ebl:LocaleCode>");
   }
   if (PageStyle != null) {
     sb.append("<ebl:PageStyle>").append(SDKUtil.escapeInvalidXmlCharsRegex(PageStyle));
     sb.append("</ebl:PageStyle>");
   }
   if (cppHeaderImage != null) {
     sb.append("<ebl:cpp-header-image>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(cppHeaderImage));
     sb.append("</ebl:cpp-header-image>");
   }
   if (cppHeaderBorderColor != null) {
     sb.append("<ebl:cpp-header-border-color>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(cppHeaderBorderColor));
     sb.append("</ebl:cpp-header-border-color>");
   }
   if (cppHeaderBackColor != null) {
     sb.append("<ebl:cpp-header-back-color>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(cppHeaderBackColor));
     sb.append("</ebl:cpp-header-back-color>");
   }
   if (cppPayflowColor != null) {
     sb.append("<ebl:cpp-payflow-color>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(cppPayflowColor));
     sb.append("</ebl:cpp-payflow-color>");
   }
   if (cppCartBorderColor != null) {
     sb.append("<ebl:cpp-cart-border-color>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(cppCartBorderColor));
     sb.append("</ebl:cpp-cart-border-color>");
   }
   if (cppLogoImage != null) {
     sb.append("<ebl:cpp-logo-image>").append(SDKUtil.escapeInvalidXmlCharsRegex(cppLogoImage));
     sb.append("</ebl:cpp-logo-image>");
   }
   if (Address != null) {
     sb.append("<ebl:Address>");
     sb.append(Address.toXMLString());
     sb.append("</ebl:Address>");
   }
   if (PaymentAction != null) {
     sb.append("<ebl:PaymentAction>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(PaymentAction.getValue()));
     sb.append("</ebl:PaymentAction>");
   }
   if (SolutionType != null) {
     sb.append("<ebl:SolutionType>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(SolutionType.getValue()));
     sb.append("</ebl:SolutionType>");
   }
   if (LandingPage != null) {
     sb.append("<ebl:LandingPage>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(LandingPage.getValue()));
     sb.append("</ebl:LandingPage>");
   }
   if (BuyerEmail != null) {
     sb.append("<ebl:BuyerEmail>").append(SDKUtil.escapeInvalidXmlCharsRegex(BuyerEmail));
     sb.append("</ebl:BuyerEmail>");
   }
   if (ChannelType != null) {
     sb.append("<ebl:ChannelType>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(ChannelType.getValue()));
     sb.append("</ebl:ChannelType>");
   }
   if (BillingAgreementDetails != null) {
     for (int i = 0; i < BillingAgreementDetails.size(); i++) {
       sb.append("<ebl:BillingAgreementDetails>");
       sb.append(BillingAgreementDetails.get(i).toXMLString());
       sb.append("</ebl:BillingAgreementDetails>");
     }
   }
   if (PromoCodes != null) {
     for (int i = 0; i < PromoCodes.size(); i++) {
       sb.append("<ebl:PromoCodes>").append(SDKUtil.escapeInvalidXmlCharsRegex(PromoCodes.get(i)));
       sb.append("</ebl:PromoCodes>");
     }
   }
   if (PayPalCheckOutBtnType != null) {
     sb.append("<ebl:PayPalCheckOutBtnType>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(PayPalCheckOutBtnType));
     sb.append("</ebl:PayPalCheckOutBtnType>");
   }
   if (ProductCategory != null) {
     sb.append("<ebl:ProductCategory>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(ProductCategory.getValue()));
     sb.append("</ebl:ProductCategory>");
   }
   if (ShippingMethod != null) {
     sb.append("<ebl:ShippingMethod>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(ShippingMethod.getValue()));
     sb.append("</ebl:ShippingMethod>");
   }
   if (ProfileAddressChangeDate != null) {
     sb.append("<ebl:ProfileAddressChangeDate>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(ProfileAddressChangeDate));
     sb.append("</ebl:ProfileAddressChangeDate>");
   }
   if (AllowNote != null) {
     sb.append("<ebl:AllowNote>").append(SDKUtil.escapeInvalidXmlCharsRegex(AllowNote));
     sb.append("</ebl:AllowNote>");
   }
   if (FundingSourceDetails != null) {
     sb.append("<ebl:FundingSourceDetails>");
     sb.append(FundingSourceDetails.toXMLString());
     sb.append("</ebl:FundingSourceDetails>");
   }
   if (BrandName != null) {
     sb.append("<ebl:BrandName>").append(SDKUtil.escapeInvalidXmlCharsRegex(BrandName));
     sb.append("</ebl:BrandName>");
   }
   if (CallbackURL != null) {
     sb.append("<ebl:CallbackURL>").append(SDKUtil.escapeInvalidXmlCharsRegex(CallbackURL));
     sb.append("</ebl:CallbackURL>");
   }
   if (EnhancedCheckoutData != null) {
     sb.append("<ebl:EnhancedCheckoutData>");
     sb.append(EnhancedCheckoutData.toXMLString());
     sb.append("</ebl:EnhancedCheckoutData>");
   }
   if (OtherPaymentMethods != null) {
     for (int i = 0; i < OtherPaymentMethods.size(); i++) {
       sb.append("<ebl:OtherPaymentMethods>");
       sb.append(OtherPaymentMethods.get(i).toXMLString());
       sb.append("</ebl:OtherPaymentMethods>");
     }
   }
   if (BuyerDetails != null) {
     sb.append("<ebl:BuyerDetails>");
     sb.append(BuyerDetails.toXMLString());
     sb.append("</ebl:BuyerDetails>");
   }
   if (PaymentDetails != null) {
     for (int i = 0; i < PaymentDetails.size(); i++) {
       sb.append("<ebl:PaymentDetails>");
       sb.append(PaymentDetails.get(i).toXMLString());
       sb.append("</ebl:PaymentDetails>");
     }
   }
   if (FlatRateShippingOptions != null) {
     for (int i = 0; i < FlatRateShippingOptions.size(); i++) {
       sb.append("<ebl:FlatRateShippingOptions>");
       sb.append(FlatRateShippingOptions.get(i).toXMLString());
       sb.append("</ebl:FlatRateShippingOptions>");
     }
   }
   if (CallbackTimeout != null) {
     sb.append("<ebl:CallbackTimeout>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(CallbackTimeout));
     sb.append("</ebl:CallbackTimeout>");
   }
   if (CallbackVersion != null) {
     sb.append("<ebl:CallbackVersion>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(CallbackVersion));
     sb.append("</ebl:CallbackVersion>");
   }
   if (CustomerServiceNumber != null) {
     sb.append("<ebl:CustomerServiceNumber>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(CustomerServiceNumber));
     sb.append("</ebl:CustomerServiceNumber>");
   }
   if (GiftMessageEnable != null) {
     sb.append("<ebl:GiftMessageEnable>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(GiftMessageEnable));
     sb.append("</ebl:GiftMessageEnable>");
   }
   if (GiftReceiptEnable != null) {
     sb.append("<ebl:GiftReceiptEnable>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(GiftReceiptEnable));
     sb.append("</ebl:GiftReceiptEnable>");
   }
   if (GiftWrapEnable != null) {
     sb.append("<ebl:GiftWrapEnable>").append(SDKUtil.escapeInvalidXmlCharsRegex(GiftWrapEnable));
     sb.append("</ebl:GiftWrapEnable>");
   }
   if (GiftWrapName != null) {
     sb.append("<ebl:GiftWrapName>").append(SDKUtil.escapeInvalidXmlCharsRegex(GiftWrapName));
     sb.append("</ebl:GiftWrapName>");
   }
   if (GiftWrapAmount != null) {
     sb.append("<ebl:GiftWrapAmount");
     sb.append(GiftWrapAmount.toXMLString());
     sb.append("</ebl:GiftWrapAmount>");
   }
   if (BuyerEmailOptInEnable != null) {
     sb.append("<ebl:BuyerEmailOptInEnable>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(BuyerEmailOptInEnable));
     sb.append("</ebl:BuyerEmailOptInEnable>");
   }
   if (SurveyEnable != null) {
     sb.append("<ebl:SurveyEnable>").append(SDKUtil.escapeInvalidXmlCharsRegex(SurveyEnable));
     sb.append("</ebl:SurveyEnable>");
   }
   if (SurveyQuestion != null) {
     sb.append("<ebl:SurveyQuestion>").append(SDKUtil.escapeInvalidXmlCharsRegex(SurveyQuestion));
     sb.append("</ebl:SurveyQuestion>");
   }
   if (SurveyChoice != null) {
     for (int i = 0; i < SurveyChoice.size(); i++) {
       sb.append("<ebl:SurveyChoice>")
           .append(SDKUtil.escapeInvalidXmlCharsRegex(SurveyChoice.get(i)));
       sb.append("</ebl:SurveyChoice>");
     }
   }
   if (TotalType != null) {
     sb.append("<ebl:TotalType>").append(SDKUtil.escapeInvalidXmlCharsRegex(TotalType.getValue()));
     sb.append("</ebl:TotalType>");
   }
   if (NoteToBuyer != null) {
     sb.append("<ebl:NoteToBuyer>").append(SDKUtil.escapeInvalidXmlCharsRegex(NoteToBuyer));
     sb.append("</ebl:NoteToBuyer>");
   }
   if (Incentives != null) {
     for (int i = 0; i < Incentives.size(); i++) {
       sb.append("<ebl:Incentives>");
       sb.append(Incentives.get(i).toXMLString());
       sb.append("</ebl:Incentives>");
     }
   }
   if (ReqInstrumentDetails != null) {
     sb.append("<ebl:ReqInstrumentDetails>")
         .append(SDKUtil.escapeInvalidXmlCharsRegex(ReqInstrumentDetails));
     sb.append("</ebl:ReqInstrumentDetails>");
   }
   if (ExternalRememberMeOptInDetails != null) {
     sb.append("<ebl:ExternalRememberMeOptInDetails>");
     sb.append(ExternalRememberMeOptInDetails.toXMLString());
     sb.append("</ebl:ExternalRememberMeOptInDetails>");
   }
   if (FlowControlDetails != null) {
     sb.append("<ebl:FlowControlDetails>");
     sb.append(FlowControlDetails.toXMLString());
     sb.append("</ebl:FlowControlDetails>");
   }
   if (DisplayControlDetails != null) {
     sb.append("<ebl:DisplayControlDetails>");
     sb.append(DisplayControlDetails.toXMLString());
     sb.append("</ebl:DisplayControlDetails>");
   }
   if (ExternalPartnerTrackingDetails != null) {
     sb.append("<ebl:ExternalPartnerTrackingDetails>");
     sb.append(ExternalPartnerTrackingDetails.toXMLString());
     sb.append("</ebl:ExternalPartnerTrackingDetails>");
   }
   if (CoupledBuckets != null) {
     for (int i = 0; i < CoupledBuckets.size(); i++) {
       sb.append("<ebl:CoupledBuckets>");
       sb.append(CoupledBuckets.get(i).toXMLString());
       sb.append("</ebl:CoupledBuckets>");
     }
   }
   return sb.toString();
 }
  @Override
  public ConfirmCheckoutResponse confirmCheckout(
      final Payment payment, final String notifyUrl, final String token, final String payerId)
      throws FrameworkException {

    try {

      final GetExpressCheckoutDetailsResponseType response =
          PayPalHelper.getExpressCheckoutResponse(token);

      if (AckCodeType.SUCCESS.equals(response.getAck())) {

        // TODO: change currency code
        final GetExpressCheckoutDetailsResponseDetailsType details =
            response.getGetExpressCheckoutDetailsResponseDetails();
        final CurrencyCodeType currencyCode = CurrencyCodeType.fromValue(payment.getCurrencyCode());

        final DoExpressCheckoutPaymentResponseType confirmationResponse =
            PayPalHelper.commitExpressCheckout(
                notifyUrl, currencyCode, payment.getTotal(), token, payerId);

        if (AckCodeType.SUCCESS.equals(confirmationResponse.getAck())) {

          final PayPalConfirmCheckoutResponse checkoutResponse =
              new PayPalConfirmCheckoutResponse(confirmationResponse);
          final DoExpressCheckoutPaymentResponseDetailsType confirmation =
              confirmationResponse.getDoExpressCheckoutPaymentResponseDetails();
          final String billingAgreementId = confirmation.getBillingAgreementID();
          final String note = confirmation.getNote();

          // billing address
          final AddressType billingAddress = details.getBillingAddress();
          if (billingAddress != null) {

            final String billingAddressName = billingAddress.getName();
            final String billingAddressStreet1 = billingAddress.getStreet1();
            final String billingAddressStreet2 = billingAddress.getStreet2();
            final String billingAddressZip = billingAddress.getPostalCode();
            final String billingAddressCity = billingAddress.getCityName();
            final String billingAddressCountry = billingAddress.getCountryName();

            payment.setBillingAddressName(billingAddressName);
            payment.setBillingAddressStreet1(billingAddressStreet1);
            payment.setBillingAddressStreet2(billingAddressStreet2);
            payment.setBillingAddressZip(billingAddressZip);
            payment.setBillingAddressCity(billingAddressCity);
            payment.setBillingAddressCountry(billingAddressCountry);
          }

          // payer info
          final PayerInfoType payerInfo = details.getPayerInfo();
          if (payerInfo != null) {

            payment.setPayer(payerInfo.getPayer());
            payment.setPayerBusiness(payerInfo.getPayerBusiness());

            final AddressType payerAddress = payerInfo.getAddress();
            if (payerAddress != null) {

              payment.setPayerAddressName(payerAddress.getName());
              payment.setPayerAddressStreet1(payerAddress.getStreet1());
              payment.setPayerAddressStreet2(payerAddress.getStreet1());
              payment.setPayerAddressZip(payerAddress.getPostalCode());
              payment.setPayerAddressCity(payerAddress.getCityName());
              payment.setPayerAddressCountry(payerAddress.getCountryName());
            }
          }

          payment.setBillingAgreementId(billingAgreementId);
          payment.setNote(note);
          payment.setInvoiceId(details.getInvoiceID());
          payment.setPaymentState(PaymentState.completed);
          payment.setToken(null);

          // success
          return checkoutResponse;
        }
      }

    } catch (Throwable t) {
      throw new FrameworkException(422, t.getMessage());
    }

    throw new FrameworkException(422, "Unknown error.");
  }