In your CND-file, you need to declare all the namespaces you'll use, even the ones that come with Jackrabbit: ============================== /* orig.namespaces */ /* my stuff */ [my:page] > nt:unstructured, mix:referenceable orderable - my:active (boolean) = 'true' mandatory autocreated ======================= etc... On 4/2/07, Nandana Mihindukulasooriya 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/ [nt:folder] > /blogRoot/user/blogSpace// [nt:folder] > /blogRoot/user/blogSpace///blogEntry [blog:blogEntry] > /blogRoot/user/blogSpace///blogEntry/comment [blog:Comment] > /blogRoot/user/library [nt:folder] > /blogRoot/user/libray/avatar [nt:file] > / [nt:folder] > > ------------------------------------------- CND Notation for custom > types ------------------------------------- > > > > > > > > [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 > .(CompactNodeTypeDefReader.java:165) > at > org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader > .(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 wrote: > > > > Hi, > > > > On 3/29/07, Nandana Mihindukulasooriya 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 > > 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 and 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 > > >