1 Reply Latest reply on May 17, 2010 4:35 PM by rhauch

    BasicSingleValueProperty turns into multi-value property

    cbredesen

      Hi Folks,

       

      I've created a custom FileSystemSource that adds metadata to my content.  Everything's gone quite well except for this one small issue.  I create properties in the default namespace like such:

       

      private Property createProperty(String namespace, String key, String value) {
          return new BasicSingleValueProperty(new BasicName(namespace, key), value);
      }

       

      But when I go to read the property, it always comes out as isMultiple() == true.  Is this a bug in Modeshape?  If not, how can I create a truly single-valued property?  I'm having to read property.getValue()[0].getString(), etc.

        • 1. Re: BasicSingleValueProperty turns into multi-value property
          rhauch

          Well, it's not a bug in ModeShape per se, but rather expected behavior under certain situations that happens to result in non-intuitive behavior in this case. It's fairly easy to deal with. Before I describe how to do that, let me explain what's happening.

           

          What's happening now

          When ModeShape accesses nodes from a connector, it looks at the primary type and mixin types for that node to find the most appropriate property definition for each of the node's properties.  If no valid property definition can be found, ModeShape uses one that is as lenient as possible, which is a property definition that is multi-valued.

           

          Remember that the file system connector is using "nt:file" and "nt:folder" node types for file nodes and directory nodes, respectively?  Well, these node types are defined by JCR and they do not handle any arbitrary property. (In JCR terminology, these node types do not define any residual property definitions.)  So any properties you add to the file or directory nodes technically do not match any of the property definitions on the "nt:file" and "nt:folder", and so ModeShape defaults to uber-lenient (and mult-valued) property definitions.

           

          The fix

          Now, this is pretty easy to fix by leveraging JCR's mixin types. Recall that every node in JCR can be assigned zero or more mixin types, and the property definitions of those types are "mixed into" those of the node's primary type. Since "nt:file" and "nt:folder" don't define the properties you're using, you can define these properties on a mixin type (or types), and then define the "jcr:mixinTypes" property on the particular node (the same way you're adding your custom properties). Then just be sure to define the mixin type in a CND file (see the Reference Guide for how to register node types in the configuration file or programmatically).

           

          For example, here is a node type that might define some properties commonly used for authored assets:

           

          [acme:authored] mixin

            - acme:created (date) 

            - acme:createdBy (string)

           

          Many mixins are designed to be very orthogonal and aspect-oriented, so one can simply combine one or more mixin types depending upon the properties you need (or aspects needed by the node). One can imagine a "acme:describable":

           

          [acme:title] mixin

            - acme:title (string)

            - acme:description (string) 

           

          Unfortunately, JCR 2.0 defines the "mix:authored" and "mix:title" (and several other) mixins, but ModeShape cannot include these out of the box per the JCR 1.0 requirements. One could also use an "extensible" mixin that allowed your nodes to contain single- or multi-valued properties with any name and type (aka, "residual properties"):

           

          [acme:extensible] mixin

            - * (undefined) multiple

            - * (undefined)

           

          Once these types are registered properly, change your CustomPropertiesFactory implementation to add properties with these names (using Java value objects that are compatible with the property types in your mixin types), and add a "jcr:mixinTypes" property with a value of the Name object for each of the mixins you want to add for that node.

           

          Use factories

          One final note.  We highly recommend you don't create the Property or Name objects via their concrete class constructors, but instead use the factories in the ExecutionContext instance (passed to the CustomPropertiesFactory methods). These factories are part of ModeShape's public API (whereas the implementation classes are not), and the factories also encapsulate all the fairly complex conversion and value enforcement logic.

           

          For example, your code looks like this when using the factories:

           

          private Property createProperty(ExecutionContext context, String namespace,
                                          String key, String value) {
              Name name = context.getValueFactories().getNameFactory().create(namespace,key);
              return context.getPropertyFactory().create(name,value);
          }

           

           

          The various value factories (e.g., getStringFactory(), getDateFactory(), getPathFactory(), etc.) have methods that will create a value of the specified type by converting from a variety of types. Those may come in handy depending upon how you're storing the extra properties.