Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "JCR Management"

(The API)
(A tour through JCRM)
 
(39 intermediate revisions by 2 users not shown)
Line 1: Line 1:
= JCR Mangement (JCRM) =
+
= JCR Management (JCRM) =
 
JCR Management will provide tooling and a JCR (http://en.wikipedia.org/wiki/Content_repository_API_for_Java) persistence framework for EMF with pluggable JCR implementations.
 
JCR Management will provide tooling and a JCR (http://en.wikipedia.org/wiki/Content_repository_API_for_Java) persistence framework for EMF with pluggable JCR implementations.
  
Line 35: Line 35:
 
There is a seperate page that explains how to [[map EMF type elements]] to JCR node type elements.
 
There is a seperate page that explains how to [[map EMF type elements]] to JCR node type elements.
  
 +
== Tasks ==
 +
# See Bugzilla for an overview of the ToDo's https://bugs.eclipse.org/bugs/buglist.cgi?short_desc_type=allwordssubstr&short_desc=&product=EMFT&component=JCR+Management&long_desc_type=allwordssubstr&long_desc=&order=Importance
  
== The Tooling ==
 
  
=== EMF Class Editor ===
+
== Next Milestone ==
The class editor is based on the EMF Ecore model. This model is generated from the node types in the repository.
+
Create a first downloadable presentation of the project.
  
[[Image:ClassEditor.png]]
+
== Ideas ==
=== Jackrabbit XML Nodetype Editor ===
+
* Using Cedrics Compare editor inside the JCR Manager
This editor saves the content in the XML format that can be used for Jackrabbit node type registration. It completely supports drag 'n drop, copy & paste and undo/redo. The editor is basically the sample model editor of EMF enhanced with the JCRM type mapping semantics. You can use it to create a new XML file for the node type registration in Jackrabbit and you can also read the node types from the repository save it and manipulate it with this editor.
+
:http://www.eclipse.org/modeling/emft/?project=compare#compare
  
 +
== FAQ ==
 +
# What's the relationship between JCR Management and Jackrabbit JCR-OCM?
 +
One part of JCR Management has the same goal as JCR-OCM - exposing node data and operations to domain models - but JCRM uses an MDSD approach based on Eclipse Modeling Framework (EMF). This makes it depending less on reflection and using more generated classes instead. It will delegate as many calls on JCR node data as possible to minimize copying node data to domain model objects. Additionally JCR Management also has many other goals. But find out the details of JCR-OCM and check out the  [http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-ocm/ source code] and the [http://jackrabbit.apache.org/object-content-mapping.html documentation].
 +
 +
== A tour through JCRM ==
 +
 +
[[Category:Modeling]]
 +
[[Category:EMFT]]
 +
 +
=== Installation ===
 +
* Jackrabbit:
 +
JCRM currently expects Jackrabbit version 1.4 remotely at "//localhost:1099/jackrabbit.repository". Please make sure it's available there.
 +
* Eclipse:
 +
JCRM is tested with the Eclipse Gallileo modeling package
 +
* JCRM:
 +
** Create a new CVS repository location with the following configuration:
 +
    Server: dev.eclipse.org
 +
    Repository Path: /cvsroot/modeling
 +
    User: anonymous
 +
    Password: (leave blank)
 +
    Connection Type: pserver
 +
** Navigate to the branch 'org_eclipse_emf_jcrm-tour-0_8_3'
 +
** Check out all modules org.eclipse.emf.jcrm.* as plugins
 +
** In the "org.eclipse.emf.jcrm.conversion" plugin in the source folder you find the general build.xml file. It is used to build all projects.
 +
# Right-Click it and choose "Run As/Ant Build..."
 +
# In the "JRE" tab choose "Run in the same JRE as the workspace"
 +
# Press "Run"
 +
** There are three projects that don't get generated successfully with the Ant task. Unfortunately you have to generate these projects manually until I found a solution to that. These projects are:
 +
# org.eclipse.emf.jcrm.repoconn.simplecredentials
 +
# org.eclipse.emf.jcrm.repoconn and
 +
# org.eclipse.emf.jcrm.ntmodel
 +
Please go into their "model" folder, open the *.genmodel file, right-click at the root element and choose "Generate All"
 +
** If there are no errors anymore you successfully checked out JCRM.
 +
 +
=== Running JCRM ===
 +
# In the main menu choose "Run/Run Configurations"
 +
# Create a new Run Configuration for "Eclipse Application"
 +
# Give it a name like "Start JCRM" if you want
 +
# In the "Arguments" tab make sure there is "-Xmx512m" in the "VM arguments" field
 +
# Press "Run" to start a new Eclipse instance
 +
# You can also start your Jackrabbit server now
 +
 +
This puts all plugin projects that have been checked out (and maybe modified) into the new Eclipse instance.
 +
 +
=== Creating a demo domain model ===
 +
# In the new Eclipse instance create a new JCR Management project using the "New Project..." wizard. You can give it a name like "Demo" if you want.
 +
# Paste the [[example library EMF model]] as library.ecore into the generated "model" folder. I tested JCRM basically with this model but the current features should also work with other models.
 +
 +
=== Registering the domain model and create the tooling ===
 +
Now the fun part starts as the tooling can be generated.
 +
# Right-Click at "workflow/registerModelToRepository.oaw" choose "Run As/oAW Workflow" to register your Ecore model to the Jackrabbit repository.
 +
## "src-gen/library.jrxmlnt" is the xml file that has been used to register the domain model as Jackrabbit XML. This editor saves the content in the XML format that can be used for Jackrabbit node type registration. It completely supports drag 'n drop, copy & paste and undo/redo. The editor is basically the sample model editor of EMF enhanced with the JCRM type mapping semantics. You can use it to create a new XML file for the node type registration in Jackrabbit and you can also read the node types from the repository save it and manipulate it with this editor.
 
[[Image:JackrabbitXMLNodetypeEditor.png]]
 
[[Image:JackrabbitXMLNodetypeEditor.png]]
 +
## "src-gen/library.nodetype" is a native JCRM model that serves as a basis for transformations into other models.
 +
# Right-Click at "workflow/loadModelFromRepository.oaw" choose "Run As/oAW Workflow" to create a new EMF model from the native JCR node types and your own node types that are currently registered to your repository. This basically puts your domain model in the context of the node types of your repository.
 +
## "src-gen/loadedLibrary.ecore" is the Ecore model that contains the domain model, the native JCR node types in Ecore format and the annotations that map the Ecore elements to node types elements. The JCR namespaces are mapped to packages.
 +
## "src-gen/loadedLibrarySinglePackage.ecore" is the same Ecore model like loadedLibrary.ecore. It is just not seperated into packages to make it easier to create a complete class diagram from that.
 +
## Right-Click at "loadedLibrarySinglePackage.ecore/Initialize ecore_diagram Diagram file"
 +
## Press "Finish" and you will see how the EClasses (node types) relate to each other in the Diagram
 +
[[Image:ClassEditor.png]]
  
=== Jackrabbit CND Editor ===
+
=== Configure JCRM for the use as API and as domain model editor ===
This text editor validates the content against the Jackrabbit CND format. It also contains minimal code completion. For this editor the XText framework of oAW is used. The JCRM type mapping framework makes it possible to use the JCR node type structure in the grammar for the XText editor. This way the CND file can get generated from the node types in the repository on the fly.
+
# Copy the loadedLibrary from the src-gen folder to the model folder to avoid that it is overwritten by subsequent calls on loadModelFromRepository.oaw
At the moment only a small subset of the XText features are used in this editor.
+
# Right-Click at loadedLibrary.ecore and create a new "Eclipse Modeling Framework/EMF model" (loadedLibrary.genmodel) based on the Ecore model.
 +
## Choose 'Ecore model' as model importer at the 3rd page
 +
## Press "Load" at the 4th page
 +
## At the "Package Selection" page press "Select all" and check both available models in the "Referenced generator models" section. Then you can finish the dialog.
 +
# Open the properties editor for the root element of the genmodel and change the "Model/Feature Delegation Field" to "Dynamic". That delegates all calls on the model to the JCRM framework.
 +
# Right-Click at the root element of the genmodel and select "Generate All". That generates the model classes, initial source code for a test class and the tree based editor for the model.
 +
# Add org.eclipse.emf.jcrm.userdependencies to the list of the plug-in dependencies in the META-INF/MANIFEST.MF file. Make sure the "reexport" option is selected.
 +
# Add the following extension to the plugin.xml file:
 +
  <extension point="org.eclipse.emf.jcrm.ejcrmnode.conCon4FileExtension">
 +
      <connectionConfiguration
 +
            ConConURI="defaultRMIConnection"
 +
            extension="library">
 +
      </connectionConfiguration>
 +
  </extension>
 +
It tells EMF to register the 'library' extension with the JCRM ResourceFactory. "defaultRMIConnection" is the name of the connection that the JCRM ResourceFactory (ConConResourceFactoryImpl) will use to connect to a JCR. Later on the tour you will see the connection configuration file that contains all configured connections to choose from.
  
[[Image:JackrabbitCNDEditor.png]]
+
=== Starting the domain model editor ===
 +
# In the main menu of your current (2nd) Eclipse instance choose "Run/Run Configurations"
 +
# Create a new Run Configuration for "Eclipse Application"
 +
# Give it a name like "Start Editor" if you want
 +
# Press "Run" to start a new Eclipse instance open a new simple project like that:
 +
# In the new Eclipse instance (the 3rd):
 +
## Navigate to Window / Show View / Other / JCR Management / ConConFile. This opens the view that manages the ConCon file. This file contains all configured JCR connections. It is the frontend for the JCRM ConCon framework. This framework allows to create arbitrary connector models to different repositories. While all connectors with its own models will be displayed by this unified model editor and all connections are referencable by a unique JCRM-URI. The 'org.eclipse.emf.jcrm.jr.rmi' bundle is an example of such a connector implementation.
 +
## Click on the link to open the file. It contains one preconfigured connection to a Jackrabbit 1.4 repository.
 +
[[Image:ConConModel.png]]
 +
## Navigate down to a Simple Credentials element
 +
## If you right-click it you find a menu item for our library model. Clicking it opens the editor that we previously generated for our model. There you can edit your Jackrabbit backed EMF model.
 +
[[Image:GeneratedEditor.png]]
  
=== Domain Model Editor ===
+
=== The API ===
The domain model editor is a sample tool that is generated from EMF. It usually has a XML backend. Just the backend configuration changes it to be an editor of JCR nodes.
+
To test the JCRM API you can replace the Demo.tests/src/library.tests.LibraryExample.main() method with the content from the sections below.
 +
If you would like to see the changes in the generated editor you need to go to the ConCon model, duplicate a credentials object, give it a new name and start the editor from there. The reason is that the editor does not yet get refreshed if the content changes from outside of the editor. This creates a new and uncached EMF resource.  
 +
==== Configuring the Resource, Navigation and Modification ====
 +
This adds some nodes and gives you a quick example of configuring the resource, navigation and modification with the JCRM runtime API.
 +
It uses the classes generated by EMF and the JCRM type mapping. At runtime you can see the JCRM object mapping at work.
 +
<source lang="java">
 +
public static void main(String[] args) throws IOException {
 +
// Create a resource set to hold the resources.
 +
ResourceSet resourceSet = new ResourceSetImpl();
 +
 +
// It registers the JCRM packages and the resource factory for the ConCon model.
 +
StandaloneSetup.initializeConCon();
 +
 +
//  JCRM uses an own scheme for resources. After 'jcr:/' follows the connection name and
 +
//  the extension identifying the model. This makes it possible to configure many
 +
                //  different connections for one model.
 +
//  Connections with its names can be configured in the singleton ConCon model
 +
//  by opening it from the ConConFile view at
 +
//  Window / Show View / Other / JCR Management / ConConFile
 +
URI resourceURI = URI.createURI("jcr:/defaultRMIConnection.library");
 +
  
Every change in the model immediately changes the underlaying repository. E.g. if you add a "Book" object in that editor node.addNode("NewNode","Book") is called. As soon as you save the editor session.save() is called.  
+
                // This file is automatically created with you create the first JCRM project within the workspace.
 +
                // The name of the properties file is always jcrm.properties.
 +
                // You can copy the path from the ConConFile view at
 +
// Window / Show View / Other / JCR Management / ConConFile
 +
                // Just click at 'ConCon File Location' and copy the path of the folder.
 +
String path2jcrmProperties = "/Users/sboehme/Documents/workspaces/runtime-New_configuration_26/.metadata/.plugins/org.eclipse.emf.jcrm.repoconn/jcrm.properties";
  
[[Image:JCRMDomainModelEditor.png]]
+
// The properties file is needed to read the path to the ConCon file that contains configuration of the
 +
// connection to the repository.
 +
ConConResourceFactoryImpl conConResourceFactoryImpl = new ConConResourceFactoryImpl(path2jcrmProperties);
 +
 +
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("library", conConResourceFactoryImpl);
 +
conConResourceFactoryImpl.addResource(resourceURI);
  
== The API ==
+
// Register the package to ensure it is available during loading.
 +
resourceSet.getPackageRegistry().put(LibraryPackage.eNS_URI, LibraryPackage.eINSTANCE);
  
=== Navigation and Modification ===
+
try {
The API uses the classes generated by EMF and the JCRM type mapping. At runtime you can see the JCRM object mapping at work. You can find more detailed descriptions in the comments.
+
// Create the resource to access the model
<source lang="java">
+
Resource resource = resourceSet.createResource(resourceURI);
public static void main(String[] args) {
+
  // Create an EMF resource set to hold the resources.
+
// Create a domain object. The constructor is initially generated by EMF to be protected
  ResourceSet resourceSet = new ResourceSetImpl();
+
                        // but you can make it public if you want.
+
Library library = LibraryFactory.eINSTANCE.createLibrary();
  // Register the appropriate EMF resource factory to handle the file
+
        // extension "mydomainmodel"
+
// In contrast to the JCR specification EMF generally allows to have many root nodes
  resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put
+
                        // hence the content of the resource is designed to be a list in EMF even though the  
  ("mydomainmodel", new JRRMIResourceFactoryImpl());
+
                        // JCRM Framework needs only one element in the content.
+
                        // JCRM puts the root object containing the corresponding root node of the repository
  // Register the EMF package to ensure it is available during loading.
+
                        // in the content of the resource where it can get retrieved. "root" is the class
  resourceSet.getPackageRegistry().put
+
                        // of the rootObject that corresponds to the node type of the root node. Generating
  (MyDomainModelPackage.eNS_URI,
+
// classes with a first capital letter is a feature that is still to implement.
  MyDomainModelPackage.eINSTANCE);
+
root rootNode = (root) resource.getContents().get(0);
+
  try {
+
// As soon as an object is added to it's containing object it also get it's
                // Create an EMF resource using the registered "mydomainmodel" extension
+
                        // node injected. In this case the library object is added to the "bases"  
  Resource resource = resourceSet.createResource(URI.createURI("http:///My.mydomainmodel"));
+
                        // feature of the rootObject. That calls addNode() on the
+
                        // node that is contained within the rootObject. The resulting node
                // Create a domain object. The constructor is initially generated by EMF to be protected
+
                        // is then injected in the library object.
                // but you can make it public if you want.
+
rootNode.getBases().add(library);
  Library library = MyDomainModelFactory.eINSTANCE.createLibrary();
+
+
// Every domain object contains it's corresponding node and every modification  
                // In contrast to the JCR specification EMF generally allows to have many root nodes
+
                        // is delegated to the node. In this case setName...("MyLibraryNameByAPI") actually
                // hence the content of the resource is designed to be a list in EMF even though the  
+
                        // calls nodeOfTheObject.setProperty("name","MyLibraryNameByAPI")
                // JCRM Framework needs only one element in the content.
+
                        // This way the objects don't need to have own copies of the property content.
                // JCRM puts the root object containing the corresponding root node of the repository
+
                        // At the moment there is not something like a detached mode where you can
                // in the content of the resource where it can get retrieved. "root" is the type
+
                        // modify properties without the object having an injected node.
                // of the rootObject that corresponds to the node type of the root node.
+
library.setName("MyLibraryNameByAPI");  
  root rootObject = (root) resource.getContents().get(0);
+
library.setNodeName("MyLibraryNodeNameByAPI");
+
  Book aBook = LibraryFactory.eINSTANCE.createBook();
                // As soon as an object is added to it's containing object it also get it's
+
                // node injected. In this case the library object is added to the "bases"  
+
                // feature of the rootObject. That calls addNode() on the
+
                // node that is contained within the rootObject. The resulting node
+
                // is then injected in the library object.
+
  rootObject.getBases().add(library);
+
+
                // Every domain object contains it's corresponding node and every modification  
+
                // is delegated to the node. In this case setName...("MyLibraryNameByAPI") actually
+
                // calls nodeOfTheObject.setProperty("name","MyLibraryNameByAPI")
+
                // This way the objects don't need to have own copies of the property content.
+
                // At the moment there is not something like a detached mode where you can
+
                // modify properties without the object having an injected node.
+
  library.setName("MyLibraryNameByAPI");
+
  library.setNodeName("MyLibraryNodeNameByAPI");
+
  Book aBook = MyDomainModelFactory.eINSTANCE.createBook();
+
 
  library.getBooks().add(aBook);
 
  library.getBooks().add(aBook);
  Writer aWriter = MyDomainModelFactory.eINSTANCE.createGuideBookWriter();
+
  Writer aWriter = LibraryFactory.eINSTANCE.createGuideBookWriter();
 
  aBook.setAuthor(aWriter);
 
  aBook.setAuthor(aWriter);
 
  aWriter.setName("aGuidBookWritersNameByAPI");
 
  aWriter.setName("aGuidBookWritersNameByAPI");
 
  aBook.setTitle("Book-TitleByAPI");
 
  aBook.setTitle("Book-TitleByAPI");
 
  aBook.setPages("200ByAPI");
 
  aBook.setPages("200ByAPI");
+
 
                // that calls session.save() and persists the changes made above.
+
  // that calls session.save() and persists the changes made above.
  resource.save(System.out, null);
+
resource.save(System.out, null);
  }
+
} catch (IOException exception) {
  catch (IOException exception) {
+
exception.printStackTrace();
  exception.printStackTrace();
+
}
  }
+
}
  }
+
 
</source>
 
</source>
  
=== Locking ===
+
==== Locking ====
 
<source lang="java">
 
<source lang="java">
 
 
public static void main(String[] args) {
 
public static void main(String[] args) {
// Create an EMF resource set to hold the resources.
+
// Information about configuring the resource and navigating in the model can
 +
// be found in the previous example
 
ResourceSet resourceSet = new ResourceSetImpl();
 
ResourceSet resourceSet = new ResourceSetImpl();
 
+
StandaloneSetup.initializeConCon();
// Register the appropriate EMF resource factory to handle the file extension "mydomainmodel"  
+
URI resourceURI = URI.createURI("jcr:/defaultRMIConnection.library");
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("mydomainmodel",
+
String path2jcrmProperties = "/Users/sboehme/Documents/workspaces/runtime-New_configuration_26/.metadata/.plugins/org.eclipse.emf.jcrm.repoconn/jcrm.properties";
new JRRMIResourceFactoryImpl());
+
ConConResourceFactoryImpl conConResourceFactoryImpl = new ConConResourceFactoryImpl(path2jcrmProperties);
 
+
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("library", conConResourceFactoryImpl);
// Register the EMF package to ensure it is available during loading.
+
conConResourceFactoryImpl.addResource(resourceURI);
resourceSet.getPackageRegistry().put(MyDomainModelPackage.eNS_URI, MyDomainModelPackage.eINSTANCE);
+
resourceSet.getPackageRegistry().put(LibraryPackage.eNS_URI, LibraryPackage.eINSTANCE);
 
+
 
try {
 
try {
// Create a library object to lock it.
+
Resource resource = resourceSet.createResource(resourceURI);
Resource resource = resourceSet.createResource(URI.createURI("http:///My.mydomainmodel"));
+
Library library = LibraryFactory.eINSTANCE.createLibrary();
Library library = MyDomainModelFactory.eINSTANCE.createLibrary();
+
 
root rootObject = (root) resource.getContents().get(0);
 
root rootObject = (root) resource.getContents().get(0);
 
rootObject.getBases().add(library);
 
rootObject.getBases().add(library);
 
library.setNodeName("Testlibrary for locking");
 
library.setNodeName("Testlibrary for locking");
 
library.setName("Testlibrary for locking");
 
library.setName("Testlibrary for locking");
+
 
// Make this library lockable.
 
// Make this library lockable.
 
library.setLockable(true);
 
library.setLockable(true);
 
resource.save(System.out, null);
 
resource.save(System.out, null);
 
+
 
// The JSR-170 javadoc says about the session scoped lock:
 
// The JSR-170 javadoc says about the session scoped lock:
 
// If isSessionScoped is true then this lock will expire upon the expiration of the  
 
// If isSessionScoped is true then this lock will expire upon the expiration of the  
 
// current session.
 
// current session.
 
boolean sessionScoped = true;
 
boolean sessionScoped = true;
+
 
// The JSR-170 javadoc says about the deep lock:
 
// The JSR-170 javadoc says about the deep lock:
 
// If isDeep is true then the lock applies to this node and all its descendant nodes;  
 
// If isDeep is true then the lock applies to this node and all its descendant nodes;  
 
boolean deep = true;
 
boolean deep = true;
+
 
// Apply the lock to the library.
 
// Apply the lock to the library.
 
library.lock(deep, sessionScoped);
 
library.lock(deep, sessionScoped);
+
 
try {
 
try {
 
// This method tries to change the library in an other session.
 
// This method tries to change the library in an other session.
 
// But that throws an Exception as the library is locked.  
 
// But that throws an Exception as the library is locked.  
changeLibraryNameInANewSession();
+
changeLibraryNameInANewSession(conConResourceFactoryImpl, resourceSet);
 
} catch (Throwable t) {
 
} catch (Throwable t) {
 
// Exception is throws as we try to modify a locked node.
 
// Exception is throws as we try to modify a locked node.
 
t.printStackTrace();
 
t.printStackTrace();
 
}
 
}
+
 
// Unlock the library.
 
// Unlock the library.
 
library.unlock();
 
library.unlock();
+
 
// Changing the library in an other session is possible now.
 
// Changing the library in an other session is possible now.
changeLibraryNameInANewSession();
+
changeLibraryNameInANewSession(conConResourceFactoryImpl, resourceSet);
 
+
 
// that calls session.save() and persists the changes made above.
 
// that calls session.save() and persists the changes made above.
 
resource.save(System.out, null);
 
resource.save(System.out, null);
Line 187: Line 284:
 
}
 
}
 
}
 
}
 
+
private static void changeLibraryNameInANewSession() {
+
private static void changeLibraryNameInANewSession(ConConResourceFactoryImpl conConResourceFactoryImpl, ResourceSet resourceSet) {
ResourceSet secondResourceSet = new ResourceSetImpl();
+
URI resourceURI = URI.createURI("jcr:/otherUserDefaultRMIConnection.library");
secondResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("mydomainmodel",
+
conConResourceFactoryImpl.addResource(resourceURI);
new JRRMIResourceFactoryImpl());
+
Resource secondResource = resourceSet.createResource(resourceURI);
 
+
// Register the EMF package to ensure it is available during loading.
+
secondResourceSet.getPackageRegistry().put(MyDomainModelPackage.eNS_URI, MyDomainModelPackage.eINSTANCE);
+
Resource secondResource = secondResourceSet.createResource(URI.createURI("http:///My2nd.mydomainmodel"));
+
 
root secondRootObject = (root) secondResource.getContents().get(0);
 
root secondRootObject = (root) secondResource.getContents().get(0);
 
EList<base> rootChildren = secondRootObject.getBases();
 
EList<base> rootChildren = secondRootObject.getBases();
Line 204: Line 297:
 
</source>
 
</source>
  
== Tasks ==
+
==== Versioning ====
# See Bugzilla for an overview of the ToDo's https://bugs.eclipse.org/bugs/buglist.cgi?short_desc_type=allwordssubstr&short_desc=&product=EMFT&component=JCR+Management&long_desc_type=allwordssubstr&long_desc=&order=Importance
+
<source lang="java">
 
+
public static void main(String[] args) {
 
+
// Information about configuring the resource and navigating in the model can
== Next Milestone ==
+
// be found in the previous example
Create a first downloadable presentation of the project to show the potential of Eclipse modeling to the Jackrabbit community.
+
ResourceSet resourceSet = new ResourceSetImpl();
 
+
StandaloneSetup.initializeConCon();
== Ideas ==
+
URI resourceURI = URI.createURI("jcr:/defaultRMIConnection.library");
* Using Cedrics Compare editor inside the JCR Manager
+
String path2jcrmProperties = "/Users/sboehme/Documents/workspaces/runtime-New_configuration_26/.metadata/.plugins/org.eclipse.emf.jcrm.repoconn/jcrm.properties";
:http://www.eclipse.org/modeling/emft/?project=compare#compare
+
ConConResourceFactoryImpl conConResourceFactoryImpl = new ConConResourceFactoryImpl(path2jcrmProperties);
 
+
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("library", conConResourceFactoryImpl);
== Values ==
+
conConResourceFactoryImpl.addResource(resourceURI);
* simplicity
+
resourceSet.getPackageRegistry().put(LibraryPackage.eNS_URI, LibraryPackage.eINSTANCE);
* transparency
+
try {
* no dependency on JCR implementations
+
Resource resource = resourceSet.createResource(resourceURI);
 
+
  Library library = LibraryFactory.eINSTANCE.createLibrary();
== FAQ ==
+
  root rootObject = (root) resource.getContents().get(0);
# What's the relationship between JCR Management and Jackrabbit JCR-OCM?
+
  rootObject.getBases().add(library);
One part of JCR Management has the same goal as JCR-OCM - exposing node data and operations to domain models - but JCRM uses an MDSD approach based on Eclipse Modeling Framework (EMF). This makes it depending less on reflection and using more generated classes instead. It will delegate as many calls on JCR node data as possible to minimize copying node data to domain model objects. Additionally JCR Management also has many other goals. But find out the details of JCR-OCM and check out the  [http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-ocm/ source code] and the [http://jackrabbit.apache.org/object-content-mapping.html documentation].
+
  library.setNodeName("MyVersionedLibrary1");
 
+
  library.setName("MyVersionedLibrary");
== Try it out ==
+
  // initial unversioned content
 
+
  resource.save(System.out,null);
[[Category:Modeling]]
+
[[Category:EMFT]]
+
  library.setVersionable(true);
 
+
  library.setName("MyLibraryVersion Zero");
=== Installation ===
+
  resource.save(System.out,null);
* Jackrabbit:
+
  // checkin the initial version
JCRM expects the currently latest Jackrabbit version remotely at "//localhost:1099/jackrabbit.repository". Please make sure it's available there.
+
  // This makes the library read-only until checkout() is called.
* Eclipse:
+
  library.checkin();
JCRM is tested with the Eclipse modeling package (http://www.eclipse.org/downloads/packages/) together with oAW (http://www.eclipse.org/downloads/download.php?file=/technology/gmt/oaw/43/openarchitectureware-sdk-4.3-release.zip)
+
* JCRM:
+
  try {
- Check out all modules from org.eclipse.emf/org.eclipse.emf.jcrm/plugins as plugins using this repository connection:
+
// The library is not changeable as it is not yet checked out.
    Server: dev.eclipse.org
+
library.setName("New Text");
    Repository Path: /cvsroot/modeling
+
} catch (Exception e) {
    User: anonymous
+
//Trying to change versioned content that is not checked out throws an Exception.
    Password: (leave blank)
+
}
    Connection Type: pserver
+
    Checkout As: Empty EMF Project
+
  library.checkout();
- In the "org.eclipse.emf.jcrm.conversion" plugin in the source folder you find the general build.xml file. It is used to build all projects.
+
  library.setName("MyLibraryVersion One");
# Right-Click it and choose "Run As/Ant Build..."
+
  resource.save(System.out,null);
# In the "JRE" tab choose "Run in the same JRE as the workspace"
+
  // Creates a second version.
# Press "Run"
+
  library.checkin();
 
+
If there are no errors anymore you successfully checked out JCRM.
+
  library.checkout();
 
+
  library.setName("MyLibraryVersion Two");
=== Running JCRM ===
+
  resource.save(System.out,null);
# In the main menu choose "Run/Run Configurations"
+
  // Creates a third version.
# Create a new Run Configuration for "Eclipse Application"
+
  library.checkin();
# Give it a name like "Start JCRM" if you want
+
# In the "Arguments" tab enter "-Xmx512m" in the "VM arguments" field
+
  JCRMVersionHistory versionHistory = library.getJcrmVersionHistory();
# Press "Run" to start a new Eclipse instance
+
  EList<JCRMVersion> allVersions = versionHistory.getAllVersions();
# You can also start your Jackrabbit server now
+
  for (JCRMVersion version : allVersions) {
 
+
java.util.Date creationDate = version.getCreated();
This puts all plugin projects that have been checked out (and maybe modified) into the new Eclipse instance.
+
String versionName=version.getVersionName();
 
+
System.out.println("Version: "+versionName+": created at: "+creationDate);
=== Creating a demo domain model ===
+
}
# In the new Eclipse instance create a new JCR Management project using the "New Project..." wizard. You can give it a name like "Demo" if you want.
+
# Paste the [[example library EMF model]] as library.ecore into the generated "model" folder. I tested JCRM basically with this model but the current features should also work with other models.
+
  boolean removeExisting=true;
# In the "workflow" folder open the "workflow.properties" file and change the "projectFolderName" to the one you have choosen in the New Project-wizard.
+
library.restore("1.1", removeExisting);
 
+
System.out.println(library.getName());
=== Registering the domain model and create the tooling ===
+
Now the fun part starts as the tooling can be generated.
+
// Non versioning use cases e.g. the generated EMF editor don't call
# Right-Click at "workflow/registerModelToRepository.oaw" choose "Run As/oAW Workflow" to register your Ecore model to the Jackrabbit repository.
+
// checkout()/checkin() before/after a model modification.  
## "src-gen/library.jrxmlntmodel" is the xml file that has been used to register the domain model as Jackrabbit XML.
+
// Set versionable to false to not force checkin()/checkout()  
## "src-gen/library.nodetype" is a native JCRM model that serves as a basis for transformations into other models.
+
// in these use cases later on.
# Right-Click at "workflow/loadModelFromRepository.oaw" choose "Run As/oAW Workflow" to create a new EMF model from the native JCR node types and your own node types that are currently registered to your repository. This basically puts your domain model in the context of the node types of your repository.
+
library.checkout();
## "src-gen/loadedLibrary.ecore" is the Ecore model that contains the domain model, the native JCR node types in Ecore format and the annotations that map the Ecore elements to node types elements.
+
library.setVersionable(false);
## "src-gen/loadedlibraryNodeTypes.nodetype" is a native JCRM model that serves as a basis for transformations into other models.
+
## "src-gen/loadedLibrary.jrcnd" is a generated file that contains all node types in the Jackrabbit CND format.
+
        // that calls session.save() and persists the changes made above.
## Right-Click at "loadedLibrary.ecore/Initialize ecore_diagram Diagram file"
+
  resource.save(System.out, null);
## Press "Finish" and you will see how the EClasses (node types) relate to each other in the Diagram
+
  }
 
+
  catch (IOException exception) {
=== Configure JCRM for the use as API and as domain model editor ===
+
  exception.printStackTrace();
# Copy the loadedLibrary from the src-gen folder to the model folder to avoid that it is overwritten by subsequent calls on loadModelFromRepository.oaw
+
  }
# To make JCRM aware of changes in the model instance, all domain model classes need to extend from JCRM's JCRMNode class instead of Object or EMF's EObject. As now basically all domain model classes inherit from the "Base" class (nt:base) we only need to make the Base class inherit from JCRMNode. To do this you can do the following steps:
+
  }
## Open the mode/loadedLibrary.ecore file
+
</source>
## Right-Click at the root node of the tree and choose "Load Resource..."
+
## Choose "Browse Registered Packages..."
+
## Select "http://www.eclipse.org/jcrm/0.8.0/dmodel, finish the dialog and save the model. This references the domain model (dmodel) base of JCRM for the object-node mapping.
+
## Open the properties editor for the "base" EClass
+
## Assign the JCRMNode EClass as the ESuper Type for "base"
+
# Right-Click at loadedLibrary.ecore and create a new "Eclipse Modeling Framework/EMF model" (loadedLibrary.genmodel) based on the Ecore model.  
+
## Click throuch to the 4th page and press "Load".
+
## At the "Package Selection" page check "myDomainModel" as "Root packages" and "Domainmodel" as "Referenced generator models". Then you can finish the dialog.
+
# Open the properties editor for the root element of the genmodel and change the "Model/Feature Delegation Field" to "Reflective". That delegates all calls on the model to the JCRM framework. Later an other value instead of "Reflective" will be used which will provide more flexibility.
+
# Right-Click at the root element of the genmodel and select "Generate All". That generates the model classes, initial source code for a test class and the tree based editor for the model.
+
# Add org.eclipse.emf.jcrm.userdependencies to the list of the plug-in dependencies in the  META-INF/MANIFEST.MF file. Make sure the "reexport" option is selected.
+
# Add the "org.eclipse.emf.ecore.extension_parser" extension to the list of extensions in the plugin.xml file (it's the same editor as the manifest.mf file.
+
## Use "mydomainmodel" in the type field. That declarates that every resource that ends with *.mydomainmodel will handled by the JCR backend we declare in the class field
+
## In the class field add the Jackrabbit RMI Resource Factory class "org.eclipse.emf.jcrm.jr.rmi.JRRMIResourceFactoryImpl". Now the JCRM class <--> node type mapping, the object <--> node mapping and the backend (resource) configuration are finished.
+
 
+
=== Starting a test case using the API ===
+
# To test the JCRM API you can replace the Demo.tests/src/myDomainModel.tests.MyDomainModelExample.main() method with the one from http://wiki.eclipse.org/JCR_Management#The_API . If you run it as an application within Eclipse you need to add "-Xmx512m" to the VM arguments in the "Arguments" tab of the run configuration. This should add some nodes and give you a quick example of the JCRM runtime API.
+
 
+
=== Starting the domain model editor ===
+
# In the main menu of your current (2nd) Eclipse instance choose "Run/Run Configurations"
+
# Create a new Run Configuration for "Eclipse Application"
+
# Give it a name like "Start Editor" if you want
+
# In the "Arguments" tab enter "-Xmx512m" in the "VM arguments" field
+
# Press "Run" to start a new Eclipse instance open a new simple project like that:
+
# In the new Eclipse instance (the 3rd):
+
## Click at "File/New/Project...".
+
## Choose "General/Project".
+
## Give it a name like "Editor".
+
# Now you can create the domain model editor by using the new file wizard:
+
## Right click at your project and choose "New/Other...".
+
## Choose "Example EMF Model Creation Wizards/MyDomainModel".
+
## Give it an arbitrary name.
+
## Choose an arbitrary Model Object in the following page and finish the dialog.
+
## Now the editor opens and you can edit your Jackrabbit backed model.
+
## The properties editor can be opened by right clicking on a model element and choosing "Show Properties View".
+

Latest revision as of 13:45, 25 September 2010

JCR Management (JCRM)

JCR Management will provide tooling and a JCR (http://en.wikipedia.org/wiki/Content_repository_API_for_Java) persistence framework for EMF with pluggable JCR implementations.


The Contributions

2008

  • Johan Gielstra:
  • My employer inovex GmbH (http://www.inovex.de) contributes 2 person days to work on this project within working hours.
  • Ed Merks:
    • helps as a mentor for questions regarding the Eclipse foundation.
    • implemented a new feature request for EMF that I had (dynamic feature delegation)
    • answers a lot of my questions in the newsgroup

2007

  • My employer inovex GmbH (http://www.inovex.de) contributes 5 person days to work on this project within working hours.
  • Ed Merks:
    • helps as a mentor for questions regarding the Eclipse foundation.
    • answers a lot of my questions in the newsgroup
  • The ATL team contributed an initial meta model and transformation that will speed up ATL integration.
  • Nick Boldt created the initial JCR Management (CVS, website, ...) setup at eclipse.org

The Status

JCRM is not production ready at the moment. The current code base consists of prototypes that serve as a basis for concrete discussions about requirements and solutions. The prototypes are tested exclusively with the example library EMF model.

The Architecture

JCRM is based on a mapping between EMF and JCR. One part is responsible to map EMF type elements to JCR node type elements and the other part maps EMF objects to JCR nodes. The main advantage of that architecture is, that many EMF frameworks can now work on JCR node types and nodes. The following JCRM tool prototypes are just examples how this mapping can be used. More ideas JCR tools or Eclipse projects are certainly welcome. They will be logged in the ideas section of this wiki. The most interesting ideas will be provided to the community for priorization and for validation the use cases. After that the JCRM team (at the moment it's just me - Sandro) will work on it.

Mapping of type elements

There is a seperate page that explains how to map EMF type elements to JCR node type elements.

Tasks

  1. See Bugzilla for an overview of the ToDo's https://bugs.eclipse.org/bugs/buglist.cgi?short_desc_type=allwordssubstr&short_desc=&product=EMFT&component=JCR+Management&long_desc_type=allwordssubstr&long_desc=&order=Importance


Next Milestone

Create a first downloadable presentation of the project.

Ideas

  • Using Cedrics Compare editor inside the JCR Manager
http://www.eclipse.org/modeling/emft/?project=compare#compare

FAQ

  1. What's the relationship between JCR Management and Jackrabbit JCR-OCM?

One part of JCR Management has the same goal as JCR-OCM - exposing node data and operations to domain models - but JCRM uses an MDSD approach based on Eclipse Modeling Framework (EMF). This makes it depending less on reflection and using more generated classes instead. It will delegate as many calls on JCR node data as possible to minimize copying node data to domain model objects. Additionally JCR Management also has many other goals. But find out the details of JCR-OCM and check out the source code and the documentation.

A tour through JCRM

Installation

  • Jackrabbit:

JCRM currently expects Jackrabbit version 1.4 remotely at "//localhost:1099/jackrabbit.repository". Please make sure it's available there.

  • Eclipse:

JCRM is tested with the Eclipse Gallileo modeling package

  • JCRM:
    • Create a new CVS repository location with the following configuration:
   Server: dev.eclipse.org
   Repository Path: /cvsroot/modeling
   User: anonymous
   Password: (leave blank)
   Connection Type: pserver
    • Navigate to the branch 'org_eclipse_emf_jcrm-tour-0_8_3'
    • Check out all modules org.eclipse.emf.jcrm.* as plugins
    • In the "org.eclipse.emf.jcrm.conversion" plugin in the source folder you find the general build.xml file. It is used to build all projects.
  1. Right-Click it and choose "Run As/Ant Build..."
  2. In the "JRE" tab choose "Run in the same JRE as the workspace"
  3. Press "Run"
    • There are three projects that don't get generated successfully with the Ant task. Unfortunately you have to generate these projects manually until I found a solution to that. These projects are:
  1. org.eclipse.emf.jcrm.repoconn.simplecredentials
  2. org.eclipse.emf.jcrm.repoconn and
  3. org.eclipse.emf.jcrm.ntmodel

Please go into their "model" folder, open the *.genmodel file, right-click at the root element and choose "Generate All"

    • If there are no errors anymore you successfully checked out JCRM.

Running JCRM

  1. In the main menu choose "Run/Run Configurations"
  2. Create a new Run Configuration for "Eclipse Application"
  3. Give it a name like "Start JCRM" if you want
  4. In the "Arguments" tab make sure there is "-Xmx512m" in the "VM arguments" field
  5. Press "Run" to start a new Eclipse instance
  6. You can also start your Jackrabbit server now

This puts all plugin projects that have been checked out (and maybe modified) into the new Eclipse instance.

Creating a demo domain model

  1. In the new Eclipse instance create a new JCR Management project using the "New Project..." wizard. You can give it a name like "Demo" if you want.
  2. Paste the example library EMF model as library.ecore into the generated "model" folder. I tested JCRM basically with this model but the current features should also work with other models.

Registering the domain model and create the tooling

Now the fun part starts as the tooling can be generated.

  1. Right-Click at "workflow/registerModelToRepository.oaw" choose "Run As/oAW Workflow" to register your Ecore model to the Jackrabbit repository.
    1. "src-gen/library.jrxmlnt" is the xml file that has been used to register the domain model as Jackrabbit XML. This editor saves the content in the XML format that can be used for Jackrabbit node type registration. It completely supports drag 'n drop, copy & paste and undo/redo. The editor is basically the sample model editor of EMF enhanced with the JCRM type mapping semantics. You can use it to create a new XML file for the node type registration in Jackrabbit and you can also read the node types from the repository save it and manipulate it with this editor.

JackrabbitXMLNodetypeEditor.png

    1. "src-gen/library.nodetype" is a native JCRM model that serves as a basis for transformations into other models.
  1. Right-Click at "workflow/loadModelFromRepository.oaw" choose "Run As/oAW Workflow" to create a new EMF model from the native JCR node types and your own node types that are currently registered to your repository. This basically puts your domain model in the context of the node types of your repository.
    1. "src-gen/loadedLibrary.ecore" is the Ecore model that contains the domain model, the native JCR node types in Ecore format and the annotations that map the Ecore elements to node types elements. The JCR namespaces are mapped to packages.
    2. "src-gen/loadedLibrarySinglePackage.ecore" is the same Ecore model like loadedLibrary.ecore. It is just not seperated into packages to make it easier to create a complete class diagram from that.
    3. Right-Click at "loadedLibrarySinglePackage.ecore/Initialize ecore_diagram Diagram file"
    4. Press "Finish" and you will see how the EClasses (node types) relate to each other in the Diagram

ClassEditor.png

Configure JCRM for the use as API and as domain model editor

  1. Copy the loadedLibrary from the src-gen folder to the model folder to avoid that it is overwritten by subsequent calls on loadModelFromRepository.oaw
  2. Right-Click at loadedLibrary.ecore and create a new "Eclipse Modeling Framework/EMF model" (loadedLibrary.genmodel) based on the Ecore model.
    1. Choose 'Ecore model' as model importer at the 3rd page
    2. Press "Load" at the 4th page
    3. At the "Package Selection" page press "Select all" and check both available models in the "Referenced generator models" section. Then you can finish the dialog.
  3. Open the properties editor for the root element of the genmodel and change the "Model/Feature Delegation Field" to "Dynamic". That delegates all calls on the model to the JCRM framework.
  4. Right-Click at the root element of the genmodel and select "Generate All". That generates the model classes, initial source code for a test class and the tree based editor for the model.
  5. Add org.eclipse.emf.jcrm.userdependencies to the list of the plug-in dependencies in the META-INF/MANIFEST.MF file. Make sure the "reexport" option is selected.
  6. Add the following extension to the plugin.xml file:
  <extension point="org.eclipse.emf.jcrm.ejcrmnode.conCon4FileExtension">
     <connectionConfiguration
           ConConURI="defaultRMIConnection"
           extension="library">
     </connectionConfiguration>
  </extension>

It tells EMF to register the 'library' extension with the JCRM ResourceFactory. "defaultRMIConnection" is the name of the connection that the JCRM ResourceFactory (ConConResourceFactoryImpl) will use to connect to a JCR. Later on the tour you will see the connection configuration file that contains all configured connections to choose from.

Starting the domain model editor

  1. In the main menu of your current (2nd) Eclipse instance choose "Run/Run Configurations"
  2. Create a new Run Configuration for "Eclipse Application"
  3. Give it a name like "Start Editor" if you want
  4. Press "Run" to start a new Eclipse instance open a new simple project like that:
  5. In the new Eclipse instance (the 3rd):
    1. Navigate to Window / Show View / Other / JCR Management / ConConFile. This opens the view that manages the ConCon file. This file contains all configured JCR connections. It is the frontend for the JCRM ConCon framework. This framework allows to create arbitrary connector models to different repositories. While all connectors with its own models will be displayed by this unified model editor and all connections are referencable by a unique JCRM-URI. The 'org.eclipse.emf.jcrm.jr.rmi' bundle is an example of such a connector implementation.
    2. Click on the link to open the file. It contains one preconfigured connection to a Jackrabbit 1.4 repository.

ConConModel.png

    1. Navigate down to a Simple Credentials element
    2. If you right-click it you find a menu item for our library model. Clicking it opens the editor that we previously generated for our model. There you can edit your Jackrabbit backed EMF model.

GeneratedEditor.png

The API

To test the JCRM API you can replace the Demo.tests/src/library.tests.LibraryExample.main() method with the content from the sections below. If you would like to see the changes in the generated editor you need to go to the ConCon model, duplicate a credentials object, give it a new name and start the editor from there. The reason is that the editor does not yet get refreshed if the content changes from outside of the editor. This creates a new and uncached EMF resource.

Configuring the Resource, Navigation and Modification

This adds some nodes and gives you a quick example of configuring the resource, navigation and modification with the JCRM runtime API. It uses the classes generated by EMF and the JCRM type mapping. At runtime you can see the JCRM object mapping at work.

	public static void main(String[] args) throws IOException {
		// Create a resource set to hold the resources.
		ResourceSet resourceSet = new ResourceSetImpl();
 
		// It registers the JCRM packages and the resource factory for the ConCon model.
		StandaloneSetup.initializeConCon();
 
		//  JCRM uses an own scheme for resources. After 'jcr:/' follows the connection name and
		//  the extension identifying the model. This makes it possible to configure many
                //  different connections for one model.
		//  Connections with its names can be configured in the singleton ConCon model 
		//  by opening it from the ConConFile view at
		//  Window / Show View / Other / JCR Management / ConConFile
		URI resourceURI = URI.createURI("jcr:/defaultRMIConnection.library");
 
 
                // This file is automatically created with you create the first JCRM project within the workspace.
                // The name of the properties file is always jcrm.properties.
                // You can copy the path from the ConConFile view at 
		// Window / Show View / Other / JCR Management / ConConFile
                // Just click at 'ConCon File Location' and copy the path of the folder.
		String path2jcrmProperties = "/Users/sboehme/Documents/workspaces/runtime-New_configuration_26/.metadata/.plugins/org.eclipse.emf.jcrm.repoconn/jcrm.properties";
 
		// The properties file is needed to read the path to the ConCon file that contains configuration of the
		// connection to the repository.
		ConConResourceFactoryImpl conConResourceFactoryImpl = new ConConResourceFactoryImpl(path2jcrmProperties);
 
		resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("library",	conConResourceFactoryImpl);
		conConResourceFactoryImpl.addResource(resourceURI);
 
		// Register the package to ensure it is available during loading.
		resourceSet.getPackageRegistry().put(LibraryPackage.eNS_URI, LibraryPackage.eINSTANCE);
 
		try {
			// Create the resource to access the model
			Resource resource = resourceSet.createResource(resourceURI);
 
			// Create a domain object. The constructor is initially generated by EMF to be protected
                        // but you can make it public if you want.
			Library library = LibraryFactory.eINSTANCE.createLibrary();
 
			// In contrast to the JCR specification EMF generally allows to have many root nodes
                        // hence the content of the resource is designed to be a list in EMF even though the 
                        // JCRM Framework needs only one element in the content.
                        // JCRM puts the root object containing the corresponding root node of the repository
                        // in the content of the resource where it can get retrieved. "root" is the class
                        // of the rootObject that corresponds to the node type of the root node. Generating
			// classes with a first capital letter is a feature that is still to implement.
			root rootNode = (root) resource.getContents().get(0);
 
			// As soon as an object is added to it's containing object it also get it's
                        // node injected. In this case the library object is added to the "bases" 
                        // feature of the rootObject. That calls addNode() on the
                        // node that is contained within the rootObject. The resulting node
                        // is then injected in the library object.
			rootNode.getBases().add(library);
 
			// Every domain object contains it's corresponding node and every modification 
                        // is delegated to the node. In this case setName...("MyLibraryNameByAPI") actually
                        // calls nodeOfTheObject.setProperty("name","MyLibraryNameByAPI")
                        // This way the objects don't need to have own copies of the property content.
                        // At the moment there is not something like a detached mode where you can
                        // modify properties without the object having an injected node.
			library.setName("MyLibraryNameByAPI");	  		
			library.setNodeName("MyLibraryNodeNameByAPI");
	  		Book aBook = LibraryFactory.eINSTANCE.createBook();
	  		library.getBooks().add(aBook);
	  		Writer aWriter = LibraryFactory.eINSTANCE.createGuideBookWriter();
	  		aBook.setAuthor(aWriter);
	  		aWriter.setName("aGuidBookWritersNameByAPI");
	  		aBook.setTitle("Book-TitleByAPI");
	  		aBook.setPages("200ByAPI");
 
	  		// that calls session.save() and persists the changes made above.
			resource.save(System.out, null);
		} catch (IOException exception) {
			exception.printStackTrace();
		}
	}

Locking

	public static void main(String[] args) {
		// Information about configuring the resource and navigating in the model can
		// be found in the previous example
		ResourceSet resourceSet = new ResourceSetImpl();
		StandaloneSetup.initializeConCon();
		URI resourceURI = URI.createURI("jcr:/defaultRMIConnection.library");
		String path2jcrmProperties = "/Users/sboehme/Documents/workspaces/runtime-New_configuration_26/.metadata/.plugins/org.eclipse.emf.jcrm.repoconn/jcrm.properties";
		ConConResourceFactoryImpl conConResourceFactoryImpl = new ConConResourceFactoryImpl(path2jcrmProperties);
		resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("library",	conConResourceFactoryImpl);
		conConResourceFactoryImpl.addResource(resourceURI);
		resourceSet.getPackageRegistry().put(LibraryPackage.eNS_URI, LibraryPackage.eINSTANCE);
		try {
			Resource resource = resourceSet.createResource(resourceURI);
			Library library = LibraryFactory.eINSTANCE.createLibrary();
			root rootObject = (root) resource.getContents().get(0);
			rootObject.getBases().add(library);
			library.setNodeName("Testlibrary for locking");
			library.setName("Testlibrary for locking");			
 
			// Make this library lockable.
			library.setLockable(true);
			resource.save(System.out, null);
 
			// The JSR-170 javadoc says about the session scoped lock:
			// If isSessionScoped is true then this lock will expire upon the expiration of the 
			// current session.
			boolean sessionScoped = true;
 
			// The JSR-170 javadoc says about the deep lock:
			// If isDeep is true then the lock applies to this node and all its descendant nodes; 
			boolean deep = true;
 
			// Apply the lock to the library.
			library.lock(deep, sessionScoped);
 
			try {
				// This method tries to change the library in an other session.
				// But that throws an Exception as the library is locked. 
				changeLibraryNameInANewSession(conConResourceFactoryImpl, resourceSet);
			} catch (Throwable t) {
				// Exception is throws as we try to modify a locked node.
				t.printStackTrace();
			}
 
			// Unlock the library.
			library.unlock();
 
			// Changing the library in an other session is possible now.
			changeLibraryNameInANewSession(conConResourceFactoryImpl, resourceSet);
 
			// that calls session.save() and persists the changes made above.
			resource.save(System.out, null);
		} catch (IOException exception) {
			exception.printStackTrace();
		}
	}
 
	private static void changeLibraryNameInANewSession(ConConResourceFactoryImpl conConResourceFactoryImpl, ResourceSet resourceSet) {
		URI resourceURI = URI.createURI("jcr:/otherUserDefaultRMIConnection.library");
		conConResourceFactoryImpl.addResource(resourceURI);
		Resource secondResource = resourceSet.createResource(resourceURI);
		root secondRootObject = (root) secondResource.getContents().get(0);
		EList<base> rootChildren = secondRootObject.getBases();
		// retrieve the last library
		Library libraryFromSecondResource = (Library) rootChildren.get(rootChildren.size() - 1);
		libraryFromSecondResource.setName("not settable as the node is locked");
	}

Versioning

	public static void main(String[] args) {
		// Information about configuring the resource and navigating in the model can
		// be found in the previous example
		ResourceSet resourceSet = new ResourceSetImpl();
		StandaloneSetup.initializeConCon();
		URI resourceURI = URI.createURI("jcr:/defaultRMIConnection.library");
		String path2jcrmProperties = "/Users/sboehme/Documents/workspaces/runtime-New_configuration_26/.metadata/.plugins/org.eclipse.emf.jcrm.repoconn/jcrm.properties";
		ConConResourceFactoryImpl conConResourceFactoryImpl = new ConConResourceFactoryImpl(path2jcrmProperties);
		resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("library",	conConResourceFactoryImpl);
		conConResourceFactoryImpl.addResource(resourceURI);
		resourceSet.getPackageRegistry().put(LibraryPackage.eNS_URI, LibraryPackage.eINSTANCE);
		try {
			Resource resource = resourceSet.createResource(resourceURI);
	  		Library library = LibraryFactory.eINSTANCE.createLibrary();
	  		root rootObject = (root) resource.getContents().get(0);
	  		rootObject.getBases().add(library);
	  		library.setNodeName("MyVersionedLibrary1");
	  		library.setName("MyVersionedLibrary");
	  		// initial unversioned content
	  		resource.save(System.out,null);
 
	  		library.setVersionable(true);
	  		library.setName("MyLibraryVersion Zero");
	  		resource.save(System.out,null);
	  		// checkin the initial version
	  		// This makes the library read-only until checkout() is called.
	  		library.checkin();
 
	  		try {
				// The library is not changeable as it is not yet checked out.
				library.setName("New Text");
			} catch (Exception e) {
				//Trying to change versioned content that is not checked out throws an Exception.
			}
 
	  		library.checkout();
	  		library.setName("MyLibraryVersion One");
	  		resource.save(System.out,null);
	  		// Creates a second version.
	  		library.checkin();
 
	  		library.checkout();
	  		library.setName("MyLibraryVersion Two");
	  		resource.save(System.out,null);
	  		// Creates a third version.
	  		library.checkin();
 
	  		JCRMVersionHistory versionHistory = library.getJcrmVersionHistory();
	  		EList<JCRMVersion> allVersions = versionHistory.getAllVersions();
	  		for (JCRMVersion version : allVersions) {
				java.util.Date creationDate = version.getCreated();
				String versionName=version.getVersionName();
				System.out.println("Version: "+versionName+": created at: "+creationDate);
			}
 
	  		boolean removeExisting=true;
			library.restore("1.1", removeExisting);
			System.out.println(library.getName());
 
			// Non versioning use cases e.g. the generated EMF editor don't call
			// checkout()/checkin() before/after a model modification. 
			// Set versionable to false to not force checkin()/checkout() 
			// in these use cases later on.
			library.checkout();
			library.setVersionable(false);
 
	        // that calls session.save() and persists the changes made above.
	  		resource.save(System.out, null);
	  	}
	  	catch (IOException exception) {
	  		exception.printStackTrace();
	  	}
	  }

Back to the top