title: AbstractReadonlyModel in wicket Framework
body: <pre><code>package org.apache.wicket.examples.ajax.builtin;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.apache.wicket.ajax.AjaxRequestTarget;
  import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
  import org.apache.wicket.markup.html.form.DropDownChoice;
  import org.apache.wicket.markup.html.form.Form;
  import org.apache.wicket.model.AbstractReadOnlyModel;
  import org.apache.wicket.model.IModel;
  import org.apache.wicket.model.Model;
  import org.apache.wicket.model.PropertyModel;
  
  /**
   * Linked select boxes example
   * 
   * @author Igor Vaynberg (ivaynberg)
   */
  public class ChoicePage extends BasePage
  {
  private String selectedMake;
  
  private final Map&lt;String, List&lt;String&gt;&gt; modelsMap = new HashMap&lt;String, List&lt;String&gt;&gt;(); // map:company-&gt;model
  
  /**
   * @return Currently selected make
   */
  public String getSelectedMake()
  {
      return selectedMake;
  }
  
  /**
   * @param selectedMake
   *            The make that is currently selected
   */
  public void setSelectedMake(String selectedMake)
  {
      this.selectedMake = selectedMake;
  }
  
  /**
   * Constructor.
   */
  public ChoicePage()
  {
      modelsMap.put("AUDI", Arrays.asList(new String[] { "A4", "A6", "TT" }));
      modelsMap.put("CADILLAC", Arrays.asList(new String[] { "CTS", "DTS", "ESCALADE", "SRX",
              "DEVILLE" }));
      modelsMap.put("FORD", Arrays.asList(new String[] { "CROWN", "ESCAPE", "EXPEDITION",
              "EXPLORER", "F-150" }));
  
      IModel&lt;List&lt;? extends String&gt;&gt; makeChoices = new AbstractReadOnlyModel&lt;List&lt;? extends String&gt;&gt;()
      {
          @Override
          public List&lt;String&gt; getObject()
          {
              Set&lt;String&gt; keys = modelsMap.keySet();
              List&lt;String&gt; list = new ArrayList&lt;String&gt;(keys);
              return list;
          }
  
      };
  
      IModel&lt;List&lt;? extends String&gt;&gt; modelChoices = new AbstractReadOnlyModel&lt;List&lt;? extends String&gt;&gt;()
      {
          @Override
          public List&lt;String&gt; getObject()
          {
              List&lt;String&gt; models = modelsMap.get(selectedMake);
              if (models == null)
              {
                  models = Collections.emptyList();
              }
              return models;
          }
  
      };
  
      Form&lt;?&gt; form = new Form("form");
      add(form);
  
      final DropDownChoice&lt;String&gt; makes = new DropDownChoice&lt;String&gt;("makes",
          new PropertyModel&lt;String&gt;(this, "selectedMake"), makeChoices);
  
      final DropDownChoice&lt;String&gt; models = new DropDownChoice&lt;String&gt;("models",
          new Model&lt;String&gt;(), modelChoices);
      models.setOutputMarkupId(true);
  
      form.add(makes);
      form.add(models);
  
      makes.add(new AjaxFormComponentUpdatingBehavior("onchange")
      {
          @Override
          protected void onUpdate(AjaxRequestTarget target)
          {
              target.addComponent(models);
          }
      });
  }
  </code></pre>
  
  <p>}</p>
  
  <p>What is the use two AbstractReadonlyModel here?i couldnt understand the logic of this program.can anybody plz help to understand this one</p>