All posts by ransico

Train Game

After being stumped by the ‘train game’ one evening, I have made a quick Javascript ‘Train-Game’ solver (see it here)! I used html5 boilerplate and KendoUI to make it in ~ 1 hour.

The rules are simple. Take the 4 digit train number (normally visible near the stairs inside a carriage) and perform simple arithmatic operations on them such that the result is 10.

For example, take the train number ‘1234’. We can make 10 by the the following sequence:

1 + 2 + 3 + 4 = 10

also, 1 * 2 + 3 + 4 = 10.

You can even group digits, like so:

44 – 34 = 10

I’ve put in on a public repo on github as well as hosted it here.

ADF InputListOfValues Validation

Based on various sources, the InputListOfValues sometimes skips validation when the value has changed. The reasoning behind this is that the framework assumes that all values present in the LOV list are valid choices.

In reality, this may not always be the case. Especially if complex business rules dictate which values are valid; or if there is dependency for valid values between various fields. These complex validation scenarios are normally solved using a custom validator.

My solution to the issue of custom validators not being reliably called, was to subscribe to the ValueChangedEvent, and manually call each validator individually. Note that it is not enough to simply call control.validate().

JSF

  <af:inputListOfValues id="xxItNo"
                        value="#{row.bindings.ItemNo.inputValue}"
                        model="#{row.bindings.ItemNo.listOfValuesModel}"
                        autoSubmit="true"
                        valueChangeListener="#{BackingBeanInst.itemNoChangedListener}"
                        autoComplete="off">
      <f:validator binding="#{row.bindings.ItemNo.validator}"/>
      <f:validator validatorId="MultiOpItemNoValidator"/>
  </af:inputListOfValues>

Java Bean

public class BackingBeanInst {
  public void itemNoChangedListener(ValueChangeEvent valueChangeEvent) {
      log.fine("Entered itemNoChangedListener()");

      try {
            UIXInput input = (UIXInput)valueChangeEvent.getSource();
            forceInputValidation(input, valueChangeEvent.getNewValue());

            if (input.isValid()) {
                  // Perform some optional calculations if required
            } else {
                log.fine("input is invalid, skipping calculations");
            }
      } catch (Exception ex) {
            log.severe(ex);
      }
  }
}

Java Validator

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

import oracle.adf.share.logging.ADFLogger;

/**
 * Performs some arbitrary validation
 */
@FacesValidator("MultiOpItemNoValidator")
public class MultiOpItemNoValidator implements Validator {

    private static ADFLogger log = ADFLogger.createADFLogger(MultiOpItemNoValidator.class);

    @Override
    public void validate(FacesContext facesContext, UIComponent uiComponent, Object value) throws ValidatorException {

        if (log.isFine()) {
            log.fine("in validate");
            log.fine("new value= " + value);
        }

        boolean valid = true;
        try {

            // Super Advanced Custom Validation
            valid = false;
        } catch (Exception ex) {

            log.severe(ex);
        }

        if (!valid) {

            log.info("Falied Validation: " + ve.getMessage());
    
            FacesMessage msg = new FacesMessage("Item Number Validation Failed", ve.getMessage());
            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(msg);
        }
    }
}

faces-context

Remember to add your validator to faces-config.xml.