1 Reply Latest reply on Aug 20, 2010 4:40 AM by Nick Belaevski

    About extended data models

    Bernard Labno Master

      Hi,

      I'm developing another component, which could use ExtendedDataModel that would use my custom Range (the SquareRange(startX,startY,endX,endY)).

      I've looked around RF sources to see how datamodels are used and found out that there are some assumptions made.

      I.e.: org.ajax4jsf.model.SequenceDataModel

      It casts Range to SequenceRange without any check if it is instance of SequenceRange, and there is no mentioning about acceptable Range in javadoc.

       

      I think it is dangerous to do check in UIComponent if datamodel is instance of ExtendedDataModel and then send there some custom implementation of Range.

       

      I also have question about using extended data model by UIComponent. If I want to retrive data restricted by SquareRange (my custom implementation) from datamodel (also my custom impl), should i store keys passed to "process" method of DataVisitor by datamodel and then retrive data from datamodel according to set of passed keys, or should I assume, that if I pass SquareRange to "walk" method then datamodel will filter itself and I can iterate over all rowIndexes?

       

      Here is my solution according to first approach. Could you comment if it is right?

       

       

           public List<Map<String, Object>> getData(int startX, int startY, int endX, int endY) throws IOException {
              ELContext elContext = getFacesContext().getELContext();
              ValueExpression valueExpression = getFacesContext().getApplication().getExpressionFactory().createValueExpression(getFacesContext().getELContext(), "#{" + getVar() + "}", Object.class);
              List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
              DataModel dataModel = getDataModel();
              List<Object> elements = new ArrayList<Object>();
       
              if (dataModel instanceof ExtendedDataModel) {
                  final List<Object> keys = new ArrayList<Object>();
                  DataVisitor visitor = new DataVisitor() {
                      public void process(FacesContext context, Object rowKey, Object argument) throws IOException {
                          keys.add(rowKey);
                      }
                  };
                  ((ExtendedDataModel) dataModel).walk(getFacesContext(), visitor, new SquareRange(startX, startY, endX, endY), null);
                  for (Object key : keys) {
                      ((ExtendedDataModel) dataModel).setRowKey(key);
                      if (dataModel.isRowAvailable()) {
                          elements.add(dataModel.getRowData());
                      }
                  }
              } else {
                  for (int i = 0; i < dataModel.getRowCount(); i++) {
                      dataModel.setRowIndex(i);
                      if (dataModel.isRowAvailable()) {
                          elements.add(dataModel.getRowData());
                      }
                  }
              }
       
              for (Object element : elements) {
                  valueExpression.setValue(elContext, element);
                  Map<String, Object> firstDataElement = new HashMap<String, Object>();
                  for (UIComponent child : getChildren()) {
                      if (child instanceof UICoordinatesGridItem) {
                          UICoordinatesGridItem item = (UICoordinatesGridItem) child;
                          if (!item.isRendered()) {
                              continue;
                          }
                          firstDataElement.put("x", item.getX());
                          firstDataElement.put("y", item.getY());
                          if (item.getText() != null) {
                              firstDataElement.put("text", item.getText());
                          }
                          if (item.getStyleClass() != null) {
                              firstDataElement.put("className", item.getStyleClass());
                          }
                          data.add(firstDataElement);
                      }
                  }
              }
              valueExpression.setValue(elContext, null);
              return data;
          }
      

      And here is ExtendedDataModel implementation:

       

          /** This is inner class */
          private class CustomDataModel extends SequenceDataModel {
              public CustomDataModel() {
                  /** seats is attribute of outer class */
                  super(new ListDataModel(seats));
              }
      
              @Override
              public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
                  SquareRange squareRange = null;
                  if (range instanceof SquareRange) {
                      squareRange = (SquareRange) range;
                  }
                  if (squareRange == null) {
                      super.walk(context, visitor, new SequenceRange(0, -1), argument);
                  } else {
                      for (int i = 0; i < seats.size(); i++) {
                          Seat seat = seats.get(i);
                          if (squareRange.getStartX() <= seat.getSeatNr() && seat.getSeatNr() <= squareRange.getEndX()
                              && squareRange.getStartY() <= seat.getRow() && seat.getRow() <= squareRange.getEndY()) {
                              visitor.process(context, i, argument);
                          }
                      }
                  }
              }
          }
      

        • 1. Re: About extended data models
          Nick Belaevski Master

          Hi Bernard,

          I think it is dangerous to do check in UIComponent if datamodel is instance of ExtendedDataModel and then send there some custom implementation of Range.

          DataModel should be able to work with what component provided as range. If no - this model is not supported by the component.

          I also have question about using extended data model by UIComponent. If I want to retrive data restricted by SquareRange (my custom implementation) from datamodel (also my custom impl), should i store keys passed to "process" method of DataVisitor by datamodel and then retrive data from datamodel according to set of passed keys, or should I assume, that if I pass SquareRange to "walk" method then datamodel will filter itself and I can iterate over all rowIndexes?

          Yes, data model should filter itself and return only items that in the range.

           

          Commented model code:

                  //place var into requestMap directly
                  ValueExpression valueExpression = getFacesContext().getApplication().getExpressionFactory().createValueExpression(getFacesContext().getELContext(), "#{" + getVar() + "}", Object.class);
          

                  if (dataModel instanceof ExtendedDataModel) {
                      final List<Object> keys = new ArrayList<Object>();
                      DataVisitor visitor = new DataVisitor() {
                          public void process(FacesContext context, Object rowKey, Object argument) throws IOException {
                              //get row data here
          
          
                              keys.add(rowKey);
                          }
                      };
                      ((ExtendedDataModel) dataModel).walk(getFacesContext(), visitor, new SquareRange(startX, startY, endX, endY), null);
                      for (Object key : keys) {
                          ((ExtendedDataModel) dataModel).setRowKey(key);
                          if (dataModel.isRowAvailable()) {
                              elements.add(dataModel.getRowData());
                          }
                      }
                  } else {
                      //doesn't use range
                      //simple model can be just wrapped into ExtendedDataModel
                      for (int i = 0; i < dataModel.getRowCount(); i++) {
                          dataModel.setRowIndex(i);
                          if (dataModel.isRowAvailable()) {
                              elements.add(dataModel.getRowData());
                          }
                      }
                  }