In your CND-file, you need to declare all the namespaces you'll use, even the ones that come with Jackrabbit:
============================== /* orig.namespaces */ <mix = 'http://www.jcp.org/jcr/mix/1.0'> <nt = 'http://www.jcp.org/jcr/nt/1.0'> /* my stuff */ <my = 'http://www.example.com/jcr-ns/my'> <page = 'http://www.example.com/jcr-ns/page'> [my:page] > nt:unstructured, mix:referenceable orderable - my:active (boolean) = 'true' mandatory autocreated ======================= etc... On 4/2/07, Nandana Mihindukulasooriya <[EMAIL PROTECTED]> wrote:
Hi, I changed the Node structure as following according to the discussion and tried to register them in the repository. Here are some of the problems I came across. Grammer for CND notation defines a property of a Node type as property_def ::= "-" property_name [property_type_decl] [default_values] [attributes] [value_constraints] property_name ::= string Does all properties have to have a namespace prefix ? When I tried to register the node types using the CompactNodeTypeDefReader it gave an error caused by "UnknownPrefixException". It also said that if I define the autocreated attribute for a childnode I should define the default type for them which is of cource reasonable. Like Node class's hasNode() method is there convinient methods to check whether a namespace prefix is already registered ? and to check whether a Node Type is already registed ? I didn't find such methods in NodeTypeManager or NamespaceRegistry Interfaces of JCR. I used the NodeTypeManagerImpl which inplements the JackrabbitNodeTypeManager Interface. But in the mailing list // only register the type if it does not yet exist if (!manager.hasNodeType("myfile")) is used to check this. Is that method not available in Jackrabbit 1.0 ? To create a the repository I used the TransientRepository class which created me a default repository configuration file. But if I am using JNDI binding do I have to create a repository.xml by my self ? Is there a way to specify to create a default configuration ? Where can I find contrib/compact-nt tools ? I really appreciate your comments. Thank you in advance. BR, Nandana ----------------------------------------------------- Node Structure ------------------------------------------------------- /blogRoot [nt:folder] /blogRoot/user [blog:user] /blogRoot/user/blogSpace [nt:folder] /blogRoot/user/blogSpace/<yyyy> [nt:folder] /blogRoot/user/blogSpace/<yyyy>/<mm> [nt:folder] /blogRoot/user/blogSpace/<yyyy>/<mm>/blogEntry [blog:blogEntry] /blogRoot/user/blogSpace/<yyyy>/<mm>/blogEntry/comment [blog:Comment] /blogRoot/user/library [nt:folder] /blogRoot/user/libray/avatar [nt:file] /<libray> [nt:folder] ------------------------------------------- CND Notation for custom types ------------------------------------- <blog = 'http://jackrabbit.apache.org/jackrabbit-jcr-demo/1.0'> <nt = ... > <jcr = ... > [blog:user] > mix:referenceable - blog:nickname (string) mandatory - blog:email (string) mandatory - blog:password (string) mandatory + blog:library (nt:folder) =nt:folder mandatory autocreated + blog:blogSpace (nt:folder) =nt:folder mandatory autocreated [blog:blogEntry] > nt:hierarchyNode, mix:referenceable - blog:title (string) mandarory primary - blog:content (string) mandatory - blog:rate (long) + blog:attachments (nt:folder) =nt:folder mandatory autocreated [blog:comment] - blog:content (string) mandatory primary - blog:commenter (reference ) mandatory < blog:user ----------------------------------------------------------- Stack trace ----------------------------------------------------- org.apache.jackrabbit.core.nodetype.compact.ParseException: Error while parsing 'nickname' at org.apache.jackrabbit.core.nodetype.compact.Lexer.fail(Lexer.java :146) at org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader.toQName (CompactNodeTypeDefReader.java:635) at org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader.doPropertyDefinition (CompactNodeTypeDefReader.java:373) at org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader.doItemDefs (CompactNodeTypeDefReader.java:331) at org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader.parse ( CompactNodeTypeDefReader.java:208) at org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader .<init>(CompactNodeTypeDefReader.java:165) at org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader .<init>(CompactNodeTypeDefReader.java:150) at nandana.jackrabbit.example1.NodeStructure.RegisterCustomNodeTypes( NodeStructure.java:94) at nandana.jackrabbit.example1.NodeStructure.main(NodeStructure.java :58) Caused by: org.apache.jackrabbit.name.UnknownPrefixException: at org.apache.jackrabbit.name.QName.fromJCRName(QName.java:596) at org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader.toQName (CompactNodeTypeDefReader.java:630) ... 7 more Exception in thread "main" java.lang.NullPointerException at nandana.jackrabbit.example1.NodeStructure.RegisterCustomNodeTypes( NodeStructure.java:101) at nandana.jackrabbit.example1.NodeStructure.main(NodeStructure.java :58) On 3/28/07, Jukka Zitting <[EMAIL PROTECTED]> wrote: > > Hi, > > On 3/29/07, Nandana Mihindukulasooriya <[EMAIL PROTECTED]> wrote: > > I should thank Brian, Xin and Jukka a lot for their valuable feedbacks > > and I was able to understand lot of things when I went through the > > JSR-170 again after reading the feedbacks. > > Excellent, thanks again for your efforts. Comments below... > > > Now we will create users using their unique user IDs like > > > > Node root = session.getRootNode(); > > Node user = root.addNode("uniqueUserID","blog:user"); > > > > To avoid uniqueUserID conflit with other root's child nodes ( which are > not > > user nodes), can we use a namespace prefix as "id:uniqueID" with <id = > > http://... >. > > Namespaces are a good way to avoid naming conflicts, but in this case > an even better way would be to create your own "application root node" > like /blog:root like the one you propose below. Such a root node > nicely separates the blog content from any other application you may > want to store in the same workspace. It also makes it easy to limit > searches to just that subtree instead of including for example the > whole /jcr:system tree. > > Also, I would encourage you to use a username or even the real name of > the user as the node name instead of a numeric or some other abstract > identifier. > > Thus the code would be: > > Node root = session.getRootNode().getNode("blog:root"); > Node user = root.addNode(username,"blog:user"); > > > can we add something like this to root node to avoid non-unique userIDs > ? > > > > ChildNodeDefinition > > Name * > > RequiredPrimaryTypes UNDEFINED > > ... > > SameNameSiblings false > > The root node definition in Jackrabbit is essentially equivalent to > nt:unstructured, so you can already add whatever child nodes you want > to it without modifying the type definition. > > > If we can, how can we define it ? and is ItemExistsException throwed > > immediately or on save in jackrabbit implementation of jcr ? > > If we can't is there any other way to prevent it ? > > Node types can be registered using the CND or XML node type definition > formats and the JackrabbitNodeTypeManager extension interface found in > the jackrabbit-api component. > > Generally you shouldn't rely on an JCR implementation to perform > consistency checks before the save() call. There are even many full > consistency checks that can logically not be performed before the > save() call. > > > or can I make a one root note child like this and define it not to have > > sameNameSiblings. > > > > [blog:blog] > > - * [blog:user] > > - library [nt:folder] mandatory autocreated > > Such an approach would be my preferred alternative. You can't easily > constraint the repository root node not to have children with same > names, but you can quite easily enforce that in your application. > > As to the blog:blog node type, again I would prefer the standard > nt:folder type. I'd also place the image library under a separate > "content root" since it could very well be used by other applications > as well. The content tree would look something like this: > > /blog:blog [nt:folder] > /blog:blog/... > /blog:library [nt:folder] > /blog:library/... > > You can initialize your application like this (assuming you've already > set up the namespaces): > > Session session = ...; > Node root = session.getRootNode(); > if (!root.hasNode("blog:blog")) { > root.addNode("blog:blog", "nt:folder"); > } > if (!root.hasNode("blog:library")) { > root.addNode("blog:library", "nt:folder"); > } > session.save(); > > > As blogspace is of type nt:folder which has a child node definition, > > > > ChildNodeDefinition > > Name * > > RequiredPrimaryType[nt:hierarchyNode] > > > > it can in turn have children of type nt:folder as nt:folder is > a subtype of > > nt:hierarchyNode. So both <yyyy> and <mm> would be nodes of type > nt:folder. > > Exactly. > > > So we can use, > > > > Node blogSpace = user.getNode("blogSpace"); > > Node year = blogspace.addNode("2007","nt:folder"); > > Node month = year.addNode("03","nt:folder"); > > > > Is there a way to create a node with intermediate created automatically > ? > > If there is a way, how can we declare the types of intermediate nodes ? > > Javadoc says it throws a PathNotFoundException if we try to create a > > node without creating intermediate nodes. > > There's no such way, you need to handle that in your application. > > Node blogSpace = ...; > if (!blogSpace.hasNode("year")) { > blogSpace.addNode("year", "nt:folder"); > blogSpace.save(); > } > Node year = blogSpace.getNode("year"); > if (!year.hasNode("month")) { > year.addNode("month", "nt:folder"); > year.save(); > } > Node month = year.getNode("month"); > > Note that the above code has a slight chance of race conditions if two > sessions attempt to create the same intermediate nodes at the same > time. You can either proactively prevent it by making the blogSpace > node lockable and using JCR locks, or you can catch the concurrent > modification exception and recover by retrying the operation. Since > the chance of collisions is so small, I would go with the latter > option. > > > So we have to come with a way to name the blog entries. Title may not be > a > > good candidate because they may white spacses and '.', '/', ':', '[', > ']', '*', > > ''', '"' charactors. Would a simple sequential numbering work ? Is there > a better > > way to handle this ? > > Generally a somewhat meaningful name is preferred over a sequence > number. It makes administration much easier and also gives a nice > URL-to-path mapping for web applications. I would go for a solution > that either allows the user to specify the node name or uses a > "simplifies" title as the node name. Many existing blog applications > (for example WordPress) already use a "simplification" algorithm that > turns title strings into valid URL path components. A similar solution > would be perfect here as well. > > You would still store the full title as a normal string property to > avoid losing data. > > > Node blogEntry = month.addNode("01","blog:blogEntry"); > > blogEntry.setProperty("content","my first blog entry"); > > > > As blogEntry is a subtype of nt:hierarchyNode, I would be able to use > > jcr:created property to get the created date of the blog. > > Exactly. > > > To add an image attachment, > > > > Node attachments = blogEntry.getNode("attachments"); > > Node linkedFile = attachments.addNode("attachment01","nt:linkedFile"); > > linkedFile.setProperty("jcr:content",root.getNode("library/xxx/yyy")); > > > > jcr:content property of the nt:linkedFile type is of type reference. > > Perfect. Note that the jcr:content reference of an nt:linkedFile node > should probably point to the jcr:content resource node of another file > instead of the file node itself. > > > To add a Comment > > > > Node comment = blogEntry.addNode("01","blog:comment"); > > comment.setProperty("content","my first comment"); > > comment.setProperty("commenter", root.getNode("commenterID")); > > Exactly. > > > To add a avator to a user, > > > > Node library = root.getNode("library"); > > Node manAvatar = library.addNode("manAvator","blog:avatar"); > > Node content = manAvatar.getNode("jcr:content"); > > content.setProperty("image",imageInputStream); > > > > user.setProperty("avatar",manAvator); > > I think you'd be better of again using the standard nt:hierarchyNode > model here instead of custom types. I would define a "personal > library" folder for each user and place the avatar image there as > either a local nt:file or as a nt:linkedFile that refers to some image > in the global image library. A reserved name would be used for the > avatar image, but other files could also be stored in this personal > library folder. Using the standard node types allows you for example > to use the existing WebDAV servlet classes from jackrabbit-jcr-server > to serve the content in a web application. As an extra bonus you'd > even get PUT support for free for remote clients to update the > content! > > [blog:user] > .... > + library (nt:folder) mandatory autocreated > > Adding a custom avatar would be: > > Node user = ...; > Node library = user.getNode("library"); > Node avatar = library.addNode("avatar", "nt:file"); > avatar.addNode("jcr:content", "nt:resource"); > avatar.setProperty("jcr:content/jcr:mimeType", "image/gif"); > avatar.setProperty("jcr:content/jcr:lastModified", > Calendar.getInstance()); > avatar.setProperty("jcr:content/jcr:data", ...); > library.save(); > > Adding a standard avatar from the global image library would be: > > Node standardAvatar = ...; > Node user = ...; > Node library = user.getNode("library"); > Node avatar = library.addNode("avatar", "nt:linkedFile"); > avatar.setProperty("jcr:content", standardAvatar.getNode > ("jcr:content")); > library.save(); > > > jcr:content is of type nt:base and how can we define that it has a > property > > "image" which contains Binary data. Or shall I directly add "image" > property > > to blog:avator type like > > > > [blog:avatar] > nt:file,mix:referenceable > > - image (binary) mandatory primary > > No. You should instead use the standard nt:resource type as the > jcr:content node of a file and store the image data as > jcr:content/jcr:data as shown above. > > If you want to, you can extend the nt:resource type to contain > image-specific information like size and possible thumbnails: > > [blog:image] > nt:resource > - width (long) > - height (long) > + thumbnails (nt:folder) > > BR, > > Jukka Zitting >