4 Replies Latest reply on Jul 1, 2013 11:40 AM by Randall Hauch

    Custom mixin for node using cnd file

    singhl1 Newbie

      I need to create a custom mixin using a cnd file with the following properties:

       

      modificationType -       string

      modfiedBy -                string

      modifiedDate -            date

      comment -                  string

      path -                         string

       

      The cnd file needs to have multiple entries of these properties per node - so i presume the multiple syntax is required, i have managed to add single mixins without multiple so far, but this has stumped me so far.

       

      The multiple entries should also be ordered by the date if that is possible.

       

      Any help appreciated.

        • 1. Re: Custom mixin for node using cnd file
          Randall Hauch Master

          Please see the documentation. It's pretty easy. Based only upon the information you gave:

           

          <cust = "http://example.com/customNamespaceUri">
          
          cust:myMixin mixin
          - cust:modificationType (string) multiple
          - cust:modifiedBy (string) multiple
          - cust:modifiedDate (date) multiple
          - cust:comment (string) multiple
          - cust:path (path) multiple
          

           

          Note that it is not possible to have ModeShape enforce that the values in a multi-valued property are ordered in any particular way, so your application just needs to enforce the desired order of the values. (JCR nor ModeShape do anything other than keep the multiple values of a property in the same order the client provides.)

           

          Just remember that if you use any JCR or ModeShape namespaces (by referring to JCR or ModeShape node types), you will need to include the appropriate namespace(s).

           

           

          The multiple entries should also be ordered by the date if that is possible.

          Okay, so I read this and think that you might be using an "anti-pattern". Let's say that you want to record three modifications:

           

          Modification 1 at date/time DT1 by Smith1 with comment1

          Modification 2 at date/time DT2 by Smith2 with comment3

          Modification 3 at date/time DT3 by Smith3 with comment3

           

          It sounds like you want to put all of these dates in the "cust:modifiedDate" multi-valued property, all of the "by" values in the "cust:modifiedBy" multi-valued property, all of the comments in the "cust:comment" multi-valued property, etc. Then, you would correlate these values together based upon the index of the values in these multi-valued properties.

           

          A much better design would be to a single node to represent each modification. You can either place these modification nodes A) under a single area (which you'll probably want to organize by date) or B) under the node that was modified (e.g., the node designated by the "cust:path" property, which you would no longer need).

           

          Here's a sample structure for A, where the names of the modification nodes are simple string forms of the timestamp at which the modification was made (this is simply to easily enforce some uniqueness in the names while being semantically useful/interesting) using characters that don't have to be encoded (unfortunately ':' does have to be encoded since it's used to delimit the namespace prefix from the local name, so I used '.' instead in this example). Here I'm just using "nt:unstructured" nodes for the organizational nodes, but you could very easily define specific node types (e.g., to represent the modification log, year, month, and day nodes), defining as many constraints as you like.

           

          + /

             + modifications  (jcr:primaryType="nt:unstructured")

                 + 2013  (jcr:primaryType="nt:unstructured")

                    + 2013-June  (jcr:primaryType="nt:unstructured")

                       + 2013-June-10  (jcr:primaryType="nt:unstructured")

                          + 2013.06.10-11.01.34-043  (jcr:primaryType="cust:modification", cust:modifiedBy="Smith1", cust:comment="My comment", cust:modified="2013-06-10T11:01:34.04311UTC", ..., cust:path="...")

                         + 2013.06.10-13.04.23-033  (jcr:primaryType="cust:modification", cust:modifiedBy="Smith1", cust:comment="My comment", cust:modified="2013-06-10T13:04:23.03311UTC", ..., cust:path="...")

           

          I've shown the primary type to be "cust:modification" since (in this example) these nodes are first and foremost intended to represent a modification record. Here's what this node type might look like:

           

          <cust = "http://example.com/customNamespaceUri">
          
          cust:modification
          - cust:modificationType (string) mandatory
          - cust:modifiedBy (string) mandatory
          - cust:modifiedDate (date) mandatory
          - cust:comment (string) mandatory
          - cust:path (path) mandatory
          

           

          Note I marked all these properties as 'mandatory', since they will likely all be needed on every modification record. Also, they are all single-valued, since each node of this type represents a single modification record.

           

          Of course, you could easily use a different primary type and define a "cust:modified" mixin that has these properties. IMO, this is less than ideal (plus it's an extra step).

           

          You wanted to record the path of the modified node in the modification information. You can do that, and there will be advantages to that (it will never change, even when the node that was modified is moved or renamed). However, you may want to consider using a REFERENCE property. In this case, the modified nodes would need to be "mix:referenceable" (either explicitly in the mixins, or explicitly as a supertype of your node types). In this case, your "cust:path" would change to something like this:

           

          - cust:path (reference) mandatory
          

           

          It might even be nice to define a "cust:modified" mixin (with no properties, that extends "mix:referenceable") that you then add to any node that a user modifies and to which your modification records point. Then, you could add a constraint to the "cust:path" property definition so that it can only point to "cust:modified" nodes:

           

          - cust:path (reference) mandatory < 'cust:modified'
          

           

           

          Hope this helps!

          • 2. Re: Custom mixin for node using cnd file
            singhl1 Newbie

            Many thanks for the very detailed answer, will give that a try, i think i am thinkinking that using single a node to represent each modification is the way to go.

            • 3. Re: Custom mixin for node using cnd file
              singhl1 Newbie

              The requirement has changed a little now, the scenario is:

               

              I have a folder in my repository e.g "MyFolder", within which is a file, MyFile made up of an nt:file parent with a nt:resource child, MyResource and

               

              So

              MyFolder (nt:folder)

                   MyFile (nt:file)

                        MyResource (nt:resource).

               

               

              I want the nt:file to be versionable, and to be able to store a single cust:modification against each version of the nt:file, so in order to do this do i:

               

              Make the nt:file versionable (does the nt:resource and cust:modification also need to be versionable or do they inherit ther versionable from nt:file).

               

              does the nt:folder need to be versionable?

               

              I assume that when i update any versinable node, i check it out first, make changes and checkin using VersionManager?

               

              The may be multiple files under each folder, and maybe muliple folders under each folder eg (and also the cust:modification)

               

              MyFolder (nt:folder)

                   MyFile (nt:file)

                        MyResource (nt:resource)

                   MyFolder1

                       MyFolder2

                             MyFile2 (nt:file)

                             MyResource2 (nt:resource)

                        MyFolder3

                             MyFile3 (nt:file)

                             MyResource3 (nt:resource)

              • 4. Re: Custom mixin for node using cnd file
                Randall Hauch Master

                Let me start with the easy question first:

                 

                 

                I assume that when i update any versinable node, i check it out first, make changes and checkin using VersionManager?

                 

                Yes. Checkout, change+save, checkin.

                 

                Make the nt:file versionable (does the nt:resource and cust:modification also need to be versionable or do they inherit ther versionable from nt:file).

                 

                The 'cust:modification' node type does not need to be versionable. See below.

                 

                does the nt:folder need to be versionable?

                You need to consider whether you're going to version each file and folder separately, or whether you are going to want to version a folder and have that version include that node and all subnodes (e.g., all files). When you check in a node, ModeShape will effectively take a snapshot of that node and possibly the child nodes depending upon the "on parent versioning" or OPV attribute of the child node definition. The OPV is set on the child node definition, and the possible values and behaviors are:

                 

                • ABORT - the existance of such a child will cause an exception when checking in a parent
                • VERSION - the child must be checked in an versioned separately
                • COPY - the child and all decendants (regardless of whether they're versionable or their OPV setting) will be included in the snapshot that includes the parent
                • IGNORE, INITIALIZE, and COMPUTE - the child is ignored from a versioning/snapshotting perspective.

                 

                The default OPV of every child node definition is "COPY". Since the 'nt:file' and 'nt:folder' node types don't specify an OPV on their child node definitions, this means that checking in an 'nt:file' or 'nt:folder' node will create a snapshot of it and all child nodes (recursively), including the node that is of type 'cust:modification'.

                 

                So, assuming that you will continue to want the COPY OPV behavior, you only need to make 'mix:versionable' those node(s) that you want to explicitly check in. And remember, if you do go with COPY, then when you check in a folder, that folder's version snapshot will include all folders and files within it, so you don't need to version them separately.

                 

                 

                Now, there are ways of doing different behavior, but it will require using something other than 'nt:file' and 'nt:folder', and specifying non-default OPV. Let me know if you need this, because it is more complicated.