Package org.richfaces.model

Source Code of org.richfaces.model.StackingTreeModel$ShiftingDataVisitor

/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/
package org.richfaces.model;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;

import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
import org.ajax4jsf.model.Range;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.iterators.FilterIterator;
import org.w3c.dom.NamedNodeMap;

/**
* That is intended for internal use
*
* @author Nick Belaevski mailto:nbelaevski@exadel.com created 25.07.2007
*
*/
public class StackingTreeModel extends AbstractTreeDataModel {

  //ctor arguments
  private String id;
  private String var;
  private StackingTreeModelDataProvider dataProvider;

  //structural elements
  private StackingTreeModel parent;
  private Map<String, StackingTreeModel> models = new LinkedHashMap<String, StackingTreeModel>();

  private Object rowKey;

  private class StackEntry {
    private Object modelKey;
    private Object varObject;
    private StackingTreeModel model;
    private Object rowData;
   
    public StackEntry(Object varObject, Object modelKey, Object rowData, StackingTreeModel model) {
      super();
      this.varObject = varObject;
      this.modelKey = modelKey;
      this.rowData = rowData;
      this.model = model;
    }
  }

//  private StackingTreeModel stackingTreeModel;
  private LinkedList<StackEntry> stackEntries = new LinkedList<StackEntry>();

  public ExtendedDataModel getDataModel() {
    Object data = dataProvider.getData();
    ExtendedDataModel dataModel;
    if (data instanceof Map || data instanceof NamedNodeMap) {
      dataModel = new MapDataModel();
    } else {
      dataModel = new SequenceDataModel();
    }

    dataModel.setWrappedData(data);
    return dataModel;
  }

  protected StackingTreeModel getCurrentModel() {
    if (this.rowKey == null) {
      return this;
    }
   
    if (isRowAvailable()) {
      return ((StackEntry) stackEntries.getLast()).model;
    }

    throw new IllegalStateException(
        "No tree element available or row key not set!");
  }
 
  public boolean isEmpty() {
    //TODO optimize that
    return getDataModel().getRowCount() == 0;
  }

  private void leaveModel(Iterator<StackEntry> iterator, StackEntry currentEntry, FacesContext context) {
    if (iterator == null) {
      return ;
    }

    LinkedList<StackEntry> stack = new LinkedList<StackEntry>();

    StackingTreeModel lastModel = null;
    if (currentEntry != null) {
      iterator.remove();
      stack.addFirst(currentEntry);
      lastModel = currentEntry.model;
    }
   
    while (iterator.hasNext()) {
      StackEntry entry = (StackEntry) iterator.next();
      if (entry.model != lastModel) {
        //always true for non-recursive models
        lastModel = entry.model;
        stack.addFirst(entry);
      }
     
      iterator.remove();
    }

    for (Iterator<StackEntry> iterator2 = stack.iterator(); iterator2.hasNext();) {
      StackEntry stackEntry = (StackEntry) iterator2.next();
      stackEntry.model.setupVariable(stackEntry.varObject, context);
    }
  }

  protected StackingTreeModel doSetupKey(Iterator<StackingTreeModelKey> keyIterator, Iterator<StackEntry> entriesIterator, FacesContext context, Object modelKey) {
    if (modelKey != null) {
      if (!setupModel(modelKey, context)) {
        //no key is available
        leaveModel(getRoot().stackEntries.iterator(), null, context);
        return null;
      }
     
      //TODO what's here?
    }
   
    if (keyIterator != null && keyIterator.hasNext()) {
      StackingTreeModelKey key = keyIterator.next();
      StackingTreeModel stackingTreeModel = this.getInternalModelById(key.modelId);
      Iterator<StackEntry> nextEntriesIterator = null;
      Object nextModelKey = key.modelKey;
     
      if (entriesIterator != null && entriesIterator.hasNext()) {
        StackEntry entry = entriesIterator.next();
        if (!entry.model.equals(stackingTreeModel) || !entry.modelKey.equals(nextModelKey)) {
          leaveModel(entriesIterator, entry, context);
        } else {
          //continue iterating entries, they still lead us by key path
          nextEntriesIterator = entriesIterator;
          nextModelKey = null;
        }
      }

      //should not be called when nextEntriesIterator & nextModelKey are both valid
      return stackingTreeModel.doSetupKey(keyIterator, nextEntriesIterator, context, nextModelKey);
   
    } else {
      leaveModel(entriesIterator, null, context);
      return this;
    }
  }
 
  protected StackingTreeModel setupKey(Object key, FacesContext context) {
    if (key == this.rowKey) {
      if (stackEntries.isEmpty()) {
        return this;
      } else {
        return (stackEntries.getLast()).model;
      }
    } else {
      Iterator<StackingTreeModelKey> keyIterator = null;
      if (key != null) {
        keyIterator = ((ListRowKey<StackingTreeModelKey>) key).iterator();
      }
     
      StackingTreeModel model = doSetupKey(keyIterator, stackEntries.iterator(), context, null);
      this.rowKey = key;

      return model;
    }
  }

  public StackingTreeModel(String id, String var, StackingTreeModelDataProvider dataProvider) {
    super();
    this.id = id;
    this.var = var;
    this.dataProvider = dataProvider;
  }

  public StackingTreeModel() {
    this(null, null, null);
  }

  private Object setupVariable(Object variable, FacesContext context) {
    if (var != null) {
      Map<String, Object> map = context.getExternalContext().getRequestMap();
      return map.put(var, variable);
    }

    return null;
  }

  public boolean setupModel(Object key, FacesContext facesContext) {
    ExtendedDataModel dataModel = getDataModel();
    dataModel.setRowKey(key);

    if (dataModel.isRowAvailable()) {
      Object rowData = dataModel.getRowData();
      //System.out.println("StackingTreeModel.setupModel() " + rowData);
      Object varObject = setupVariable(rowData, facesContext);

      getRoot().stackEntries.add(new StackEntry(varObject, key, rowData, this));

      return true;
    }
   
    return false;
  }

  public void setParent(StackingTreeModel parent) {
    this.parent = parent;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.richfaces.model.AbstractTreeDataModel#getTreeNode()
   */
  public TreeNode getTreeNode() {
    if (isRowAvailable()) {
      return null;
    }

    throw new IllegalStateException(
        "No tree element available or row key not set!");
  }

  /*
   * (non-Javadoc)
   *
   * @see org.richfaces.model.AbstractTreeDataModel#isLeaf()
   */
  public boolean isLeaf() {
    if (isRowAvailable()) {
      StackEntry lastEntry = (StackEntry) stackEntries.getLast();
      for (Iterator<StackingTreeModel> iterator = lastEntry.model.getInternalModelsIterator(); iterator.hasNext();) {
        StackingTreeModel stackingTreeModel = iterator.next();

        if (!stackingTreeModel.isEmpty()) {
          return false;
        }
      }

      return true;
    }
   
    throw new IllegalStateException(
        "No tree element available or row key not set!");
  }

  protected StackingTreeModel getRoot() {
    if (parent != null) {
      return parent.getRoot();
    }

    return this;
  }

  protected void doWalk(FacesContext context, DataVisitor dataVisitor,
      Range range, ListRowKey argumentKey, Object argument,
      boolean last) throws IOException {

    TreeRange treeRange = (TreeRange) range;
   
    if (treeRange == null || treeRange.processNode(argumentKey)) {
      StackingTreeModel rootModel = getRoot();
     
      if (argumentKey != null) {
        processElement(context, dataVisitor, argument, argumentKey, last);
      }
     
      final ShiftingDataVisitor shiftingDataVisitor = new ShiftingDataVisitor(
          new Visitor1(dataVisitor));
     
      if (treeRange == null || treeRange.processChildren(argumentKey)) {

        Object savedRowKey = rootModel.getRowKey();
        //setup key in order for nested components to initialize data models
        rootModel.setRowKey(context, argumentKey);
        Iterator<StackingTreeModel> iterator = this.getInternalModelsIterator();
        rootModel.setRowKey(context, savedRowKey);

        while (iterator.hasNext()) {
          final StackingTreeModel model = iterator.next();

          savedRowKey = rootModel.getRowKey();
          rootModel.setRowKey(context, argumentKey);
          final ExtendedDataModel scalarModel = model.getDataModel();
          rootModel.setRowKey(context, savedRowKey);
         
          Argument argument2 = new Argument();
          argument2.listRowKey = argumentKey;
          argument2.argument = argument;
          // setup current model
          argument2.model = model;
          argument2.range = range;
         
          scalarModel.walk(context, new DataVisitor() {

            public void process(FacesContext context,
                Object rowKey, Object argument)
                throws IOException {

              Object key = scalarModel.getRowKey();
              scalarModel.setRowKey(rowKey);
              Object data = scalarModel.getRowData();
             
              Object variable = model.setupVariable(data, context);
              boolean activeData = model.isActiveData();
              model.setupVariable(variable, context);
              scalarModel.setRowKey(key);

              if (activeData) {
                shiftingDataVisitor.process(context, rowKey, argument);
              }
            }
           
          }, null, argument2);
         
        }
      }
     
      shiftingDataVisitor.end(context);
    }
  }

  private StackingTreeModel getInternalModelById(String id) {
    StackingTreeModel model = getModelById(id);
    if (model.isActive()) {
      return model;
    }
   
    throw new IllegalStateException();
  }
 
  public StackingTreeModel getModelById(String id) {
    return (StackingTreeModel) models.get(id);
  }
 
  private Iterator<StackingTreeModel> getInternalModelsIterator() {
    return new FilterIterator(getModelsIterator(), ACTIVE_MODEL_PREDICATE);
  }
 
  public Iterator<StackingTreeModel> getModelsIterator() {
    return models.values().iterator();
  }
 
  public void walk(FacesContext context, DataVisitor dataVisitor,
      Range range, Object rowKey, Object argument,
      boolean last) throws IOException {
    StackingTreeModel rootModel = getRoot();
   
    if (rowKey != null) {
      ListRowKey listRowKey = (ListRowKey) rowKey;

      StackingTreeModel treeModel = rootModel.setupKey(listRowKey, context);

      treeModel.doWalk(context, dataVisitor, range, listRowKey, argument,
          last);

    } else {
      doWalk(context, dataVisitor, range,
          (ListRowKey) rowKey, argument, last);
    }
  }

  private class Argument {
    private ListRowKey listRowKey;
    private StackingTreeModel model;
    private Range range;
    private Object argument;
  }

  private class Visitor1 implements DataVisitor, LastElementAware {
    private DataVisitor dataVisitor;
    private boolean theLast;

    public Visitor1(DataVisitor dataVisitor) {
      super();
      this.dataVisitor = dataVisitor;
    }

    public void process(FacesContext context, Object rowKey, Object argument)
    throws IOException {

      Argument a = (Argument) argument;
      ListRowKey listRowKey = new ListRowKey(a.listRowKey, new StackingTreeModelKey(
          a.model.id, rowKey));
      //System.out.println(".walk() " + (theLast ? " * " : "") + listRowKey);

      a.model.doWalk(context, dataVisitor, a.range, listRowKey, a.argument,
          theLast);
    }

    public void resetLastElement() {
      theLast = false;
    }

    public void setLastElement() {
      theLast = true;
    }

  }

  private static class ShiftingDataVisitor implements DataVisitor {

    private DataVisitor dataVisitor;

    public ShiftingDataVisitor(DataVisitor dataVisitor) {
      super();
      this.dataVisitor = dataVisitor;
    }

    private Object rowKey;
    private Object argument;
    private boolean shifted = false;

    public void process(FacesContext context, Object rowKey, Object argument)
    throws IOException {

      if (!shifted) {
        this.rowKey = rowKey;
        this.argument = argument;
        this.shifted = true;
      } else {
        dataVisitor.process(context, this.rowKey, this.argument);
        this.rowKey = rowKey;
        this.argument = argument;
      }
    }

    public void end(FacesContext context) throws IOException {
      if (shifted) {
        try {
          ((LastElementAware) dataVisitor).setLastElement();
          dataVisitor.process(context, this.rowKey, argument);
        } finally {
          ((LastElementAware) dataVisitor).resetLastElement();
        }
      }
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.richfaces.model.AbstractTreeDataModel#walkModel(javax.faces.context.FacesContext,
   *      org.ajax4jsf.model.DataVisitor, org.ajax4jsf.model.Range,
   *      java.lang.Object, java.lang.Object, boolean)
   */
  public void walkModel(FacesContext facesContext, DataVisitor visitor,
      Range range, Object key, Object argument, boolean last)
  throws IOException {

    walk(facesContext, visitor, range, key, argument, last);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.ajax4jsf.model.ExtendedDataModel#getRowKey()
   */
  public Object getRowKey() {
    return rowKey;
  }

  public void setRowKey(Object key) {
    setRowKey(FacesContext.getCurrentInstance(), key);
  }

  public void setRowKey(FacesContext context, Object key) {
    setupKey(key, context);
  }

  public void addStackingModel(StackingTreeModel model) {
    this.models.put(model.id, model);
    model.setParent(this);
  }

  public void removeStackingModel(StackingTreeModel model) {
    this.models.remove(model.id);
    model.setParent(null);
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.faces.model.DataModel#getRowData()
   */
  public Object getRowData() {
    if (isRowAvailable()) {
      StackEntry lastEntry = (StackEntry) stackEntries.getLast();
      return lastEntry.rowData;
    }
   
    throw new IllegalStateException(
        "No tree element available or row key not set!");
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.faces.model.DataModel#isRowAvailable()
   */
  public boolean isRowAvailable() {
    return !stackEntries.isEmpty();
  }

  public StackingTreeModel getParent() {
    return parent;
  }

  protected boolean isActiveData() {
    return true;
  }
 
  protected boolean isActive() {
    return true;
  }

  private final static Predicate ACTIVE_MODEL_PREDICATE = new Predicate() {

    public boolean evaluate(Object object) {
      StackingTreeModel model = (StackingTreeModel) object;
      if (model == null) {
        return false;
      }

      return model.isActive();
    }
   
  };

  @Override
  public Object getWrappedData() {
    throw new UnsupportedOperationException();
  }

  @Override
  public void setWrappedData(Object data) {
    throw new UnsupportedOperationException();
  }

  @Override
  public Object convertToKey(FacesContext context, String keyString,
    UIComponent component, Converter converter) {

      //force model leave
      setRowKey(context, null);
     
      String[] strings = ListRowKey.fromString(keyString);
      int l = strings.length / 2;
      List<Object> list = new ArrayList<Object>(l);
      StackingTreeModel model = getRoot();
     
      for (int i = 0; i < l; i++) {
    int idx = i*2;

    String modelId = strings[idx];
    model = model.getModelById(modelId);
    if (model.isActive()) {
      Object key = model.convert(context, strings[idx + 1], component, converter);
      if (key == null) {
          return null;
      }
     
      list.add(new StackingTreeModelKey(modelId, key));
     
      if (!model.setupModel(key, context) || !model.isActiveData()) {
          return null;
      }
    } else {
        return null;
    }
      }
     
      return new ListRowKey<Object>(list);
  }

  protected Object convert(FacesContext context, String string,
    UIComponent component, Converter converter) {
     
      ConvertableKeyModel convertable = (ConvertableKeyModel) getDataModel();
      return convertable.getKeyAsObject(context, string, component, converter);
  }
 
  public String getId() {
    return id;
  }
}
TOP

Related Classes of org.richfaces.model.StackingTreeModel$ShiftingDataVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.