/**
   * Creates property descriptors for revision.
   *
   * @param spec specifies revision
   * @param groups the groups that group properties
   * @return map of property and descriptor
   */
  public static Map<String, RevisionPropertyTypeDesc> createPropertyDescriptors(
      RevisionSpec spec, PropertyGroupDesc groups[]) {
    Map<String, int[]> propsPerGroup = PropertyUtility.getGroupsPerProperty(groups);

    Map<String, RevisionPropertyTypeDesc> propertyDesc =
        new HashMap<String, RevisionPropertyTypeDesc>();
    int count = 0;

    for (String property : spec.getChangesetPropertyNames()) {
      EventPropertyGetter fullGetter = spec.getBaseEventType().getGetter(property);
      int propertyNumber = count;
      int[] propGroupsProperty = propsPerGroup.get(property);
      final RevisionGetterParameters params =
          new RevisionGetterParameters(property, propertyNumber, fullGetter, propGroupsProperty);

      // if there are no groups (full event property only), then simply use the full event getter
      EventPropertyGetter revisionGetter =
          new EventPropertyGetter() {
            public Object get(EventBean eventBean) throws PropertyAccessException {
              RevisionEventBeanDeclared riv = (RevisionEventBeanDeclared) eventBean;
              return riv.getVersionedValue(params);
            }

            public boolean isExistsProperty(EventBean eventBean) {
              return true;
            }

            public Object getFragment(EventBean eventBean) {
              return null; // fragments no provided by revision events
            }
          };

      Class type = spec.getBaseEventType().getPropertyType(property);
      RevisionPropertyTypeDesc propertyTypeDesc =
          new RevisionPropertyTypeDesc(revisionGetter, params, type);
      propertyDesc.put(property, propertyTypeDesc);
      count++;
    }

    for (String property : spec.getBaseEventOnlyPropertyNames()) {
      final EventPropertyGetter fullGetter = spec.getBaseEventType().getGetter(property);

      // if there are no groups (full event property only), then simply use the full event getter
      EventPropertyGetter revisionGetter =
          new EventPropertyGetter() {
            public Object get(EventBean eventBean) throws PropertyAccessException {
              RevisionEventBeanDeclared riv = (RevisionEventBeanDeclared) eventBean;
              return fullGetter.get(riv.getLastBaseEvent());
            }

            public boolean isExistsProperty(EventBean eventBean) {
              return true;
            }

            public Object getFragment(EventBean eventBean) {
              return null; // fragments no provided by revision events
            }
          };

      Class type = spec.getBaseEventType().getPropertyType(property);
      RevisionPropertyTypeDesc propertyTypeDesc =
          new RevisionPropertyTypeDesc(revisionGetter, null, type);
      propertyDesc.put(property, propertyTypeDesc);
      count++;
    }

    count = 0;
    for (String property : spec.getKeyPropertyNames()) {
      final int keyPropertyNumber = count;

      EventPropertyGetter revisionGetter =
          new EventPropertyGetter() {
            public Object get(EventBean eventBean) throws PropertyAccessException {
              RevisionEventBeanDeclared riv = (RevisionEventBeanDeclared) eventBean;
              return riv.getKey().getKeys()[keyPropertyNumber];
            }

            public boolean isExistsProperty(EventBean eventBean) {
              return true;
            }

            public Object getFragment(EventBean eventBean) {
              return null;
            }
          };

      Class type = spec.getBaseEventType().getPropertyType(property);
      RevisionPropertyTypeDesc propertyTypeDesc =
          new RevisionPropertyTypeDesc(revisionGetter, null, type);
      propertyDesc.put(property, propertyTypeDesc);
      count++;
    }

    return propertyDesc;
  }