15 Replies Latest reply on Feb 12, 2013 4:13 PM by rhauch

    Built in node types in relation to custom node types

    piratew

      Hi guys,

       

      I'm just starting to play around with modeshape 3.1 and the jcr2.0 spec so I'm having a question. I'm using the jcr cnd eclipse plugin to create a .cnd file that holds some kind of structure that I want to use in my repository. By using this cnd file I will be able to validate the nodes being added to the repository. When I start using the jcr cnd eclipse plugin to add my own custom nodes based on built-in types in modeshape, it seems that it does not show or recognize any default built in types. The only way to resolve this is to add the definition of the built in types to my custom cnd file myself. But this seems a bit strange to me? Anyone experience with this problem?

       

      regards,

       

      Michale

        • 1. Re: Built in node types in relation to custom node types
          elvisisking

          Hi Michale,

           

          You are right when you say that adding those node types to your CND is strange and not how it should have to be done.

           

          Here's a bit of background on the editor that I think might help: The CND editor only works with, and is scoped to, a single CND file. However, when you add a built-in namespace (nt, jcr, mix, etc) to your CND, the associated node types for that built-in namespace are available to you when choosing a supertype or a child node's required type. Both of the supertype and required type text fields have a "look ahead" feature. As you type in them, the available node types for the selected namespace that match the text pattern you typed are shown and selectable. Also, when those text fields are emtpy, you can hit Ctrl-space to see all the available node types for the selected namespace.

           

          With that said, there currently is not a way to open up the built-in node type definitions in an editor or to see their complete definition in some other way. I agree it would be nice to be able to see that.

           

          Did that answer your questions?

           

          Thanks,

           

          Dan

          • 2. Re: Built in node types in relation to custom node types
            rhauch

            With that said, there currently is not a way to open up the built-in node type definitions in an editor or to see their complete definition in some other way.

            Actually, if you add a CND file for the standard built-in types to your workspace, you can just open it up with the CND editor (albeit a different instance than the editor of your file).

             

            Now, here's a bit of under-the-covers explanation about why the CND editor can't really show the node types from other files: the CND grammar doesn't have the ability to reference a file that contains the namespaces listed in the file, so it's difficult for the CND editor to "know" how to find the node types in the listed namespaces. One could argue that the built-ins should be visible. But if you're editing multiple custom CND files, you'll likely want to see in one editor some custom node types defined in another file.

             

            Hope this helps, too.

            1 of 1 people found this helpful
            • 3. Re: Built in node types in relation to custom node types
              piratew

              Hi Dan, Randall,

               

              thanks for giving me more insights on this one.

               

              "you can hit Ctrl-space"

               

              that actually helps a lot. Probably with my unfamiliarity with the built-in node types I'm very pleased with this function!

               

               

              "the CND grammar doesn't have the ability to reference a file that contains the namespaces listed in the file"

               

              ok, so suppose I have for example a book.cnd file that has properties like author, title, isbn and then I have this library.cnd file. Should I merge these two files into one in order to get a hierarchical schema or is it better (because of flexibility) to keep those two seperate and use them in my application programmatically? Is it possible to use more than one cnd file to build a tree used for validation this way?

               

              regards,

               

              Michael

              • 4. Re: Built in node types in relation to custom node types
                rhauch

                BTW, the JCR-specification does not define an official CND file, and technically all the node type definitions within the specification include '?' for "variants", which basically are aspects of the declarations that can be varied by implementations.

                 

                However, ModeShape does define our version of a CND with only the standard built-in node type definitions. It's available here and included in our "modeshape-jcr-<version>.jar" artifact as the resource file "org/modeshape/jcr/jsr_283_builtins.cnd". Feel free to copy this into your workspace and open with the CND Editor.

                 

                ok, so suppose I have for example a book.cnd file that has properties like author, title, isbn and then I have this library.cnd file. Should I merge these two files into one in order to get a hierarchical schema or is it better (because of flexibility) to keep those two seperate and use them in my application programmatically? Is it possible to use more than one cnd file to build a tree used for validation this way?

                There's no right way or wrong way to do this. But there are several factors that might influence your decision.

                 

                Simplicity

                 

                Where possible, keep things simple and use just a single CND file. You can declare node types for different namespaces in the same file (just look at a CND with the standard built-in types), so I would try to avoid creating separate files for each namespace just because the namespaces are different.

                 

                Reusability

                 

                One reason I might create multiple CND files is because one (or more) of them is can be reused in other places (e.g., a different repository or a different web app). Another is because one (or more) CND files have a different lifecycle (e.g., it's defined by a different group than are the others).

                 

                Deployment

                 

                How the JCR applications and repositories are deployed may also affect whether you want separate CND files. For example, a ModeShape repository configuration can specify a set of CND files that are to be registered immediately upon startup of the repository. But the JCR API allows applications to register new (or updated) node types, too. You may have some node types that are always to be installed upon intialization, while others might be registered only when the application needs them.

                 

                Here's an example. Consider that you have ModeShape installed into an AS7 instance, so the ModeShape repositories are configured as part of the AS7 configuration and started when they're needed/used. All an web application (or web service) needs to do is to get a hold of the (running) repository via the JNDI, @Resource injection, or RepositoryFactory techniques. And multiple applications can use the same repository, which means that some application-specific node types might better be registered by the applications, while others can/should be registered within the centralized repository configurations in AS7.

                 

                Organization

                 

                Another possibility is that you have enough node types that it's easier to keep them organized in separate files.

                • 5. Re: Built in node types in relation to custom node types
                  piratew

                  Hi Randall,

                   

                  thanks for the extensive information, appreciate it a lot!

                   

                  Two additional question about dealing with cnd files. I'm developing an application that will use modeshape and will have to support a dynamic data structure definition. It will have to support altering data structures by adding, changing and removing definitions (cnd files). On top of this, these structures should be able to append each other in order to create a large tree once data is added. So lets say I have a library.cnd that defines a structure with departments and other simple elements and that there also is a book.cnd. Both should be able to be changeable, and books.cnd should append library.cnd in order to create a structure in the repository where the library is the root node, has some children as departmentnodes and each deparmentnode has several book nodes.

                   

                  I've read in the documentation that I should use NodeTypeManager.registerNodeTypes(...) in order to add the cnd files and let the repository know which schema it should validate data with.

                   

                  How does modeshape work when it has to create this structure of multiple cnd files? Does it need some kind of reference in the book.cnd that references the library.cnd?

                   

                  What is the difference between the nodetypemanager and the cnd sequencer? Does the cnd sequencer also cause the repository to follow the schema that is the output of the cnd sequencer?

                   

                  regards,

                   

                  Michael

                  • 6. Re: Built in node types in relation to custom node types
                    rhauch

                    I'm developing an application that will use modeshape and will have to support a dynamic data structure definition. It will have to support altering data structures by adding, changing and removing definitions (cnd files).

                    Removing node types is challenging, because you can only do this when the node type is not being used anymore (including in version histories). Are you sure you want to remove node types?

                     

                     

                    On top of this, these structures should be able to append each other in order to create a large tree once data is added. So lets say I have a library.cnd that defines a structure with departments and other simple elements and that there also is a book.cnd. Both should be able to be changeable, and books.cnd should append library.cnd in order to create a structure in the repository where the library is the root node, has some children as departmentnodes and each deparmentnode has several book nodes.

                     

                    This is a very schema-restrictive approach (very much like a database). That certainly is one way to do it, but ModeShape allows you to be more "schema-less" (to varying degrees), and many people consider this to be one of the most beneficial features of JCR and ModeShape. (See our fairly recent post.)

                     

                    For example, one extreme is to use the built-in "nt:unstructured" node type (which allow any properties with any child nodes) as the primary type for all nodes. This is the fully "schema-less" approach. If you want a bit more structure, you can define mixins (usually that capture some aspect or facet of capability, like "taggable"), which can be added to any node (they can but don't need to be explicitly used in other node types). Since a property will match the most restrictive definition on the node's primary type or any of its mixin types, you can even add the mixin after you define the property on a node. You can even remove the mixin from nodes, even if the node has properties defined by the mixin because the "nt:unstructured" node type allows anything and will "catch" the properties.

                     

                    This is often a far better, more easily maintainable, more powerful, and much more flexible way of using node types. Plus it has on major advantage: content first. You can create your node structure (again, using the "nt:unstructured" or some other more suitable primary type), then figure out which mixins you want/need, and start using them. IOW, you don't have to define your schema up front like you do with a relational database!

                     

                     

                    I've read in the documentation that I should use NodeTypeManager.registerNodeTypes(...) in order to add the cnd files and let the repository know which schema it should validate data with.

                     

                    How does modeshape work when it has to create this structure of multiple cnd files? Does it need some kind of reference in the book.cnd that references the library.cnd?

                     

                    No, the CND files do not contain any references or pointers to other CND files. You simply call "registerNodeTypes(...)" for each of your CND files. Just be aware that the node types in each CND file registered will be validated against the node types in that file plus those that are already registered. Therefore, you will need to register some before others, and this might influence which files you put your node types in. (This is why I suggested putting everything in one CND file if you can.)

                     

                     

                    What is the difference between the nodetypemanager and the cnd sequencer? Does the cnd sequencer also cause the repository to follow the schema that is the output of the cnd sequencer?

                    They not related and serve very different purposes.

                     

                    The node type manager (as you mention above) is there for the programmatic discovery, registration, and removal of node types that the repository uses for validation. Think of it as a registry of the repository's node types.

                     

                    The CND sequencer is just a sequencer that will process CND files that you upload as content into a repository. Since the node types are not registered, those node type defintions in the CND files really are just content. This really only is useful if, for example, you have a "metadata" repository into which you're placing all of the CND files for your whole company, as part of a governance solution and an aid for developers of other repositories (with real content). Developers could search this "metadata" repository for node types that might fit their need, or you might have a formal process that you use to manage the CND artifacts (and other artifacts, like DDL files, WSDLs, etc.)

                     

                    I'd suggest you not worry about the CND sequencer until you are much more comfortable with most of the other features and capabilities of ModeShape.

                     

                    Hope this helps!

                    • 7. Re: Built in node types in relation to custom node types
                      piratew

                      Hi Randall,

                       

                      thanks for this explanation and answers to my questions. I appreciate it a lot and it makes things much more clear to me. As I've described in earlier posts I'm trying to have a schema that should be alterable, preferably by a user interface. Initially I thought of using CND files but these are very hard to alter programmatically. I've looked at the eclipse plugin but it doesn't seem to be that easy to implement the logic in a different app. Therefore I've started to look at the nodetypemanager in more detail. What I'm trying to accomplish is to create certain nodetypes that hold a certain structure. this structure should cope with changing nodetype definitions. I've managed to create several nodetypes but haven't been able to change it without problems and keeping the repository working.

                       

                      Could you tell me if it is possible to create a structure by using the nodetypemanager in a way that changes could be made but older versions would still be usable? so some content in the repository will adhere to version  1 of certain nodetypes, while other content adheres to version 2 of a certain nodetype?

                       

                      regards,

                       

                      Michael

                      • 8. Re: Built in node types in relation to custom node types
                        rhauch

                        Could you tell me if it is possible to create a structure by using the nodetypemanager in a way that changes could be made but older versions would still be usable? so some content in the repository will adhere to version  1 of certain nodetypes, while other content adheres to version 2 of a certain nodetype?

                         

                        Well, yes and no. Since every node type is defined in a namespace, you can design your JCR namespaces to use URIs that contain some sort of versioning part. In fact, you should really follow the XML namespace practices (e.g., often a version number or date like "http://www.w3.org/2001/XMLSchema", don't use minor versions). Then use those versioned namespaces in your node type names, property definition and child node definition names.

                         

                        However, don't go nuts with this. Don't plan on having many node types in each of hundreds of namespaces. Ideally, you can plan ahead and create flexibility in a single set of node types that has the flexibility you want for most (if not all) of your needs.

                         

                        My suggestion would be to start simple (and stay simple as long as you can).

                         

                        First and foremost, design your content first. In a prototype, create nodes that give you the organization, flexibility, and functionality that best suits your application. Only after you're (pretty) happy with the structure would you then start thinking about node types. I still very often favor using "nt:unstructured" as the primary type for most nodes (this is the default primary type, so this is what you get when you don't specify a primary node type), and define mixin node types for each pattern of properties (or "set of related properties") that you want to use, and then add these as needed to each of nodes. See how far this will take you.

                         

                        As for node types and mixins, just be sure to define them in a namespace, and think ahead about the namespace URI. As long as there's a "version" segment (date or version string), you're pretty much set to define different versions of the namespace in the future, should you need to go there.

                         

                        I'd also suggest that you do not try to overdesign your schema up front. That's necessary with relational databases (and even a few NoSQL databases), but it's usually not the best approach for ModeShape.

                        • 9. Re: Built in node types in relation to custom node types
                          piratew

                          Hi Randall,

                           

                           

                          Then use those versioned namespaces in your node type names, property definition and child node definition names.

                           

                          So just to see if I understand what you are saying, if I have one structure with library -> department -> books then I could use a namespace like prefix: "lib" uri: "http://test.nl/library/1.0" where library:library, library:department and library:books would live. Once the book is changed in a way that it also needs an extra property "cover" which is an image, I would be best off creating another namespace like prefix "lib1" uri: "http://test.nl/library/1.1"? As I'm not able to reuse the prefix it needs to be unique and related to the uri as well?

                           

                          In addition you also state that versioned nodes could not or should not be used?

                           

                           

                          I'd also suggest that you do not try to overdesign your schema up front. That's necessary with relational databases (and even a few NoSQL databases), but it's usually not the best approach for ModeShape.

                           

                          Thanks for the suggestion. That's also what I'm tryint to do but at some level I need a small structure. So I only need the structure of a library with 0..N departments where each department has 0..N books. The properties of the books, deparment, library are flexible so these will not adhere to any other scheme. I'm indeed used to relational databases so sorry for my (perhaps stupid?) questions

                           

                          regards

                           

                          Michael

                          • 10. Re: Built in node types in relation to custom node types
                            rhauch

                            michael melsen wrote:

                             

                            So just to see if I understand what you are saying, if I have one structure with library -> department -> books then I could use a namespace like prefix: "lib" uri: "http://test.nl/library/1.0" where library:library, library:department and library:books would live. Once the book is changed in a way that it also needs an extra property "cover" which is an image...

                            Is that property with an image mandatory? If not, then you can safely add it to the existing node type and all existing nodes that use it will remain valid.

                             

                            However, if that image property is mandatory, then you have a few options.

                             

                            1. Add it as an optional (e.g., not mandatory) property definition, add images to all the existing content, and then change that optional property definition to be mandatory
                            2. Add images to all the existing content (assuming your "library:book" was flexible to allow "residual" properties), then add the image property as mandatory
                            3. Do what you suggest and create another namespace with prefix like "lib1".
                            4. Don't add the image property to "library:book", but instead define it on a new mixin that represents the somewhat generic ability to "have an image" (e.g., "library:imaged" or "library:hasImage"). Then add this mixin to a nodes (whether books or other nodes) when you want to add an image for it.

                             

                            The 4th option is what I was trying to describe earlier. It doesn't require changing the "library:books" node type, and actually makes things like "having an image" be orthogonal to books so that it could be easily reused in other kinds of nodes, too. Does that make sense?

                            • 11. Re: Built in node types in relation to custom node types
                              piratew

                              Hi Randall,

                               

                              thanks for this info. I have to say that these options don't really match my hopes on how modeshape would work with different definitions and changes to these schemes. I'll explain what I'm trying to achieve.

                               

                              As said there is a structure (or scheme) that I'm trying to use in my app. This app should be able to add new schemes or alter existing schemes and cope with multiple versions of the scheme in the same repository. So imagine the more detailed definition (version 1):

                               

                              library:

                                 properties: name, alternativename, code, employees

                                 departments: [

                                                       department:

                                                            properties: depcode, name, theme

                                                            books: [

                                                                         book: title, author, image, isbn

                                                                       ]

                                                     ]

                               

                              so a library has mandatory properties, can have 1 or more departments where each department has properties and 0 or more books, and every book has certain properties. Imagine that this is version1 of the structure. Now at a particular moment there will be a different library that wants to use a different structure, say version 2:

                               

                              library:

                                 properties: name, code, boardmembers: [  person : name, gender, age ]

                                 departments: [

                                                       department:

                                                            properties: depcode, name, theme, level, size, librarians: [ person: name, employeenumber ]

                                                            books: [

                                                                         book: title, author, image, isbn, image

                                                                       ]

                               

                              so in this version 2 there is are a few new properties on the library (boardmembers), there is a change in the department properties where a librarian is introduced and there was a change in book information that we want to store. Both structures, version 1 and version 2 should be usable at the same time. So one library will use version 1 and another will use version 2.

                               

                              My app should also be able to communicate with one or more instances of my app that is located at different locations. Each location might use a different structure for its content. As the content of the repository needs to be exchanged at a certain moment between instances of my app, first the used structure should be communicated so the consuming app knows what structure it can expect (what kind of properties it should deal with). Once the structure is known, it can request all information from the first app instance by requesting the information of version 1. Another instance might only want version 2 of the content.

                               

                              So due to the fact that there are multiple instances of my app where multiple schemes should be used, I'm looking for a way of using multiple schemes in the repository at the same time. A solution might be to use one cnd file that just holds the global structure of library, departments, department, books and book and define mixins like referenceable and created. Then I could use differnt versions of  an xsd to define properties of the book, department, library  but this requires additional parsing, validating and writing of xsds apart from modeshape. So basically this isn't ideal.

                               

                              Any suggestions?

                               

                              regards,

                               

                              Michael

                              • 12. Re: Built in node types in relation to custom node types
                                rhauch

                                This is very interesting.

                                 

                                It sounds to me like you have no other choice than to have each schema define a set of node types in a namespace unique to that schema. If the schemas are specific to locations, then they aren't so much different "versions" of the same schema but rather "variations" of some common/notional/universal schema. I might even try to use a namespace that incorporates the location.  IIUC, each location's schema is independent and might evolve over time on its own, independent of how/whether other locations' schemas evolve over time.

                                 

                                If the schemas are related by some "universal" types (at least concepts, like "books", "librarian", "department", etc.) then you could define some abstract node types in a single namespace and add in any universal property definitions (and child definitions) that all schemas will share. Note that you can even have these universal property definitions and child node definitions as not mandatory. Then, the location-specific schemas could (in their own namespace) define node types that extend the "universal" schema, and optionally override some/all of the inherited property definitions and child node definitions with their own property definitions and child node definitions (perhaps overriding attributes like mandatory, types, etc., as long as they are as or more constrained than the inherited definitions).

                                 

                                Having a "universal" foundation schema allows there to be some relationship between the data from different locations. Without it, the application might still be able to relate data simply by name, but that might not hold up in all situations.

                                 

                                Let's look at your example schemas. I'll call this "location A" (rather than "version 1"):

                                 

                                 

                                library:

                                   properties: name, alternativename, code, employees

                                   departments: [

                                                         department:

                                                              properties: depcode, name, theme

                                                              books: [

                                                                           book: title, author, image, isbn

                                                                         ]

                                                       ]

                                 

                                This schema would be define in some location-specific namespace (e.g., "http://foo.com/library/locationA/v1"), and as you would expect might define property definitions and child node defintiions.

                                 

                                Here's the second schema for "Location B" defined in its own location-specific namespace (e.g., "http://foo.com/library/locationB/v1"):

                                 

                                library:

                                   properties: name, code, boardmembers: [  person : name, gender, age ]

                                   departments: [

                                                         department:

                                                              properties: depcode, name, theme, level, size, librarians: [ person: name, employeenumber ]

                                                              books: [

                                                                           book: title, author, image, isbn, image

                                                                         ]

                                 

                                Again, the node types in this schema would define their own property definitions and child node defintiions as needed.

                                 

                                Now, if there happens to be some "universal" schema that all of these location-specific schemas might share/extend, the common abstract node types could be defined in its own schema in its own namespace (e.g., "http://foo.com/library/universal/v1"). How many property definitions are defined in this "universal" schema -- and whether they are mandatory, constrained, or some other characteristic -- is entirely up to you. On the other extreme, they may be just abstract node types with no other property definitions or child node defintions. But if, for example, all books do have an ISBN, title, and author then perhaps you can define them here as mandatory. If most books have an image, you could define the image property definition that is not mandatory, and any location-specific schema that doesn't have images doesn't need to override it in its book node type, while location-specific schemas that do require an image can override it as mandatory in its book node type.

                                 

                                If I'm getting closer on the concepts and you don't understand how the node types might be defined this way, please let me know and I'll hack together some example CNDs.

                                 

                                BTW, you might still need to evolve a given location/schema over time. My earlier comments about schema evolution (using mixins, dealing with existing content not having mandatory properties, etc.) would still apply in this case.

                                 

                                WDYT?

                                • 13. Re: Built in node types in relation to custom node types
                                  piratew

                                  Hi Randall,

                                   

                                  thanks again, I appreciate it very much you are trying to help me straighten out this thing.

                                   

                                  "If the schemas are specific to locations, then they aren't so much different "versions" of the same schema but rather "variations" of some common/notional/universal schema."

                                   

                                  wel the schemas are not specific to the location in a way that the first location, say location A has one schema and location B (the second) only has a different schema. I think it is important to add the notion of a central app, one that knows all different schemas that are defined in the central app, but also knows about the schemas that decentral apps have defined. So you could look at it like the central app is the master and it can have multiple slaves. Each slave can define a new or alter an existing schema, communicate this with the central app and the central app knows exactly which schema is used by each slave. So in this light I can imagine having one universal schema that has several nodetypes which force a structure like library -> department -> book. I do like your suggestion of an additional schema on top of this universal schema.

                                   

                                  "If I'm getting closer on the concepts and you don't understand how the node types might be defined this way, please let me know and I'll hack together some example CNDs."

                                   

                                  well if you could show me in examples how this could work, that will be highly appreciated

                                   

                                  "BTW, you might still need to evolve a given location/schema over time. My earlier comments about schema evolution (using mixins, dealing with existing content not having mandatory properties, etc.) would still apply in this case."

                                   

                                  well that would still be a challenge. Although modeshape doesn't have the characteristics of the max or min length of a field or the type of characters that are allowed, the decentral apps would have to interact with legacy systems that are bound to such characteristics. I'm not quite sure how to deal with the scenario's like:

                                  a field is changed from 200 characters max length to 50

                                  a field has become obsolete in a new version

                                   

                                  regards,

                                   

                                  Michael

                                  • 14. Re: Built in node types in relation to custom node types
                                    rhauch

                                    Beware: I've taken a lot of liberties with naming conventions, which I just picked out of thin air. Obviously it would be more related to your domain. I did not take versioning into account, and I assumed just single-valued properties (where some properties like email might be multi-valued). Hopefully it helps get my points across.

                                     

                                    If the content is something like this:

                                     

                                    + site1
                                      + libCode01 jcr:primaryType='universal:library' lib:displayName="London Library"
                                        + departments jcr:primaryType='universal:departmentCollection'
                                          + fictionCode jcr:primaryType='universal:department' lib:displayName="Fiction"
                                          + childrensCode jcr:primaryType='universal:department' lib:displayName="Children's Literature"
                                            + book1 jcr:primaryType='universal:book' lib:title="Jonny's Beanstalk" lib:isbn="abcdf" lib:author="J.K.Smith" 
                                            + book2 jcr:primaryType='universal:book' lib:title="Hansen and Gretta" lib:isbn="abcde" lib:author="R.L.Grimly"
                                    + site2
                                      + libCode02 jcr:primaryType='universal:library' lib:displayName="London Library"
                                        + boardMembers jcr:primaryType='locA:boardMemberCollection'
                                          + jdoe jcr:primaryType='locA:boardMember' email='jdoe@example.com' name="Jane Doe" age="50"
                                          + ssmith jcr:primaryType='locA:boardMember' email='ssmith@example.com' name="Samuel Smith" age="62"
                                        + librarians jcr:primaryType='locA:librarianCollection'
                                          + bthomas jcr:primaryType='locA:boardMember' email='bthomas@example.com' name="Bertie Thomas" employeeId="3111"
                                          + steph jcr:primaryType='locA:boardMember' email='steph@example.com' name="Stephanie Walters" employeeId="0043"
                                        + departments jcr:primaryType='universal:departmentCollection'
                                          + fictionCode jcr:primaryType='universal:department' lib:displayName="Fiction"
                                          + childrensCode jcr:primaryType='universal:department' lib:displayName="Children's Literature"
                                            + book1 jcr:primaryType='locA:book' lib:title="Jonny's Beanstalk" lib:isbn="abcdf" lib:author="J.K.Smith" lib:pages="150"
                                            + book2 jcr:primaryType='universal:book' lib:title="Hansen and Gretta" lib:isbn="abcde" lib:author="R.L.Grimly" lib:pages="253"
                                    

                                     

                                    You can see how there are different sites that have different variations of the content. Also, I chose to use the "code" attributes in the node names (assuming they would have to be unique), and put the "names" of things in separate properties.

                                     

                                    Here's a notional "unviersal.cnd" file defining some of the core concepts you mentioned earlier, which is used in "site1" area:

                                     

                                    <universal = 'http://example.com/library/universal/1'>
                                    <lib = 'http://example.com/library/names/1'>
                                    
                                    [universal:displayable] mixin
                                              - lib:displayName (STRING) mandatory COPY
                                    
                                    [universal:library] > universal:displayable
                                              + departments (universal:departmentCollection) = universal:departmentCollection
                                    
                                    [universal:department] > universal:displayable
                                              - lib:theme (STRING) mandatory
                                              + books (universal:bookCollection) = universal:bookCollection
                                    
                                    [universal:book] 
                                              - lib:title (STRING) mandatory COPY
                                              - lib:isbn (STRING) mandatory COPY
                                              - lib:author (STRING) mandatory COPY
                                              - lib:image (BINARY) COPY
                                    
                                    [universal:departmentCollection] 
                                              + * (universal:department) = universal:department
                                    
                                    [universal:bookCollection] 
                                              + * (universal:book) = universal:book
                                    

                                     

                                    The "site2" area would be owned by the corresponding location, so it's CND might extend the universal node types:

                                     

                                    <universal = 'http://example.com/library/universal/1'>
                                    <lib = 'http://example.com/library/names/1'>
                                    <locationA = 'http://example.com/library/locationA/1'>
                                    
                                    [locationA:library] > universal:library
                                              + boardMembers (locationA:boardMemberCollection) = locationA:boardMemberCollection
                                    
                                    [locationA:department] > universal:displayable
                                              + librarians (locationA:librarianCollection) = locationA:librarianCollection
                                    
                                    [locationA:book] > universal:book
                                              - lib:pages (LONG) mandatory COPY
                                    
                                    [locationA:emailable]
                                              - email (STRING) mandatory COPY
                                    
                                    [locationA:librarian] > locationA:emailable
                                              - name (STRING) mandatory COPY
                                              - employeeId (STRING) mandatory COPY
                                    
                                    [locationA:boardMember] > locationA:emailable
                                              - name (STRING) mandatory COPY
                                              - age (STRING) mandatory COPY
                                    
                                    [locationA:librarianCollection] 
                                              + * (locationA:librarian) = locationA:librarian
                                    
                                    [locationA:boardMemberCollection] 
                                              + * (locationA:boardMember) = locationA:boardMember
                                    

                                     

                                    Here, a node of type "locationA:book" is actually also an instance of "universal:book", so all the apps would know how to deal with it (from a universal sense; the apps should be written to ignore properties they don't understand). This impacts queries:

                                     

                                         SELECT * FROM [universal:book]
                                    

                                     

                                    would return all "locationA:book" and "universal:book" nodes, whereas:

                                     

                                         SELECT * FROM [locationA:book] WHERE pages>50
                                    

                                     

                                    would only return the "location:book" nodes (with more than 50 pages).