Re: Lucene JCR Index
Hi, Sorry for my late response. I took a quick look at Compass documentation. I think one has to subclass org.compassframework.core.lucene.engine.store.AbstractLuceneSearchEngineStore if he wishes to add a custom storage mechanism. They use a connection parameter for configuration. LuceneSearchEngineStoreFactory seems to create the appropriate AbstractLuceneSearchEngineStore implementation based on the connection prefix. One could add, for example, a jcr: prefix that looks in JNDI for a repository. From there, one should be able to use Compass as with other storage mechanisms. I do not know for transactions support. I think can they retrieve JTA transaction from JNDI. I suppose the storage implementation is responsible for publishing it ? Regards, Nicolas Le 20:25 2006-01-12, vous avez écrit: Hi must be lucene-day today see also: http://www.theserverside.com/news/thread.tss?thread_id=38478 their main feature: Being able to store the Lucene indexes in a database [...] haven't had a deeper look at yours but maybe your project can align nicely with compass. I like compass because it works nicely with spring, so a JCR+Lucene+Spring stack would be good. If it doesn't fit in your strategy just ignore it as a random wild thought. kind regards Philipp Nicolas Belisle wrote: Hi, I've contributed a JCR Directory implementation for Lucene. What it does: allows the storage of indexes in a JCR repository
Re: XML schema to node types
Hi Peeter, (Sorry for the late response) Many thanks for the contribution. This is a great addition to Jackrabbit. This will ease the integration of existing formats. I haven't had time to test it yet, but will have a deep look at it in a few weeks. Regards, Nicolas Le 21:54 2006-01-09, vous avez écrit: Hi Mike, You are right about that bug. I have intermittent access to a useful computer right now (travelling) and can't commit stuff (for some mysterious reason) but I have arranged to have a patch applied by another committer which should fix tthe specific problem. As for the more general issue of dealing with the default namespace I will take a look at that when I get a chance. Of course your are free to fix stuff yourself and send patches to me or another commiter. Actually could you clarify exactly what the default namespace issue is again? I am not quite sure I see what you mean (though I am sure you are right :-) Sorry I can't be of more help at the moment, Cheers, Peet On 1/10/06, Michael Daglian [EMAIL PROTECTED] wrote: Hello Peeter, Apologies if I am misusing the schema converter code you committed but I am a bit confused as to how to make use of the NamespaceExtractor class. As demonstrated in your test-case for the SchemaConverter I am attempting to use an extractor to get the additional namespaces out a schema file. However, this does not appear possible due to the use of getURI for the mapping property: if (mapping.getURI(prefix) != null){... The NamespaceMapping class throws an exception if the prefix is unmapped and thus the empty NamespaceMapping created using the default structure always generates this exception, which only gets caught and logged. On another note, it seems unclear how to best handle the default namespace using the NamespaceMapping class. When using the reader and explicitly mapping the namespace to be (i.e NamespaceMapping.setMapping(, );), this works fine. But when outputting it writes the default namespace in a manner that the reader cannot read. Is there a recommended way of handling this case? Thanks! Best Regards, -- Mike On 12/20/05, Peeter Piegaze [EMAIL PROTECTED] wrote: Hi Nicolas, Regarding your interest in XML schema to JCR node type conversion: I have committed the XSD to JCR node type converter into contribs/nt-ns-util Cheers Peeter On 10/31/05, Nicolas Belisle [EMAIL PROTECTED] wrote: Great news ! I'm looking forward to this. Many thanks, Nick Hi Nicholas, Actually, I wrote something that does this. I haven't gotten around to completely finishing it yet, but I will take your mail as a motivator to do just that. Then I will commit to contribs. Cheers, Peeter On 10/31/05, Nicolas Belisle [EMAIL PROTECTED] wrote: Hi, I'm currently investigating ways to convert XML schemas to Jackrabbit node types declaration. This way, most metadata formats (Dublin Core, MARC21, etc.) could be integrated easily in a Jackrabbit repository. Anyone has done something in that direction and would like to its share ideas ? Any other comments on this ? I would certainly contribute the result back to Jackrabbit.Regards, Nick
Lucene JCR Index
Hi, I've contributed a JCR Directory implementation for Lucene. What it does: allows the storage of indexes in a JCR repository Why: single place for content and index storage, transaction support (if the JCR implementation support them), Performance: JCR does not support random access (only plain Inputstreams), but my implementation splits the files into fixed-size buffers to help performance. It will also depend on the persistence mechanism used with JCR. Status: beta You can retrieve the code there: http://issues.apache.org/jira/browse/LUCENE-484 I welcome your comments. Regards, Nicolas Bélisle Laval University Library
Removing a version
Hi, I'm trying to remove a version of a Node, but the VersionHistory.removeVersion() method throws : javax.jcr.ReferentialIntegrityException: Unable to remove version. At least once referenced.. Secton 8.2.2.10 (Removal of Versions) of the specification indicates that the version graph should be automatically repaired upon removal. Then, VersionHistory.removeVersion() should take care of references. In fact, a user cannot alter the references (jcr:predecessors and jcr:successors), since they are protected properties. Here's the example : Node root1 = session.getRootNode() ; Node test1 = root1.addNode(test) ; test1.addMixin(mix:versionable); test1.setProperty(test, 1); session.save(); test1.checkin(); test1.checkout(); test1.setProperty(test, 2); session.save(); test1.checkin(); test1.checkout(); test1.setProperty(test, 3); session.save(); test1.checkin(); VersionHistory vh = test1.getVersionHistory(); for (VersionIterator vi = vh.getAllVersions(); vi.hasNext(); ) { Version currenVersion = vi.nextVersion(); String versionName = currenVersion.getName(); if (!versionName.equals(jcr:rootVersion)) { String propertyValue = currenVersion.getNode(jcr:frozenNode).getProperty(test).getString(); System.out.println(Removing version : + versionName + with value: + propertyValue); vh.removeVersion(versionName); } } Something I do wrong ? Many thanks, Nicolas
Re: Removing a version
Hi, I have already verified that. The error is for removal of version name : 1.0 and the base version name is 1.2. I've updated the example to make sure it never tries to remove the base version : Node root1 = session.getRootNode() ; Node test1 = root1.addNode(test) ; test1.addMixin(mix:versionable); test1.setProperty(test, 1); session.save(); test1.checkin(); test1.checkout(); test1.setProperty(test, 2); session.save(); test1.checkin(); test1.checkout(); test1.setProperty(test, 3); session.save(); test1.checkin(); String baseVersion = test1.getBaseVersion().getName(); System.out.println(Base version name: + baseVersion); VersionHistory vh = test1.getVersionHistory(); for (VersionIterator vi = vh.getAllVersions(); vi.hasNext(); ) { Version currenVersion = vi.nextVersion(); String versionName = currenVersion.getName(); if (!versionName.equals(jcr:rootVersion) !versionName.equals(baseVersion)) { String propertyValue = currenVersion.getNode(jcr:frozenNode).getProperty(test).getString(); System.out.println(Removing version : + versionName + with value: + propertyValue); vh.removeVersion(versionName); } } Thanks, Nicolas Le 12:23 2005-11-18, vous avez écrit: Hi Nicolas, I didn't try your code but I think it throws ReferentialIntegrityException because you are trying to remove the base version which is referenced by the versioned node. see http://thread.gmane.org/gmane.comp.apache.jackrabbit.devel/3746 br, edgar On 11/18/05, Nicolas Belisle [EMAIL PROTECTED] wrote: Hi, I'm trying to remove a version of a Node, but the VersionHistory.removeVersion() method throws : javax.jcr.ReferentialIntegrityException: Unable to remove version. At least once referenced.. Secton 8.2.2.10 (Removal of Versions) of the specification indicates that the version graph should be automatically repaired upon removal. Then, VersionHistory.removeVersion() should take care of references. In fact, a user cannot alter the references (jcr:predecessors and jcr:successors), since they are protected properties. Here's the example : Node root1 = session.getRootNode() ; Node test1 = root1.addNode(test) ; test1.addMixin(mix:versionable); test1.setProperty(test, 1); session.save(); test1.checkin(); test1.checkout(); test1.setProperty(test, 2); session.save(); test1.checkin(); test1.checkout(); test1.setProperty(test, 3); session.save(); test1.checkin(); VersionHistory vh = test1.getVersionHistory(); for (VersionIterator vi = vh.getAllVersions(); vi.hasNext(); ) { Version currenVersion = vi.nextVersion(); String versionName = currenVersion.getName(); if (!versionName.equals(jcr:rootVersion)) { String propertyValue = currenVersion.getNode(jcr:frozenNode).getProperty(test).getString(); System.out.println(Removing version : + versionName + with value: + propertyValue); vh.removeVersion(versionName); } } Something I do wrong ? Many thanks, Nicolas
[jira] Created: (JCR-272) Removal of versions throws javax.jcr.ReferentialIntegrityException
Removal of versions throws javax.jcr.ReferentialIntegrityException -- Key: JCR-272 URL: http://issues.apache.org/jira/browse/JCR-272 Project: Jackrabbit Type: Bug Components: versioning Versions: 1.0 Environment: CVS build (2005-11-16) and DerbyPersistenceManager Reporter: Nicolas Belisle From the following thread : http://www.mail-archive.com/jackrabbit-dev%40incubator.apache.org/msg03483.html When trying to remove a version of a Node the VersionHistory.removeVersion() method throws : javax.jcr.ReferentialIntegrityException: Unable to remove version. At least once referenced.. Secton 8.2.2.10 (Removal of Versions) of the specification indicates that the version graph should be automatically repaired upon removal. Then, VersionHistory.removeVersion() should take care of references. (In fact, a user cannot alter the references (jcr:predecessors and jcr:successors), since they are protected properties.) Here's the example (*updated) : Node root1 = session.getRootNode() ; Node test1 = root1.addNode(test) ; test1.addMixin(mix:versionable); test1.setProperty(test, 1); session.save(); test1.checkin(); test1.checkout(); test1.setProperty(test, 2); session.save(); test1.checkin(); test1.checkout(); test1.setProperty(test, 3); session.save(); test1.checkin(); String baseVersion = test1.getBaseVersion().getName(); System.out.println(Base version name: + baseVersion); VersionHistory vh = test1.getVersionHistory(); for (VersionIterator vi = vh.getAllVersions(); vi.hasNext(); ) { Version currenVersion = vi.nextVersion(); String versionName = currenVersion.getName(); if (!versionName.equals(jcr:rootVersion) !versionName.equals(baseVersion)) { String propertyValue = currenVersion.getNode(jcr:frozenNode).getProperty(test).getString(); System.out.println(Removing version : + versionName + with value: + propertyValue); vh.removeVersion(versionName); } } Regards, Nicolas -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://issues.apache.org/jira/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira
XML schema to node types
Hi, I'm currently investigating ways to convert XML schemas to Jackrabbit node types declaration. This way, most metadata formats (Dublin Core, MARC21, etc.) could be integrated easily in a Jackrabbit repository. Anyone has done something in that direction and would like to its share ideas ? Any other comments on this ? I would certainly contribute the result back to Jackrabbit. Regards, Nick
Re: XML schema to node types
Great news ! I'm looking forward to this. Many thanks, Nick Hi Nicholas, Actually, I wrote something that does this. I haven't gotten around to completely finishing it yet, but I will take your mail as a motivator to do just that. Then I will commit to contribs. Cheers, Peeter On 10/31/05, Nicolas Belisle [EMAIL PROTECTED] wrote: Hi, I'm currently investigating ways to convert XML schemas to Jackrabbit node types declaration. This way, most metadata formats (Dublin Core, MARC21, etc.) could be integrated easily in a Jackrabbit repository. Anyone has done something in that direction and would like to its share ideas ? Any other comments on this ? I would certainly contribute the result back to Jackrabbit.Regards, Nick
Re: Problems with concurrent sessions
Hi Marcel, If all three tryLock() fail, the event is certainly active. The event is then waiting for an ACTIVE lock to be released (the last tryLock() confirms that fact). The event is not cancelled/removed until the lock is obtained. Then doInTransaction() is called. The only way I see to stop the transaction from executing is to stop the server... Am I missing something ? Regards, Nicolas Le 05:54 2005-07-19, vous avez écrit: Hi Nicolas, Looks better now, but there are still cases where the doTransaction() method will not be called, though very unlikely: when all three tryLock() attempts fail. not very likely but theoretically possible... regards marcel Nicolas Belisle wrote: Hi, Thanks again for your comments. Here's the second version of my template class. It should resolves the concurrency issues you mentionned : package app; import javax.jcr.Credentials; import javax.jcr.LoginException; import javax.jcr.Node; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.lock.LockException; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; import javax.jcr.observation.EventListener; public abstract class SerializableTemplate { private Session session; private Node scope; private boolean done = false; private EventListener el; public SerializableTemplate(Repository repository, Credentials cr, String scopePath) throws LoginException, RepositoryException { session = repository.login(cr); scope = session.getRootNode().getNode(scopePath); //scope = session.getNodeByUUID(scope.getUUID()); } public abstract void doInTransaction(Session session) throws RepositoryException; public void execute() throws RepositoryException { if (tryLock()) { return; } this.el = new EventListener() { public void onEvent(EventIterator events) { try { tryLock(); } catch (RepositoryException e) { throw new RuntimeException(e); } } }; session.getWorkspace().getObservationManager().addEventListener(el, Event.PROPERTY_REMOVED, scope.getPath(), true, null, null, false); //Try again, in case the lock is removed before observer could be put in place tryLock(); } private synchronized boolean tryLock() throws RepositoryException { try { if (done) { return false; } if (!scope.isLocked()) { scope.lock(true, true); try { if (el != null) { session.getWorkspace().getObservationManager().removeEventListener(el); } doInTransaction(session); } finally { done = true; if (session.isLive()) { session.logout(); } } return true; } } catch (LockException e) { e.printStackTrace(); } return false; } } Here's how to use it : SerializableTemplate sTemplate = new SerializableTemplate(repository, new SimpleCredentials(user, password.toCharArray()), node/path) { //@Override public void doInTransaction(Session session) throws RepositoryException { //Do your favorite transaction... }; sTemplate.execute(); For the constructor you suggested, I actually came up with a similiar design at first, but found a problem with it : since the template class might use an EventListener the class should be responsible for closing the session (the EventListener can wait a while...). Else, the event could be removed by the user before being invoked. That's the reason for my ugly constructor. I welcome your comments again... Regards, Nicolas
Re: Giving a name to the workspace ?
Hi, Please, read the following thread : http://thread.gmane.org/gmane.comp.apache.jackrabbit.devel/2660 = WorkspaceImpl.createWorkspace() Regards, Nicolas Le 09:49 2005-07-18, vous avez écrit: Hi, I would like to create a workspace in my repository with a name (soacms in this case). I saw the getName() method for the workspace, but not the setName method... So, I don't see how I have to set its name ? Thank you for your help... Jessica
Re: Problems with concurrent sessions
Hi, Thanks again for your comments. Here's the second version of my template class. It should resolves the concurrency issues you mentionned : package app; import javax.jcr.Credentials; import javax.jcr.LoginException; import javax.jcr.Node; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.lock.LockException; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; import javax.jcr.observation.EventListener; public abstract class SerializableTemplate { private Session session; private Node scope; private boolean done = false; private EventListener el; public SerializableTemplate(Repository repository, Credentials cr, String scopePath) throws LoginException, RepositoryException { session = repository.login(cr); scope = session.getRootNode().getNode(scopePath); //scope = session.getNodeByUUID(scope.getUUID()); } public abstract void doInTransaction(Session session) throws RepositoryException; public void execute() throws RepositoryException { if (tryLock()) { return; } this.el = new EventListener() { public void onEvent(EventIterator events) { try { tryLock(); } catch (RepositoryException e) { throw new RuntimeException(e); } } }; session.getWorkspace().getObservationManager().addEventListener(el, Event.PROPERTY_REMOVED, scope.getPath(), true, null, null, false); //Try again, in case the lock is removed before observer could be put in place tryLock(); } private synchronized boolean tryLock() throws RepositoryException { try { if (done) { return false; } if (!scope.isLocked()) { scope.lock(true, true); try { if (el != null) { session.getWorkspace().getObservationManager().removeEventListener(el); } doInTransaction(session); } finally { done = true; if (session.isLive()) { session.logout(); } } return true; } } catch (LockException e) { e.printStackTrace(); } return false; } } Here's how to use it : SerializableTemplate sTemplate = new SerializableTemplate(repository, new SimpleCredentials(user, password.toCharArray()), node/path) { //@Override public void doInTransaction(Session session) throws RepositoryException { //Do your favorite transaction... }; sTemplate.execute(); For the constructor you suggested, I actually came up with a similiar design at first, but found a problem with it : since the template class might use an EventListener the class should be responsible for closing the session (the EventListener can wait a while...). Else, the event could be removed by the user before being invoked. That's the reason for my ugly constructor. I welcome your comments again... Regards, Nicolas Le 05:07 2005-07-15, vous avez écrit: Hi Nicolas, I can see where you are heading for ;) I think the constructor take the node that acts as the lock scope. It should provide all that is needed: public SerializableTemplate(Node scope) { session = scope.getSession(); this.scope = scope; } you may then also ommit the session parameter in doInTransaction. And just as a minor improvement the method should be allowed to throw a RepositoryException. After checking whether a node is locked it is not guaranteed that you can then lock the node. A similar concurrency problem can arise when isLocked() returns true, between that call and the listener registration the node might get unlocked. so, you don't get an event for that and keep waiting. regards marcel Nicolas Belisle wrote: I just thought about something like this (Note that I've only done a few tests on that class.) : public abstract class SerializableTemplate { private Session session; private Node scope; public SerializableTemplate(Repository repository, Credentials cr, String scopePath) throws LoginException, RepositoryException { session = repository.login(cr); scope = session.getRootNode().getNode(scopePath); } public abstract void doInTransaction(Session session); public void execute() { try { if (!scope.isLocked()) { scope.lock(true, true); doInTransaction(session); if (session.isLive()) { session.logout(); } } else { EventListener el = new EventListener() { public void onEvent
Re: Problems with concurrent sessions
Hi again, You probably want a lock call that is blocking and returns when the lock could be retrieved. Locks in jsr-170 were primarily designed to lock nodes for a longer time and not just while in a transaction. Maybe a blocking variant of the getLock() method is something we should consider for the next jcr version. I just thought about something like this (Note that I've only done a few tests on that class.) : import javax.jcr.Credentials; import javax.jcr.LoginException; import javax.jcr.Node; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; import javax.jcr.observation.EventListener; public abstract class SerializableTemplate { private Session session; private Node scope; public SerializableTemplate(Repository repository, Credentials cr, String scopePath) throws LoginException, RepositoryException { session = repository.login(cr); scope = session.getRootNode().getNode(scopePath); } public abstract void doInTransaction(Session session); public void execute() { try { if (!scope.isLocked()) { scope.lock(true, true); doInTransaction(session); if (session.isLive()) { session.logout(); } } else { EventListener el = new EventListener() { public void onEvent(EventIterator events) { try { if (!scope.isLocked()) { scope.lock(true, true); doInTransaction(session); if (session.isLive()) { session.logout(); } } } catch (Exception e) { throw new RuntimeException(e); } } }; session.getWorkspace().getObservationManager().addEventListener(el, Event.PROPERTY_REMOVED, scope.getPath(), true, null, null, false); } } catch (Exception e) { throw new RuntimeException(e); } } } I don't like a few things about that class, especially the constructor... What do you think overall ? Again I think this always depends on the application on top of the repository. Setting an isolation level as a global property does not seems to be a good idea to me. Well, if many applications need control of their isolation level, maybe that feature should be implemented in one place or documented in a worked example... Regards, Nicolas Le 12:34 2005-07-08, vous avez écrit: Hi Nicolas, Nicolas Belisle wrote: no, but you may use locks to further control isolation level. There seems to be at least two problems with that approach : - You will get a (unpleasant) javax.jcr.lock.LockException if another transaction tries to lock the node (or a child). You probably want a lock call that is blocking and returns when the lock could be retrieved. Locks in jsr-170 were primarily designed to lock nodes for a longer time and not just while in a transaction. Maybe a blocking variant of the getLock() method is something we should consider for the next jcr version. - It is not enforced even though it should be used everywhere, even for only a read. This depends on the application. I don't think you have to lock the workspace when your applicaton is fine with an read-committed isolation level. Sorry there was an error in my example. I should make more sense this way : Example v.2 : A : open session A : read nodes test test2 B : open session B : delete nodes test test2 B : save session //WHAT SHOULD HAPPEN ?? B : logout A : read nodes test test2 //WHAT SHOULD HAPPEN ?? A : logout yeah, that definitively makes more sense ;) deleting the two nodes with Session B will be successful, unless session A has locked the two nodes. regarding the second attempt to read the two nodes with session A, this depends whether A already obtained references to the nodes or not. If A already has reference to those two nodes, calles that read the state of those nodes will throw an InvalidItemStateException. Indicating that the nodes do not exist anymore. If A tries to retrieve the nodes again. E.g. by calling getNodes() on the parent of the just deleted nodes. The returned NodeIterator will simply not contain the nodes anymore. It would be useful if the isolation level could configured at the repository level. So if your application needs better isolation or performance you would only need to change the configuration and not your code. Again I think this always depends on the application on top of the repository. Setting an isolation level as a global property does not seems
Re: Problems with concurrent sessions
Hi, Many thanks for your response. no, but you may use locks to further control isolation level. There seems to be at least two problems with that approach : - You will get a (unpleasant) javax.jcr.lock.LockException if another transaction tries to lock the node (or a child). - It is not enforced even though it should be used everywhere, even for only a read. I cannot quite follow you here. thread B seems to save a session without having made changes to it? that means 'B : save session' is basically no op. But I guess that's not what you want to know... Sorry there was an error in my example. I should make more sense this way : Example v.2 : A : open session A : read nodes test test2 B : open session B : delete nodes test test2 B : save session //WHAT SHOULD HAPPEN ?? B : logout A : read nodes test test2 //WHAT SHOULD HAPPEN ?? A : logout It would be useful if the isolation level could configured at the repository level. So if your application needs better isolation or performance you would only need to change the configuration and not your code. An implementation could (hypothetically) use locks in SessionImpl and use events (when a session saves/logout) to prevent throwing exceptions. A queue would hold pending operations. However, we would have to be careful about long lived sessions... What do you think ? Regards, Nicolas Le 04:06 2005-07-08, vous avez écrit: Hi Nicolas, Nicolas Belisle wrote: What is the session isolation level [ref. http://www.unix.org.ua/orelly/java-ent/ebeans/ch08_03.htm] by default ? the default is read commited. Is it configurable ? no, but you may use locks to further control isolation level. a session in jackrabbit will see changes as soon as they are committed. you may however use locks to achieve a higher isolation level. successfully setting a lock on a node will give you repeatable read for that subtree. if you do that on the root node you get serializable isolation level. At least, Jackrabbit seems to prevent dirty reads (determined from tests). Is there any documentation regarding isolation level ? I think it is a very important topic... Unfortunately there is currently no documentation on isolation levels, but this thread may be a good starting point to collect all relevant information and then put it into a nice xdoc or wiki page. Example : A : open session A : read nodes test test2 B : open session A : delete nodes test test2 B : save session //WHAT SHOULD HAPPEN ?? B : logout A : read nodes test test2 //WHAT SHOULD HAPPEN ?? A : logout I cannot quite follow you here. thread B seems to save a session without having made changes to it? that means 'B : save session' is basically no op. But I guess that's not what you want to know... regards marcel
Problems with concurrent sessions
Hi, I'm a Jackrabbit newbie. I'm doing some tests with the tool and I'm having problem with concurrent sessions. I have joined my (simple) test class (JCRTest) and the exception I get from running it. Anyone had similar problems ? Regards, Nicolas --The exception report: java.util.NoSuchElementException: cdeab285-fdbc-4af3-918a-bf4316a29276 at org.apache.jackrabbit.core.LazyItemIterator.next(LazyItemIterator.java:157) at org.apache.jackrabbit.core.LazyItemIterator.nextNode(LazyItemIterator.java:98) at app.JCRTest$ThreadDeleter.run(JCRTest.java:107) --The class: package app; import java.util.Hashtable; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.SimpleCredentials; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; import javax.jcr.observation.EventListener; import javax.naming.Context; import javax.naming.InitialContext; import org.apache.jackrabbit.core.jndi.RegistryHelper; import org.apache.jackrabbit.core.value.StringValue; public class JCRTest { private Repository repository; public JCRTest(Repository repository) { this.repository = repository; } public void execute() throws Exception { Session session = this.repository.login(new SimpleCredentials(, .toCharArray()), null); Node rn = session.getRootNode(); new ThreadObserver().start(); Node n = rn.addNode(node + System.currentTimeMillis(), nt:unstructured); n.setProperty(testprop, new StringValue(Hello, World.)); new ThreadDeleter().start(); session.save(); session.logout(); } public static void main(String[] args) { try { String configFile = repository/repository.xml; String repHomeDir = repository; Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory); env.put(Context.PROVIDER_URL, localhost); InitialContext ctx = new InitialContext(env); RegistryHelper.registerRepository(ctx, repo, configFile, repHomeDir, true); Repository r = (Repository) ctx.lookup(repo); for (int i = 0; i 20; i++) { JCRTest test = new JCRTest(r); test.execute(); } } catch (Exception e){ e.printStackTrace(); } } public class ThreadObserver extends Thread { public void run() { System.out.println(Observing thread started); try { Session session = repository.login(new SimpleCredentials(, .toCharArray())); EventListener el = new EventListener() { public void onEvent(EventIterator events) { while (events.hasNext()) { try { Thread.sleep(100); } catch (InterruptedException e) {} Event e = events.nextEvent(); if (e.getType() == Event.NODE_ADDED) { try { System.out.println(Node added : + e.getPath()); } catch (RepositoryException re) { re.printStackTrace(); } } } } }; session.getWorkspace().getObservationManager().addEventListener(el, Event.NODE_ADDED, /, true, null, null, false); session.save(); //Some time to listen Thread.sleep(500); session.logout(); } catch (Exception e) { e.printStackTrace(); } } } public class ThreadDeleter extends Thread { public void run() {
Re: How do I create more workspaces
Hi Richard, I would suggest WorkspaceImpl#createWorkspace(), since this method is public rather than protected (SessionImpl#createWorkspace()). Hope it helps, Nicolas Le 13:53 2005-07-06, vous avez écrit: Apologies if this is a really dumb question but how can I create multiple workspaces with jackrabbit? Passing a named workspace into the login returns a javax.jcr.NoSuchWorkspaceException, but will create a new default workspace if it dosnt already exist and trawling over the API hasn't helped. The repository.xml file seems to define a workspace template rather than a list of workspaces (at least that's how I read it). Ah, as I'm typing I can see createWorkspace() on SessionImpl -- I guess I'm supposed to cast an active session object to the jackrabbit SessionImpl and call that? - Richard
Re: Problems with concurrent sessions
Hi Oliver, Thanks for your response. Thereforeall your threads have to have their own session My code doesn't share any session between threads. Only the repository is shared. [...] or you have to synchronize session access to avoid the exception you get (which is similar to ConcurrentModificationException thrown by standard SDK collections/iterators). Then a solution (as you suggest) would like something like this : synchronized( repository ) { Session session = this.repository.login(new SimpleCredentials(, .toCharArray()), null); //Do something session.save(); session.logout(); } What is the preferred approach ? Also, if I'm responsible for preventing concurrrent sessions, then why is there those multithreading issues in JIRA : http://issues.apache.org/jira/browse/JCR-18 http://issues.apache.org/jira/browse/JCR-155 ? Regards, Nicolas Le 18:37 2005-07-06, vous avez écrit: Nicolas, the JCR spec does not require a session to be thread-safe so you are on your own to take care for problems like the one you describe. Therefore all your threads have to have their own session or you have to synchronize session access to avoid the exception you get (which is similar to ConcurrentModificationException thrown by standard SDK collections/iterators). Oliver Nicolas Belisle wrote: Hi, I'm a Jackrabbit newbie. I'm doing some tests with the tool and I'm having problem with concurrent sessions. I have joined my (simple) test class (JCRTest) and the exception I get from running it. Anyone had similar problems ? Regards, Nicolas --The exception report: java.util.NoSuchElementException: cdeab285-fdbc-4af3-918a-bf4316a29276 at org.apache.jackrabbit.core.LazyItemIterator.next(LazyItemIterator.java:157) at org.apache.jackrabbit.core.LazyItemIterator.nextNode(LazyItemIterator.java:98) at app.JCRTest$ThreadDeleter.run(JCRTest.java:107) --The class: package app; import java.util.Hashtable; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.SimpleCredentials; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; import javax.jcr.observation.EventListener; import javax.naming.Context; import javax.naming.InitialContext; import org.apache.jackrabbit.core.jndi.RegistryHelper; import org.apache.jackrabbit.core.value.StringValue; public class JCRTest { private Repository repository; public JCRTest(Repository repository) { this.repository = repository; } public void execute() throws Exception { Session session = this.repository.login(new SimpleCredentials(, .toCharArray()), null); Node rn = session.getRootNode(); new ThreadObserver().start(); Node n = rn.addNode(node + System.currentTimeMillis(), nt:unstructured); n.setProperty(testprop, new StringValue(Hello, World.)); new ThreadDeleter().start(); session.save(); session.logout(); } public static void main(String[] args) { try { String configFile = repository/repository.xml; String repHomeDir = repository; Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory); env.put(Context.PROVIDER_URL, localhost); InitialContext ctx = new InitialContext(env); RegistryHelper.registerRepository(ctx, repo, configFile, repHomeDir, true); Repository r = (Repository) ctx.lookup(repo); for (int i = 0; i 20; i++) { JCRTest test = new JCRTest(r); test.execute(); } } catch (Exception e){ e.printStackTrace(); } } public class ThreadObserver extends Thread { public void run() { System.out.println(Observing thread started); try { Session session = repository.login(new SimpleCredentials(, .toCharArray())); EventListener el = new EventListener() { public void onEvent(EventIterator events) { while (events.hasNext()) { try { Thread.sleep(100); } catch (InterruptedException e