0

This is a long one. Copied and pasted from blog entry found here:

http://www.bespokn.net/2017/01/22/code-anomaly-a001/

Running code should not produce different results given the same inputs. Pretty sure that’s axiomatic. Following is a detail of a webpage built with Visual Force interacting with an Apex controller extension that exhibits some behavior that I am temporarily labeling “random” and unexpected….

The purpose of the page is to permit a registered application user to create a password and to set challenge questions and answers. A live link to a current version of the page resides here:

Authentication Protocol

The page requires an instance of controller and a controller extension. The top of this class with some of the properties and variables of class follows. Then some visual force markup for the page rendering.

public class authSetUpExt {

authentication__c auth;

private contact con;

public string mobile {get; set;}

public string mobilephonestring {get; set;}

private static boolean showPhonePanel = true;

public static boolean getShowPhonePanel () {
    return showPhonePanel;
}

// standard controller is instantiated; ditto extension; // other methods follow // here's some page markup

    <apex:form id="apform" >

        <apex:outputPanel id="container1">
            <apex:outputPanel id="enterPhonePan" rendered="{!showPhonePanel}">

                <!-- some other code here  -->



                    <apex:inputText id="userPhone"
                                    label="Phone"
                                    value="{!mobilephonestring}"
                                    onkeypress="magic()" /> 
                    <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>

                    <apex:commandButton id="phoneBut"
                                        styleClass="selBut"
                                        value="  SUBMIT  "
                                        onclick="validatePhoneAndSend()"
                                        rerender="none" /><br/>
                    <apex:outputText id="pherr" style="font-size:12px;font-weight:bold;color:red"></apex:outputText>
                    <apex:outputText id="phstat1" style="font-size:12px;font-weight:bold;color:red" ></apex:outputText>
                    <apex:outputText id="phstat2" style="font-size:12px;font-weight:bold;color:green" ></apex:outputText>

                </div><br/>


            </apex:outputPanel>
        </apex:outputPanel>

        <apex:actionFunction name="fetchU"
                             action="{!getUser}"
                             rerender="container1,container2, container2a"
                             status="myStatus">
            <apex:param name="firstParam" assignto="{!mobile}"  value=""/>
        </apex:actionFunction>



            <apex:outputPanel id="onePhonePan" rendered="true"  > 

                <div class="wrap" >
                    We found your phone attached to one account.  We will send an access
                    code for verification.
                </div><br/>


                <div>

                    <hr class="style14" />
                    <br/><br/>       


                    <apex:commandButton id="sendText"
                                        rendered="{!!showCodeBox}"
                                        rerender="onePhonePan"
                                        action="{!sendAccessByText}" 
                                        styleClass="goBut" />

                    <span class="lab" >&nbsp;&nbsp;&nbsp;&nbsp;Send VIA text to {!conmob} </span><br/>

                    <apex:commandButton id="sendEmail"
                                        rendered="{!!showCodeBox}"
                                        rerender="onePhonePan,container2"
                                        action="{!sendAccessByEmail}" 
                                        styleClass="goBut" />

                    <span class="lab">&nbsp;&nbsp;&nbsp;&nbsp;Send email to {!conem}</span><br/>


                </div>

                <br/>

                <!-- call JS which reviews, sets vars and calls method in controller -->

                <div>
                    <hr class="style14" />
                    <br/>                               
                </div>
                <br/>

                <div>
                    <span class="lab">Enter the code here&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>

                    <apex:inputHidden id="hidcode" value="{!useraccessentry}" />
                    <apex:inputText id="acode" maxlength="6"
                                    value="{!useraccessentry}"
                                    onfocus="setObjVars()"
                                    rendered="{!showCodeBox}" /> <!-- onblur assign value to hidcode value ??? -->

                    <br/><br/>

                <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   
                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                         
                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                        
                &nbsp;&nbsp; </span>

                <apex:commandButton id="accessBut"
                                    styleClass="selBut"                   
                                    value="  SUBMIT  "
                                    onclick="submitAccess()" /><br/><br/>
                </div>


                <!-- event handlers on select for boxes call js calls action function / call method
                        method sends code; on confirm shows new page section in this outputPanel
                        these output vars to verify some controller properties / params passed in view state -->


                <apex:outputText >showContainer2 = {!showContainer2} </apex:outputText><br/><br/>
                <apex:outputText >showPushSingleProfile = {!showPushSingleProfile} </apex:outputText><br/><br/>
                <apex:outputText >conmob = {!conMob} </apex:outputText><br/><br/>
                <apex:outputText >conem = {!conem} </apex:outputText><br/><br/>

            </apex:outputPanel>


            <!-- some other code   -->

        </apex:form>

The first screen asks the user to enter a phone number. A command button calls a javaScript method validateAndSendPhone(). The js function validates the user’s entry and if valid, calls the actionFuntion fetchU() aka getUser(), passing the user entry with the function call. This should be familiar pattern work-around for those of you who are familiar with the known issue of passing parameters to the controller with a commandButton function call.

So far, so good. Here’s the js function:

    <!-- this method works as expected -->

function validatePhoneAndSend ()
{
    var phWin = document.getElementById("{!$Component.apform.userPhone}");
    var errstat = document.getElementById("{!$Component.apform.pherr}").innerHTML;

    if (errstat) 
    {
        console.log('should reset');
        document.getElementById("{!$Component.apform.pherr}").innerHTML = '';
    }

    var ph = document.getElementById("{!$Component.apform.userPhone}").value;
    var x = 0;
    for (var i = 0, len = ph.length; i < len; i++) 
    {
        var thisx = ph[i];
        var y = Number(thisx);
        console.log(thisx);
        console.log(y);

        if (thisx == y && (thisx === '0' || y != ' '))
        {
            console.log(thisx + ' increment');
            x++;
        }
    }

    console.log(x);

    if (x === 10)
    {
        console.log('count 10 : ' + ph);
        fetchU(ph);
    }

    else
    {
        console.log('bad count');
        document.getElementById("{!$Component.apform.pherr}").innerHTML = 'Phone number requires 10 digits.';
        phWin.focus();
    }
};

The following code runs in the controller, executing a query against Contact for a contact matching mobilephonestring__c. Focusing right now on the the code block that runs when the query returns a list of one, a host of controller variables are then set by the method.

    public void getUser () {

    system.debug('entered getUser method');

    system.debug(mobile);

    string q = 'select id, firstname, lastname, name, zfetch__c, mobilephone, '+
        'account.name, account.Mobile_account_primary__r.name, sms_send__c, '+
        'email from contact where mobilephonestring__c = : mobile AND zfetch__c = true';

    consFromPhone = database.query(q);

    integer s = consfromPhone.size();

    if (s == 0) {
        showNoProfile = true;

    }

    else if (s == 1) {

        showPhonePanel = false;
        showPushSingleProfile = false;
        con = consFromPhone[0];
        conmob = con.mobilePhone;
        conem = con.email;
        contextsend = con.sms_send__c;

    }

    else {
        showPhonePanel = false;
        showMultiProfiles = true;

    }

    system.debug(showNoProfile);
    system.debug(showSingleProfile);
    system.debug(showMultiProfiles);
    system.debug(showPhonePanel);

    system.debug(con.account.Mobile_account_primary__r.name);

}

An output panel is then rerendered which asks the user to select a notification method for the delivery of an access code. There is no need to pass any new data. If the user expresses a preference to receive a text message, one method is called; if by email, a different method is called. Each method is called by apex:commandButton.

In any case, the correct method is always called. The following code runs:

public void sendAccessByText () {

    string message = accessStringMessage(true);
    system.debug(mobile);
    system.debug(con);
    system.debug(conmob);
    system.debug(conem);
    system.debug(contextsend);

    sendmail.futureTextMssg(message, con.sms_send__c);

    showCodeBox = true;

}


//  HELPER FUNCTIONS


string access () {
    string access = string.valueof(math.random()).right(6);
    return access;
}

string accessStringMessage (boolean text) {
    accessCode = access();
    string message = '';

    if (text) {
        message += 'Use this code --- ' + accessCode +
            ' --- to set your password and challenge questions.' ; 
    }

    else {
        message += 'Use this code ---  \n\n' + accessCode +
            '\n\n --- to set your password and challenge questions. \n\n Thank you for using beSpoKn.' ;             

    }

    return message;
}    

AccessStringMessage() always generates a message. The following five debugs, however, is where the randomness comes in. Sometimes these are null, and sometimes they are not. What’s more, they are either all null, or they are all not null. No in-between. When they return null, of course, the page fails.

So there you have it….

  • 1
    Can you at least try to distill a single concise statement of which portion of your code exhibits "random" behavior? Try to reduce your example to something more manageable. Surely not every line included here is relevant. – Adrian Larson Jan 23 '17 at 2:05
  • 1
    I wouldn't care to speculate about what is relevant here and what is not. I'm all too familiar with questions that do not contain enough information... – VeeDee Jan 23 '17 at 2:25
  • 1
    If you would care to speculate about it, just imagine how we feel. – Adrian Larson Jan 23 '17 at 2:25
  • This would be much easier if the text-editor would just cooperate with me. Start with the codeBlock that begins "public void getUser()". We get a contact aka user, and when the next method is called -- "sendAccessByText()" -- sometimes the controller vars are still there, and sometimes they are null. All other things being equal.... that seems pretty strange to me.... Surely, the very literate you knows that all the good stuff is found at the end :-) And no fair asking me for imagination.... – VeeDee Jan 23 '17 at 2:53
  • You can go with with the first debug system.debug(mobile); why is it null intermittently . There are only few instances where it is called. Trace all of these and please update your question with some useful information/research which can replace the word "random" behavior. Because random is random for us also. – Ashwani Jan 23 '17 at 3:41
2

Firstly. The following lines from your code are a big security problem:

string q = 'select id, firstname, lastname, name, zfetch__c, mobilephone, '+
    'account.name, account.Mobile_account_primary__r.name, sms_send__c, '+
    'email from contact where mobilephonestring__c = : mobile AND zfetch__c = true';

consFromPhone = database.query(q);

Read up about SOQL injection.


The rest reads like a Viewstate issue. It seems likely that the modifications you are making to the member variables server side aren't always round tripping back to the client. Or they aren't being submitted back to the server when sendAccessByText() is called.

You will need to pull it apart bit by bit until the problem is isolated. Try adding some lines like System.assertNotEquals(null, mobile) in the appropriate locations in the extension class.

  • Familiar with the soql issue, thanks. Sleep-coding! Ummm.... View state. So I added a bunch of outputText lines in the mark-up to verify that these values were found, client-side... They are there, on the client, in the iteration immediately prior to actionFunction sendAccessByText() call back to the server. They're always available on the client, at least for as long as I have had these debugs placed, regardless of whether they reappear on the server. And then, these vars which are on the client don't make the trip to the server, but only sometimes... I've never had to debug view state. – VeeDee Jan 23 '17 at 10:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.