Skip to main content
Jump to: navigation, search

Talk:SMILA/Documentation/2011.Simplification/Data Model and Serialization Formats

comments and ideas on the current model

TM: I have just briefly looked @ the new DM and had some ideas/remarks which I just put down in all brevity as a bullet list. At times these are formulated rather strongly as "should be" and not as a question. So plz. be not offended and just comment on why this is not a good idea or does not work for Smila.

  • TM: AnyMap should extend Map interface, AnySeq should extend List
    • AW: We had that in mind, so we named the methods as they are in the appropriate Java interfaces. But we didn't want to have that dependency resp. implement all methods at first version. Maybe we should... ;)
      • TM: i really would suggest this as it opens a whole world of interoperability of utility classes that we then can use (e.g. apache.commons.collections). Other than laziness, i dont see a reason not to ;).
  • TM: isValue -> isContainer, isLiteral
Reason: also a Map, Seq is a Value, albeit a complex one hence isValue is not really that telling IMO
  • AW: Naming discussions are evil. ;) After some discussion we agreed on the term "Value" for scalar Any values, and so the method is named isValue(). Should be clear for a user in that context I think.
    • TM: naming discussions are good, because that is what u have to deduct the functionality! but yes, sometimes it just boils down to taste and preference. i just raised it b/c when looking at the method names and trying to understand the model behind it (at that time i hadnt seen the diagram yet) i wasn't quite sure what value meant here, and hence i brought it up (foolishly thinking that others might have the same problem).
  • TM: what is the distinction between Date and DateTime other than the use case? i.e. do we treat its value differently, e.g. truncate the time part in case we say asDate()
    • AW: Internally, both are mapped to java.util.Date. But we need different print/stringconvert formats for both, so we have to use different value types. (Yes, asString() truncates the timepart for DATE)
  • TM: why have a Value class and not use java native objects directly? e.g. Boolean, Integer, …
    • AW: Hmm, I think this allows for a more generic handling of 'Any' objects. But in the impl. we also offer methods handling native types like AnyMap.put(String,String), AnyMap.put(String,Number) to make usage easy.
  • TM: Value.asXXX() I see that they throw exceptions, depending on what u want to do this is good or just bothersome.
I would also provide a version that silently returns NULL (in C# the cast operator "as" behaves like so, and I miss it sometimes in java) OR
a default value in case datatype doesn’t match – or even convert automatically.
this could be done by overloading with a parameter that takes the default value, a flag that controls return null vs. throw exception or having 2 sets of methods
  • AW: I'd prefer to have a method Value.getObject() to get the native value (which was missing and is added at the moment right now ;). Then a user can handle that for his own.
  • TM: Record.getMetadata() -> Record.getValueMap()
reason: sometimes we don’t have attachments at all and only use the "meta data" which is then not just "meta", e.g. in case of search
  • AW: Naming discussions are evil[2] ;) Convention (at the moment) is that everything stored in the record's AnyMap is called record's "metadata", which can be semantically interpreted as record's attributes, parameters etc.
  • TM: are we still going to have some Path object or smth equivalent? I kind of liked that…
    • AW: not sure if we really need that. IMHO, in most cases it's easier to "manually" step to the appropriate metadata level. Maybe it could be useful to provide a helper class to accessing values on different levels if needed...
      • TM: i think it would be useful but we dont need to impl. it right now. i just wondered.
  • TM: Attachments, the record should always have an indicator of all attachments and tell if the attachment has been filtered out. that way we don’t need a trip to the BB and ask that.
    • AW: Not sure if I got point your here. Record has interfaces to check for resp. access attachments, or what do you mean? However, this should be independent from the new data model
      • TM: scratch that thought


Regarding the counter proposal:

  • AW: We didn't want to have a flat Any structure with just one class. By having explicit interfaces for AnyMap, AnySeq and Value you can provide clearer interfaces and clearer implementation code.
    • TM: yes, i understand that reason and can agree with that, i.e. I already thought that my Any proposal is quite an all-in-one-beast, which will be a nice challenge to impl. and test. On the other hand i believe it is a simpler/easier/quicker/less verbose interface to work with (less classes) while at the same time offering the nice feature of a bag semantic. However, i admit, the (uncommon/less known) bag semantic can also be a curse to the unsuspecting user (i.e. who doesnt read the API thoroughly) causing errors when not taking into account that there can be >1 Any children with the same name.
  • AW: However, some methods you proposed look quite useful (e.g. add(Any... value)), it shouldn't be a problem to extend the current interfaces for additional methods.

Counter Proposal for an AnyValue Interface

This is my idea on how a simple model might look like.

This class is an all-in-one approach and models a tree like structure with anonymous and named children of type Any. In that sense Any is a node that may have a literal value and Any-children. The model is somewhat similar to DOM, but much simpler; it borrows these the two key features:

  • ordered children (that may have a name)
  • allows to have >1 same named children

This effectively provides List and multi-valued map (Bag) semantic, which have their own objects in the original proposal. For more details read the comments in the interface.

So far (i did this in 1.5h time this morning) i haven thought of a serialization model for this but thing that it is not a problem. the only mismatch is that the serialized version probably will have an own construct (i.e. special child) for the Literal of a node whereas the Any is modeled to be a literal itself. But this can be changed to make the object model more close to the serialization model. see also the comment in code.


/**
 * The Interface Any.
 * Counter proposal for simplification of smila.
 */
interface Any extends Iterable<Any>, List<Any> {
 
  // #################################################################################
  // literal
  /**
   * this models that the Any is also a Literal. another flavor is to model the Literal as a seperate value object and
   * move all the following methods to that object.
   * 
   * TODO | TM |
   * 
   * <pre>
   * the asXXX methods will always return null in case of a miss or error, while the toXXX will throw an exception if the type doesnt fit.
   * asXXX()
   * asXXX(T defaultValue)
   * toXXX()
   * toXXX(T defaultValue)  //NOTE: this will overwrite the Object.toString() and is not so nice but i think i can live with that
   * </pre>
   * 
   * | TM @ Mar 11, 2011
   *
   * @return the string
   */
  // #################################################################################
  /**
   * @return The string representation
   */
  String asString();
 
  /**
   * As double.
   *
   * @return The double representation, an InvalidValueTypeException is thrown if the value is not of type double.
   */
  Double asDouble();
 
  /**
   * As long.
   *
   * @return The long representation, an InvalidValueTypeException is thrown if the value is not of type long.
   */
  Long asLong();
 
  /**
   * As boolean.
   *
   * @return The boolean representation, an InvalidValueTypeException is thrown if the value is not of type boolean.
   */
  Boolean asBoolean();
 
  /**
   * As date.
   *
   * @return The date representation, an InvalidValueTypeException is thrown if the value is not of type date.
   */
  Date asDate();
 
  /**
   * As date time.
   *
   * @return The date time representation, an InvalidValueTypeException is thrown if the value is not of type date time.
   */
  Date asDateTime();
 
  /**
   * Enumeration with the possible value types.
   * 
   */
  enum LiteralType {
 
    /** The STRING. */
    STRING, 
 /** The DOUBLE. */
 DOUBLE, 
 /** The BOOLEAN. */
 BOOLEAN, 
 /** The LONG. */
 LONG, 
 /** The DATE. */
 DATE, 
 /** The DATETIME. */
 DATETIME
  };
 
  /**
   * sets the value, the type is deducted must be one of the allowed ones.
   * 
   * @param <T>
   *          the generic type
   * @param literal
   *          the literal
   * @return the a possibly previosly set literal
   * @throws ClassCastException
   *           the class cast exception
   * @throws InvalidValueTypeException
   *           in case the given literal is not an allowed type
   * @note there might be the rare case where one wants to set another type. in this case one just would have to work
   *       with castsa like so:<br/>
   *       <code>Date date = (Date) _any.setLiteral((Object) "Tue 1st, Dec");</code>
   */
  <T> T setLiteral(T literal) throws ClassCastException, InvalidValueTypeException;
 
  /**
   * Gets the literal type.
   *
   * @return value type
   */
  LiteralType getLiteralType();
 
  /**
   * Checks for literal.
   * 
   * @return true, if this Any's literal is not null
   */
  boolean hasLiteral();
 
  /**
   * Checks if is string.
   *
   * @return true if value is of type string
   */
  boolean isString();
 
  /**
   * Checks if is double.
   *
   * @return true if value is of type double
   */
  boolean isDouble();
 
  /**
   * Checks if is boolean.
   *
   * @return true if value is of type boolean
   */
  boolean isBoolean();
 
  /**
   * Checks if is long.
   *
   * @return true if value is of type long
   */
  boolean isLong();
 
  /**
   * Checks if is date.
   *
   * @return true if value is of type date
   */
  boolean isDate();
 
  /**
   * Checks if is date time.
   *
   * @return true if value is of type date time
   */
  boolean isDateTime();
 
  /**
   * Gets the factory.
   *
   * @return data factory to create Anys of the same kind.
   */
  DataFactory getFactory();
 
  /**
   * Size.
   *
   * @return size of Any. For {@link Value} this is always 1.
   */
  int size();
 
  // #################################################################################
  // name
  // #################################################################################
 
  /**
   * Gets the name of this AnyValue. Note that it may be empty ("")! Any objects created with a blank String are trimmed
   * to empty. Any objects with an empty name are called anonymous children
   * 
   * @return the name
   */
  String getName();
 
  /**
   * Checks if is anonymous name.
   *
   * @return true, if is anonymous name
   */
  boolean isAnonymousName();
 
  // #################################################################################
  // child accessors
  /**
   * the children are held in a list and that is the primary form of their keeping. that is: they mantain their order
   * when retrieved (get, iterator). The Any object has a name which may be used to access the child item(s). However,
   * the name needs not be unique and hence there can be >1 children with the same name (Bag semantic).
   *
   * @return the iterator
   */
  // #################################################################################
  /**
   * @return iterates over underlying list in order.
   */
  @Override
  Iterator<Any> iterator();
 
  /** {@inheritDoc}
   * @see java.util.List#get(int)
   */
  Any get(int index);
 
  /**
   * Gets the first.
   *
   * @param name the name
   * @return the first
   */
  Any getFirst(String name);
 
  /**
   * Gets the.
   *
   * @param name the name
   * @return the list
   */
  List<Any> get(String name);
 
  /**
   * Gets the as array.
   *
   * @param name the name
   * @return the as array
   */
  Any[] getAsArray(String name);
 
  /**
   * Gets the all.
   *
   * @return the all
   */
  Map<String, List<Any>> getAll();
 
  /**
   * inserts the values at the given position.
   *
   * @param index the index
   * @param value the value
   */
  void add(int index, Any... value);
 
  /**
   * replaces the same amount of Any values with the given ones. If there are less to be replaced than to be added then
   * the excess will be appended.
   * 
   * @param index
   *          the index
   * @param value
   *          the value
   * @return the replaced any values
   */
  List<Any> set(int index, Any... value);
 
  /**
   * appends the new value.
   * 
   * @param value
   *          the value
   */
  void add(Any... value);
 
  /**
   * replaces existing values with the same name at their index position; given values for which no replacement exists
   * are appended.
   * 
   * @param value
   *          the value
   * @return the replaced values
   */
  List<Any> set(Any... value);
 
}

Back to the top