URLConnection -UnsupportedOperationException

Hello all,

On Xojo 2023r4 I get a UnsupportedOperationException error on occasion. What causes this and what is the best way to recover from it?

To be clear, the code will run for a hours/days without issue. Then, suddenly this occurs. Have to restart the app to get it running again - possibly and indication that the URLConnection object has had a bigger error and possibly needs to be restarted/ create a new object.

Am I reading this correctly? Again, what are the cause(s) and what is the best way to recover from it.

Thanks,
Tim

I started using Try/Catch.

Is it better to use the networkexception or RuntimeException? I think both would yield some insight but really don’t know.

The following is how I have it now. However If I wanted to replace the catch with RunTimeException, how would I also get any error from the NetworkException?

Thanks,
Tim

Catch Err As NetworkException
  Flds = Array ("EXCEPTION", CurrentMethodName + "  Lne= " + Lne.ToString , Cstr(err.Type) + "  " + err.Message )
  Logs.AddFields Flds
  Logs.LogFileAppend( Logs.K_Except_App_Err)
  
  
  eMFA_Transaction.ItemSent = "N"
  eMFA_Transaction.EventDesc = "Error " + Cstr(err.Type) + "  " + err.Message 
  Dim Result As Integer = eMFA_Transaction.UpdateRowID(TransActRID)
  
  chkTwilioTimer.Period = 50  //50mS
  chkTwilioTimer.Mode = Timer.ModeSingle
  chkTwilioTimer.Enabled =True
  chkTwilioTimer.Reset
  
  Return Err.ErrorNumber
End Try

It has always been recommended to use a new URLConnection for each request. Are you really reusing a URLConnection for days? :astonished:

Hi Tim,

Yes, in the first go, there is only one instance. In the second go, which is what the previous snippet was about I and trying another means where the object is invoked only when ready and is set to Nil following either an error or a successful send.

Here is more complete code:
This is the code ‘PrepareToSendMFA(TransActionRID’

This code is spawned from a timer. It does some work, then calls the next block of code.

Private Function PrepareToSendMFA(TransActionRID As Int64, MFADefaultsRID As Int64, ToPhone As String) As Integer
  Dim D As New Date
  Dim Msg As String 
  Dim TwilAcc As string
  Dim TwilToken As string
  Dim MsgToAdd As String
  Dim MFACode As Integer = -1
  
  MaxLength = eMFADefaults.Code_Length
  MsgToAdd = eMFADefaults.TextToAdd
  
  // Need to get the Twilio Account DEFAULTS and the Auth Token
  Dim Result As Integer = eSMSDefaults.getActive( False)
  If result = 1 then 
    eSMSDefaults.FillVars
    TwilAcc = eSMSDefaults.AccountID
    TwilToken = eSMSDefaults.AuthToken
  Else
    Return -2
  End If
  
  Dim FromPhNo As String =  eSMSDefaults.FromPhone
  Dim ToPhNo As String = eMFA_Transaction.ToPhone
  ToPhNo =  chk_PhoneNumber(ToPhNo )
  //TwilioNextIndex = SendTwilioBuffer.FirstIndex
  
  If ToPhNo.Trim <> eMFA_Transaction.ToPhone.Trim Then 
    eMFA_Transaction.ToPhone = ToPhNo
    Result = eMFA_Transaction.UpdateRowID(TransActionRID)
  End If
  
  If DebugBuild Or App.Debug = True Then 
    Flds = Array ("TRACE", CurrentMethodName,  "  Line 33, FromPhNo = " + FromPhNo + " ORG ToPhNo= " + ToPhNo +  "  Tp (after chk_phone)= " + ToPhNo  )
    Logs.AddFields Flds
    Logs.LogFileAppend( Logs.K_Trace_App )
  End If
  // -------------   -------------- //
  
  
  
  If FromPhNo <> "" AND ToPhNo <> "" Then 
    //*****  SEND TO TWILIO OBJECT ****** //
    // FromPhone As String, ToPhone As string, TwilioAccount As String, TwilioAuthToken As String, Msg As String, RowID As Integer
    // Call SendToTwilio(FromPhNo, ToPhNo, TwilAcc, TwilToken, Msg, TransActionRID)
    
    ////  Set this up in case of error so we can undo the ItemSent Property in the database
    //Twilio.TransActionRID = TransActionRID
    
    // Generate random code
    MFACode = GenerateRandomCode(MaxLength)
    
    eMFA_Transaction.TrackingNo = MFACode.ToText
    eMFA_Transaction.MFAPIN = MFACode
    
    Msg = Trim(MsgToAdd) + ":  * " + MFACode.ToString + " #"
    eMFA_Transaction.Msg = Msg
    eMFA_Transaction.SendMethod = "Text Message"
    eMFA_Transaction.FromPhone = FromPhNo
    
    //Do these items LAST
    eMFA_Transaction.ItemSent = "N"  // "Y"
    eMFA_Transaction.MFACode_Created_SQL_DateTime = d.SQLDateTime
    //eMFA_Transaction.Sent_SQL_DateTime = d.SQLDateTime
    eMFA_Transaction.EventDesc = "About to send MFA Code"
    Result = eMFA_Transaction.UpdateRowID(TransActionRID)
    
    //Dim p As integer = eMFA_Transaction.GateCode
    //
    //Result = eAccounts.getPIN(eMFA_Transaction.GateCode, True)
    //
    //p = eMFA_Transaction.GateCode
    
    
    Result = eAccounts.getPIN(eMFA_Transaction.GateCode, True)  //  012924a
    If MFACode > 0 Then
      eAccounts.MFAPIN = MFACode
      Result = eAccounts.UpdateRowID(eAccounts.RowID)
    End If
    
    
    //  There may be more than 1 record with the same Gate Code
    Result = eUnitsAccounts.getPIN(eMFA_Transaction.GateCode, False)
    If Result > 0  Then 
      Do Until  eUnitsAccounts.RsUnitsAccounts.EOF
         eUnitsAccounts.FillVars
        
        eUnitsAccounts.mfa_code = MFACode
        Result = eUnitsAccounts.UpdateRowID( eUnitsAccounts.RowID )
        
        eUnitsAccounts.RsUnitsAccounts.MoveNext
      Loop
    End If
    
    
    //  TwilioNextIndex = SendTwilioBuffer.FirstIndex
    Dim Buf As New clsSendTwilioBuffer
    Buf.FromPhNo = FromPhNo
    Buf.Msg = Msg 
    Buf.RID = TransActionRID
    Buf.ToPhNo = ToPhNo
    Buf.TransActionRID = TransActionRID
    Buf.Sent = False
    SendTwilioBuffer.Add Buf
    TwilioLastBufferIndex = SendTwilioBuffer.LastIndex
    
    
    //*****  SEND TO TWILIO OBJECT ****** //
    //  This is legacy code still there to check if the new URLConnection works any better
    Result = SendToTwilio(FromPhNo, ToPhNo, TwilAcc, TwilToken, Msg, TransActionRID)
    
    If Result = 0 Then 
      //Do these items LAST
      //Buf.Sent = False
      //SendTwilioBuffer.Add Buf
      
      SendTwilioBuffer(SendTwilioBuffer.LastIndex).Sent = True
      
      eMFA_Transaction.ItemSent = "Y"
      eMFA_Transaction.MFACode_Created_SQL_DateTime = d.SQLDateTime
      eMFA_Transaction.Sent_SQL_DateTime = d.SQLDateTime
      eMFA_Transaction.EventDesc = "Sent MFA Code"
      Result = eMFA_Transaction.UpdateRowID(TransActionRID)
      Return 0
      
    ElseIf Result > 0 Then 
      
      Return Result
    End If
    
    
  Else
    
    SendTwilioBuffer.RemoveAt(SendTwilioBuffer.LastIndex)
    eMFA_Transaction.ToPhone = "No Cell No Available"
    eMFA_Transaction.EventDesc = " Your Unit, " + eMFA_Transaction.UnitID  + ". No Phone Number set up for this unit or account.  Tracking No " + cstr(TransActionRID) + " "
    eMFA_Transaction.Sent_SQL_DateTime = d.SQLDateTime
    eMFA_Transaction.Msg = Msg
    eMFA_Transaction.ItemSent = "I   // ignor"
    eMFA_Transaction.SendMethod = "Text Message"
    eMFA_Transaction.EventDesc = "Sent MFA Code"
    Result = eMFA_Transaction.UpdateRowID(TransActionRID)
    Return -1
  End If
  
  Exception e As RuntimeException
    Flds() = Array ("EXCEPTION", CurrentMethodName, CStr(e.Type) )
    Logs.AddFields Flds
    Logs.LogFileAppend( Logs.K_Except_App_Err)
    
End Function

This next block of code does some prep work, then creates a new URLConnection Object and attempts to send.

Private Function SendToTwilio(FromPhone As String, ToPhone As string, TwilioAccount As String, TwilioAuthToken As String, Msg As String, TransActRID As Integer) As Integer
  Dim Lne As Integer = 0
  FromPhone = FromPhone.Trim
  ToPhone =  ToPhone.Trim
  
  If TwilioAccount = "" Then
    flds() = Array ("TRACE", "Missing Twilio Account ID" )
    Logs.AddFields Flds
    Logs.LogFileAppend( Logs.K_Trace_App)
    Return -1
  End If
  
  If TwilioAuthToken = "" Then
    flds() = Array ("TRACE", "Missing Twilio Auth Token")
    Logs.AddFields Flds
    Logs.LogFileAppend( Logs.K_Trace_App)
    Return -1
  End If
  
  If FromPhone = "" then
    flds() = Array ("TRACE", "Missing Twilio From Phone" )
    Logs.AddFields Flds
    Logs.LogFileAppend( Logs.K_Trace_App)
    Return -1
  End If
  
  Lne = 1
  Msg = Msg.Trim
  
  Lne = 2
  Dim accountID As String = TwilioAccount  // eSMSDefaults.AccountID.ToText
  Dim authToken As String = TwilioAuthToken  //  eSMSDefaults.AuthToken.ToText
  
  // -------------------------------------------- New Code ---------------------------------------------------- //
  Var params() As String
  Lne = 3
  params.Add("From=" + EncodeURLComponent(FromPhone ) )
  params.Add("To=" + EncodeURLComponent(ToPhone) )
  params.Add("Body=" + EncodeURLComponent(Msg) )
  Lne =4
  Var textParams As String = String.FromArray(params, "&")
  
  Lne = 5
  // Set the URL
  Var url As String = "https://api.twilio.com/2010-04-01/Accounts/" + accountID + "/Messages.json"
  
  Try
    Lne = 6
    Twilio = New TwilioSocket
    Call Twilio.Startup(Db)
    
    // Assign to the Request's Content
    Twilio.SetRequestContent(textParams, "application/x-www-form-urlencoded")
    
    //  Set this up in case of error so we can undo the ItemSent Property in the database
    Twilio.TransActionRID = TransActRID
    
    
    //----  012724a ------//
    Twilio.ToNo = ToPhone
    Twilio.Account = accountID
    Twilio.Token = authToken
    
    
    Lne = 7
    //  Set it not ready since we are about to send data
    Twilio.Ready = False
    
    Lne = 8
    // Send Request, results are in TwilioSocket.PageReceived event handler
    Twilio.Send("POST", url, 30)
    
    //Dim s As String = Twilio.SendSync("POST", url, 30)
    Return 0
    
    
  Catch Err
    //Exception err As TypeMismatchException
    //MessageBox("Tried to retype an object!")
    //Exception err As NilObjectException
    //MessageBox("Tried to access a Nil object!")
    //Exception err As RuntimeException ' NOT RECOMMENDED
    //MessageBox("Another exception")
    
    If Err IsA NetworkException Then 
      Lne = 9
      Flds = Array ("TRACE-EXCEPTION", CurrentMethodName + " Network Exception  Lne= " + Lne.ToString , Cstr(err.Type) + "  " + err.Message )
      Logs.AddFields Flds
      Logs.LogFileAppend( Logs.K_Except_App_Err )
      
    ElseIf Err IsA NilObjectException Then
      lne = 10
      Flds = Array ("TRACE-EXCEPTION", CurrentMethodName + " NilObject Eception Lne= " + Lne.ToString , Cstr(err.Type) + "  " + err.Message )
      Logs.AddFields Flds
      Logs.LogFileAppend( Logs.K_Except_App_Err )
      
    ElseIf Err IsA RuntimeException Then
      Lne = 11
      Flds = Array ("TRACE-EXCEPTION", CurrentMethodName + " Runtime Exception Lne= " + Lne.ToString , Cstr(err.Type) + "  " + err.Message )
      Logs.AddFields Flds
      Logs.LogFileAppend( Logs.K_Except_App_Err )
    End If
    
    
    //Flds = Array ("EXCEPTION", CurrentMethodName + "  Lne= " + Lne.ToString , Cstr(err.Type) + "  " + err.Message )
    //Logs.AddFields Flds
    //Logs.LogFileAppend( Logs.K_Except_App_Err )
    
    Twilio = Nil    // 012824
    
    eMFA_Transaction.ItemSent = "N"
    eMFA_Transaction.EventDesc = "Error " + Cstr(err.Type) + "  " + err.Message 
    Dim Result As Integer = eMFA_Transaction.UpdateRowID(TransActRID)
    
    chkTwilioTimer.Period = 50  //50mS
    chkTwilioTimer.Mode = Timer.ModeSingle
    chkTwilioTimer.Enabled =True
    chkTwilioTimer.Reset
    
    Return Err.ErrorNumber
  End Try
  
  Return -1
  
  
  
  Exception e as RuntimeException
    Flds = Array ("EXCEPTION", CurrentMethodName + "  Lne= " + Lne.ToString + "  " + e.Message , Cstr(e.Type) )
    Logs.AddFields Flds
    Logs.LogFileAppend( Logs.K_Except_App_Err)
    
End Function

If this is not the correct way to do it, can you please point me in the right direction? In use, sometimes there is only one POST to make, in others, there are several waiting in a database queue.

Also is it better to use “Twilio.SendSync” over just Twilio.send?

Thanks,
Tim

What about an array of URLConnections? Is that good to do?

Tim

Yes that’s what I do, and I remove and destroy completed requests. I wanted to give your post a full read through on my desktop to give you the best answer I can, but for now I’m on my iPad recovering from a recent illness. I’ll be back for you soon!

Get well Tim!
I’m going to do some surgery on the app and try this out in a different way from what I am doing now - I’ll be implementing an array of URLConnections.

Thanks again Tim and get well soon!
Tim

Well, it seems like you’re not re-using the same URLConnection for days because in the code you posted you’ve got Twilio = New TwilioSocket. It seems like each request should be a new URLConnection which brings an end to my only theory.

What does the Message of the UnsupportedOperationException say?

And my advice on Send / SendSync is to never ever never use SendSync. It locks up your whole application while it waits for a response creating a poor user experience.

Yes, it requires more work to build chained requests – but I’ve always been of the belief that you get the quality out equal to the work you put in.

1 Like

Thanks Tim!
Tim