Tuesday, 6 March 2012

Programmatically Accessing Adobe CQ Content using the JCR API

You can programmatically modify nodes and properties located within the Adobe CQ repository, which is part of the Adobe Digital Marketing Suite. To access the CQ repository, you use the Java Content Repository (JCR) API. You can use the Java JCR API to perform create, replace, update, and delete (CRUD) operations on content located within the Adobe CQ repository. For more information about the Java JCR API, see http://jackrabbit.apache.org/jcr-api.html.

This development article creates a Java class that modifies nodes and properties within  Adobe CQ. The Java class connects to a local instance of  Adobe CQ and creates nodes and stores data values to node properties. You can store data by manipulating node properties.

Note: This development article modifies the Adobe CQ JCR from an external Java application. In contrast, you can modify the JCR from within an OSGi bundle using the JCR API. For details, see http://scottsdigitalcommunity.blogspot.ca/2013/01/persisting-cq-data-in-java-content.html.

Note: To learn how to query the Adobe CQ JCR using the JCR Query API, click this link: http://scottsdigitalcommunity.blogspot.ca/2013/02/querying-adobe-experience-manager-data.html.

To read this development article, click this link:

https://helpx.adobe.com/experience-manager/using/programmatically-accessing-cq-content-using.html

See Also

To learn how to write this Java Swing application that queries the Adobe Experience Manager JCR by using the JCR API:



Adobe Digital Marketing Community


Join the Adobe Digital Marketing Community. Start by clicking this banner

About the Author

I (Scott Macdonald) am a Senior Digital Marketing Community Manager at Adobe Systems with over 16 years in the high tech industry. I am also a programmer with knowledge in Java, JavaScript, C#,C++, HTML, XML and ActionScript. If  you would like to see more CQ or other Adobe Digital Marketing end to end articles like this, then leave a comment and let me know what content you would like to see.

Linked Inhttp://www.linkedin.com/in/scottmacdonald2010
TwitterFollow the Digital Marketing Customer Care team on Twitter @AdobeMktgCare.

45 comments:

  1. Hi Scott,

    This is a great article!
    I needed to access the JCR repository from within an OSGI-Bundle.
    Please suggest what would be the way to get the repository instance.

    The below step:
    Repository repository = JcrUtils.getRepository("http://localhost:4503/crx/server");
    seems to be to get the instance for an external application.

    Also my bundle is spring-based and I am using spring-dm.

    Thanks alot
    karan
    (jaskaran81@yahoo.com)

    ReplyDelete
    Replies
    1. See this one:

      http://scottsdigitalcommunity.blogspot.ca/2013/01/persisting-cq-data-in-java-content.html

      Delete
  2. Hello,

    For anyone who is interested this is the way to access the repository in a spring bundle:

    1) Update the manifest:
    Import-Package:org.apache.sling.jcr.api,javax.jcr

    2) Update the spring xml to get the sling repository:


    3) Sample Code in the class:
    session = slingRepository.loginAdministrative(null);
    Node root = session.getRootNode();
    Node test = root.addNode("test");
    session.save();
    session.logout();

    Thanks

    ReplyDelete
  3. sorry point 2 is incomplete
    here you go:
    2) Update the spring xml to get the sling repository:

    ReplyDelete
  4. Great suggestion that you specified here.

    ReplyDelete
  5. Hi Scott
    Can you please tell me how to create a sling servlet in day cq5.5? I am new to day cq , i am using scr annotations to create sling servlet. But scr annotations are not recognized by CQ. Its throwing exception. I am creating sling servlet using crxde.

    Thanks

    Akash

    ReplyDelete
    Replies
    1. Here is the article that talks about how to create a sling servlet for AEM:

      http://scottsdigitalcommunity.blogspot.ca/2013/06/posting-form-data-to-adobe-cq-using.html

      Delete
  6. Hi Scott,

    At onset, sincere thanks for the above article, and answers to questions around accessing the repository from within a Spring Bundle.

    I have a slightly different problem, I have created a simple OSGI bundle(not a listener or a scheduler or a service). Request you to please share some code-snippet, if possible to access the repository. I understood the step 1 for importing the package in the manifest file. However, i require a snippet to move further.

    All help is much appreciated !

    Thanks,
    Hemant

    ReplyDelete
    Replies
    1. See:

      http://scottsdigitalcommunity.blogspot.ca/2013/01/persisting-cq-data-in-java-content.html

      Delete
  7. Hello

    Can anyone give me an example about spring with cq5?

    ReplyDelete
  8. Hello,

    I am getting the error as below. Please help.

    Caused by: javax.jcr.RepositoryException: Unable to access a repository with the following settings:
    org.apache.jackrabbit.repository.uri: http://localhost:5502/crx/server
    The following RepositoryFactory classes were consulted:
    org.apache.jackrabbit.commons.JndiRepositoryFactory: declined
    org.apache.jackrabbit.core.RepositoryFactoryImpl: declined
    Perhaps the repository you are trying to access is not available at the moment.
    at org.apache.jackrabbit.commons.JcrUtils.getRepository(JcrUtils.java:217)
    at org.apache.jackrabbit.commons.JcrUtils.getRepository(JcrUtils.java:257)
    at cq.maven.ConnectToCQ.main(ConnectToCQ.java:23)

    ReplyDelete
    Replies
    1. Hi , Did you find the answer to your error? would you please let me know at dbroy05@gmail.com

      Delete
    2. This looks like you do not have the correct JAR file in your class path.

      Delete
  9. I am getting the same error:

    javax.jcr.RepositoryException: Unable to access a repository with the following settings:
    org.apache.jackrabbit.repository.uri: http://localhost:8080/crx/server/

    Can you point to what I might be doing wrong?

    ReplyDelete
    Replies
    1. Hi

      I am also getting the error

      javax.jcr.RepositoryException: Unable to access a repository with the following settings:
      org.apache.jackrabbit.repository.uri: http://localhost:4502/crx/server/

      Delete
    2. Any solution? I seem to have the same issue while using getRepository()

      Delete
  10. This comment has been removed by a blog administrator.

    ReplyDelete
  11. Hi, i would like to know how to migrate a existing website(.php or .aspx) into CQ5?

    ReplyDelete
    Replies
    1. Hi Scott, Is it possible to migrate PHP or .Net websites into CQ?

      Delete
  12. Hi, Is it possible to assess the SiteAdmin node, or the Website area used for creating contents like images or reports ie libs/wcm/core/content/siteadmin.html

    ReplyDelete
  13. Yes - if you connect with correct permissions.

    ReplyDelete
  14. Hi Scott,
    This is a great article.

    We are using WEBDAV to create the session, we are not able to access the ACL node ie., we are not able to create/modify rep:policy nodes also not able to create rep:policy/deny or rep:policy/allow nodes. When we try to access getAccessControlManager() through the the session that we have created, we are facing issues. See below code snippet.

    By doing
    JackrabbitAccessControlManager acm = (JackrabbitAccessControlManager) session.getAccessControlManager();
    I am getting error
    “javax.jcr.UnsupportedRepositoryOperationException: JCR-1104”

    Please let me know if you have any inputs.

    Regards,
    Praveen

    ReplyDelete
  15. Hi Scott, I am able to create Pages via JCR APIs,but I am not able to publish or activate this pages. I have searched the internet and can't find a solution on this, is it possible to activate Pages programmatically?

    ReplyDelete
  16. I am looking into the answer to this question. I have not attempted to do this. I will let you know.

    ReplyDelete
    Replies
    1. Hi Scott, Can you help with any hint. I want to activate the page/node programatically.

      Delete
  17. This comment has been removed by the author.

    ReplyDelete
  18. Hi, I have been trying to add some node and write some properties through java code.
    I am getting the following error “javax.jcr.nodetype.ConstraintViolationException: no matching property definition found for {}id”.

    Could somebody tell me why it happens and how to solve error?

    Regards,
    Anderson

    ReplyDelete
    Replies
    1. Make sure that each id is unique. This code adds a customer node under content/customer. If the content/customer does not exist, this code creates it. Each custID property is unique too:


      /*
      * This Java Quick Start uses the jackrabbit-standalone-2.4.0.jar
      * file. See the previous section for the location of this JAR file
      */

      import java.util.Iterator;

      import javax.jcr.Repository;
      import javax.jcr.Session;
      import javax.jcr.SimpleCredentials;
      import javax.jcr.Node;

      import org.apache.jackrabbit.commons.JcrUtils;
      import org.apache.jackrabbit.core.TransientRepository;


      public class TestCustomerCode {


      public static void main(String[] args) throws Exception {

      try {

      //Create a connection to the CQ repository running on local host
      Repository repository = JcrUtils.getRepository("http://localhost:4502/crx/server");

      //Create a Session
      javax.jcr.Session session = repository.login( new SimpleCredentials("admin", "admin".toCharArray()));


      String firstName ="Tom";
      String lastName = "Blue";
      String phone ="555-555-5555";
      String desc = "active customer";

      //Create a node that represents the root node
      Node root = session.getRootNode();


      //Get the content node in the JCR
      Node content = root.getNode("content");

      //Determine if the content/customer node exists
      Node customerRoot = null;

      int custRec = doesCustExist(content);

      //-1 means that content/customer does not exist
      if (custRec == -1)
      //content/customer does not exist -- create it
      customerRoot = content.addNode("customer","sling:OrderedFolder");
      else
      //content/customer does exist -- retrieve it
      customerRoot = content.getNode("customer");

      int custId = custRec+1; //assign a new id to the customer node

      //Store content from the client JSP in the JCR
      Node custNode = customerRoot.addNode("customer"+firstName+lastName+custId,"nt:unstructured");

      //make sure name of node is unique
      custNode.setProperty("id", custId);
      custNode.setProperty("firstName", firstName);
      custNode.setProperty("lastName", lastName);
      custNode.setProperty("phone", phone);
      custNode.setProperty("desc", desc);

      // Save the session changes and log out
      session.save();
      session.logout();
      }
      catch(Exception e){
      e.printStackTrace();
      }
      }

      /*
      * Determines if the content/customer node exists
      * This method returns these values:
      * -1 - if customer does not exist
      * 0 - if content/customer node exists; however, contains no children
      * number - the number of children that the content/customer node contains
      */
      private static int doesCustExist(Node content)
      {
      try
      {
      int index = 0 ;
      int childRecs = 0 ;

      java.lang.Iterable custNode = JcrUtils.getChildNodes(content, "customer");
      Iterator it = custNode.iterator();

      //only going to be 1 content/customer node if it exists
      if (it.hasNext())
      {
      //Count the number of child nodes to customer
      Node customerRoot = content.getNode("customer");
      Iterable itCust = JcrUtils.getChildNodes(customerRoot);
      Iterator childNodeIt = itCust.iterator();

      //Count the number of customer child nodes
      while (childNodeIt.hasNext())
      {
      childRecs++;
      childNodeIt.next();
      }
      return childRecs;
      }
      else
      return -1; //content/customer does not exist
      }
      catch(Exception e)
      {
      e.printStackTrace();
      }
      return 0;
      }


      }

      Delete
  19. Hi Scott,
    I have a requirement to add all the files in a particular folder(Given by user) into DAM (Dam path is also specified). I have got the path of all assets in the particular folder, and created node in the DAM path. But how will generate renditions? and other metadata features? Simply How will i add files into DAM via "Code"? Thanks in Advance.

    Regards,
    Arthi

    ReplyDelete
  20. See this article that uploads a file and places the uploaded file into the AEM DAM: http://scottsdigitalcommunity.blogspot.ca/2013/07/uploading-files-to-adobe-experience.html

    ReplyDelete
  21. Hi Scott,

    Could you please help me display a binary as image. I am using a form with an upload image component. uploaded image has a new node and stored as binary. How do i retrive this binary as image and show on the jsp. Any help on this would be highly appreciated.

    Thanks,
    Hrishikesh.

    ReplyDelete
  22. Follow up to the previous comment. Code snippet i tried looks like this.
    javax.jcr.Session ses = resourceResolver.adaptTo(Session.class);
    Node root = ses.getRootNode();
    Node jcrContent = root.getNode("/content/usergenerated/proton- site/English/Product/product_create/product/jcr:content");
    InputStream is = jcrContent.getProperty("jcr:data").getBinary().getStream();
    BufferedInputStream bis = new BufferedInputStream(is);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while (result != -1) {
    byte b = (byte) result;
    buf.write(b);
    result = bis.read();
    }

    out.println("plain text: " + buf.toString());

    ReplyDelete
  23. You will want to see this one to learn how to display DAM images in a component:

    http://scottsdigitalcommunity.blogspot.ca/2013/08/creating-aem-dam-image-component.html

    ReplyDelete
  24. Thank you Scott. This was really helpful.

    ReplyDelete
  25. Hi Scott,
    Could you please explain how do we create deny (rep:DenyACE) on a rep:policy node programatically? Actually i am able to create allow node but no idea how to create deny. Any sample code snippet would be really helpful. Thanks in advance.

    ReplyDelete
  26. It would be a property on a node. See http://dev.day.com/docs/en/crx/current/administering/user_group_ac_admin.html.

    ReplyDelete
  27. Hi Scott,

    I want to execute SQL2 query from external java application by connecting Adobe CQ.

    Could you please give me some sample example for that.

    Regards,
    B.Sathishkumar

    ReplyDelete
    Replies
    1. See this article:

      http://scottsdigitalcommunity.blogspot.ca/2013/11/developing-java-swing-application-that.html

      Delete
  28. Hi Scott,

    We have a use case where in we have multiple sites on the cq authoring environment. Users & Group are created to take care of the Authoring of the content, review by another group and then publish and it works fine.

    For one of the site we need to do some change in the workflow wherein users in the group need to approve the content created/updated by other users of the group i.e. same user should not be able to create/update the content and publish it. It should be reviewed by other users in the group and only after approval, it will be published.

    I am looking for best practices for implementing this and how can we customize the workflow. Example would be extremely helpful

    ReplyDelete
    Replies
    1. This would be a good use case to base a workflow article on. I will add this to our community article list. Thank you for your input.

      Delete
  29. This post is very Intersting and beautiful blog lovely presentation thanks for sharing your views.....
    thanks for sharing....
    You can also read Adobe Technical Support my site.




    ReplyDelete
  30. This comment has been removed by a blog administrator.

    ReplyDelete
  31. Hello scott ,

    Is it possible to copy xls sheet data into cq5? if yes can you please help me how is it possible.

    Thanks,
    Kumar.

    ReplyDelete
    Replies
    1. You can create a Sling Servlet to upload the xls file and place it in the AEM Repository. See this artilce .

      http://scottsdigitalcommunity.blogspot.ca/2013/07/uploading-files-to-adobe-experience.html

      You can even go one step further and create an AME service to accept the Excel file and read the data from it. See this article:

      http://scottsdigitalcommunity.blogspot.ca/2013/08/creating-custom-excel-service-for-adobe.html

      Delete
  32. Hi Scott, how can I connect to an author instance (from external system) and get an XML file rendered through a selector? For example I want to get to this file:
    http://localhost:4502/content/geometrixx/en/company/management.myXMLRenderer.xml
    The goal is to get the entire XML string and then use JAXB or similar to extract the information that I need.

    ReplyDelete