Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

This page lists a series of common questions and answers. It is of course work in progress ...

Note
titleThis page is *not* meant for asking questions

Use the Sling users mailing lists for that, see http://sling.apache.org/project-information.html#mailing-lists - this page is about answers. Thanks!

If you find anything wrong in the Sling site or in and on the Wiki, do not hesitate to also contact the user's mailing list. Thanks.

Table of Contents
minLevel2
maxLevel3

...

Code Block
curl -F"greetings=Hello, World!" -F"multmulti=first" -F"multi=second" -F"translations/en=Hello" -F"translations/zh=你好" http://admin:admin@localhost:8080/content/../../..

...

Now you should be able to see an HTML version of the resource at http://localhost.local:8080/content/greet. This script matches the sling:resourceType we set and the HTTP method we used. Note that resourceType matches must be exact.

How

...

do I create a multi-value property with a single value, in HTTP?

Use this:

Code Block
curl -u admin:admin -F'foo=bar' -F'foo@TypeHint=String[]' http://localhost:8080/some/path

The TypeHint tells the Sling POST servlet to create a multi-value property for foo.

Scripts and Servlets

How do I generate links to previous versions of a node?

Assuming a versionable node at /content/versioned, with sling:resourceType=foo, here's the /apps/foo/html.esp script that handles the /content/versioned.html request:

Code Block

<html>

<%
// assume we have a versionable node
var iter = currentNode.getVersionHistory().getAllVersions();
%>

  <body>
    <h1>Versions of node <%= currentNode.getPath() %></h1>
    <%
    	while(iter.hasNext()) {
    	  var v = iter.nextVersion();

    	  // use UUID of version node to build a link, and add a .version
    	  // selector to have another esp script process that request
    	  var uuid = v["jcr:uuid"];
    	  var vPath = currentNode.getPath() + ".version." + uuid + ".html";

    	  // Use Version creation date as the link text
    	  var vDate = v.getCreated().getTime();

    	  %>
    	  <a href="<%= vPath %>"><%= vDate %></a><br/>
    	  <%
    	}
    %>
  </body>
</html>

The links to the individual versions look like: /content/versioned.version.313016e1.html where the first .version. selector causes a different esp script to be called to display the version data, and the 313016e1 selector is the UUID of the versioned node (real UUIDs are longer).

I cannot add a node under /content/config.author using a POST, the new node goes under /content/config

That happens if both the /content/config.author and /content/config nodes exist, and you do something like:

Code Block

$ curl -F try=first -u admin:admin http://localhost:8080/content/config.author/underauthor

The underauthor node goes under /content/config in that case, as Sling finds a resource at that path and considers .author as an extension or selector.

This is inherent to the way Sling matches URL paths to resources - to work around that, use

Code Block

$ curl -F underauthor/try=second -F "underauthor/jcr:primaryType=sling:Folder" -u admin:admin http://localhost:8080/content/config.author

Which correctly creates the underauthor node under /content/config.author. You can of course add more properties to the request, like -F underauthor/jcr:primaryType if needed.

Here's the resulting content of our example (including specifying the jcr:primaryType):

Code Block

$ curl http://localhost:8080/content.tidy.5.json
{
  "jcr:primaryType": "nt:unstructured",
  "config.author": {
    "foo": "bar",
    "jcr:primaryType": "nt:unstructured",
    "underauthor": {
      "try": "second",
      "jcr:createdBy": "admin",
      "jcr:created": "Fri Jan 25 2013 17:35:18 GMT+0100",
      "jcr:primaryType": "sling:Folder"
    }
  },
  "config": {
    "foo": "bar",
    "jcr:primaryType": "nt:unstructured",
    "underauthor": {
      "try": "first",
      "jcr:primaryType": "nt:unstructured"
    }
  }
}

Scripts and Servlets

How do I generate links to previous versions of a node?

Assuming a versionable node at /content/versioned, with sling:resourceType=foo, here's the /apps/foo/html.esp script that handles the /content/versioned.html requestThat request is handled by this second script, /apps/foo/version/html.esp (name will change soon, SLING-387):

Code Block
<html>

<%
	// Getassume versionwe nodehave UUID,a which is the second selector
	versionable node
var uuiditer = null;
	var sel = request.getRequestPathInfocurrentNode.getVersionHistory().getSelectorsgetAllVersions();
	if(sel.length >= 2) {
		uuid = sel[1];
	} else {
		response.sendError(400, "Version node UUID must be given as second selector");
	}

	// Get version node
	%>

  <body>
    <h1>Versions of node <%= currentNode.getPath() %></h1>
    <%
    	while(iter.hasNext()) {
    	  var v = currentNodeiter.getSessionnextVersion().getNodeByUUID(uuid);

    	var  frozen// = v.getNode("jcr:frozenNode");
	var title = frozen.title;
%>

  <body>
    <h1>Version of node <%= currentNode.getPath() %></h1>use UUID of version node to build a link, and add a .version
    Name: <b><%= v.getName() %></b><br/>
    UUID: <b><%= uuid %></b><br/>	  // selector to have another esp script process that request
    Path: <b><%= v.getPath() %></b><br/>	  var uuid = v["jcr:uuid"];
    Frozen	  nodevar path:vPath <b><%= frozencurrentNode.getPath() %></b><br/>

    <% if(title) { %>
	    Frozen node title: <b><%= frozen.getProperty("title") %></b><br/>
    <% } else { + ".version." + uuid + ".html";

    	  // Use Version creation date as the link text
    	  var vDate = v.getCreated().getTime();

    	  %>
    	Frozen node does not have a title property<a href="<%= vPath %>"><%= vDate %></a><br/>
    	  <%
    	}
    %>
  </body>
</html>

Which uses the UUID selector to retrieve the versioned node.

The second trick here is that the versioned data is saved as a "jcr:frozenNode" node under the Version node. This is explained for example at http://www.onjava.com/lpt/a/6784 .

How do I find out why a given script or servlet is preferred to another when processing a request?

The links to the individual versions look like: /content/versioned.version.313016e1.html where the first .version. selector causes a different esp script to be called to display the version data, and the 313016e1 selector is the UUID of the versioned node (real UUIDs are longer).

That request is handled by this second script, /apps/foo/version/html.esp (name will change soon, SLING-387):

Code Block

<html>

<%
	// Get version node UUID, which is the second selector
	var uuid = null;
	var sel = request.getRequestPathInfo().getSelectors();
	if(sel.length >= 2) {
		uuid = sel[1];
	} else {
		response.sendError(400, "Version node UUID must be given as second selector");
	}

	// Get version node
	var v = currentNode.getSession().getNodeByUUID(uuid);
	var frozen = v.getNode("jcr:frozenNode");
	var title = frozen.title;
%>

  <body>
    <h1>Version of node <%= currentNode.getPath() %></h1>
    Name: <b><%= v.getName() %></b><br/>
    UUID: <b><%= uuid %></b><br/>
    Path: <b><%= v.getPath() %></b><br/>
    Frozen node path: <b><%= frozen.getPath() %></b><br/>

    <% if(title) { %>
	    Frozen node title: <b><%= frozen.getProperty("title") %></b><br/>
    <% } else { %>
    	Frozen node does not have a title property
    <% } %>
  </body>
</html>

Which uses the UUID selector to retrieve the versioned node.

The second trick here is that the versioned data is saved as a "jcr:frozenNode" node under the Version node. This is explained for example at http://www.onjava.com/lpt/a/6784 .

How do I find out why a given script or servlet is preferred to another when processing a request?

See SLING-580, the SlingServletResolver class logs detailed information See SLING-580, the SlingServletResolver class logs detailed information (at the DEBUG level) to indicate in which order the candidate scripts and servlets are considered for processing a request.

...

1. In this approach, instead of deploying a system.bundle extension fragment, you package all the shared jars in an OSGI bundle and export all the shared packages from that bundle.
2. This seems to resolve classes only in JSPs in sling but fails in Sling servlets with ClassCastException.
The reason for this is as following.
Weblogic uses context classloader of the thread to resolve classes while deserializing session objects. When JSP is processed in Sling, the context classloader is set to in Sling, the context classloader is set to org.apache.sling.commons.classloader.impl.ClassLoaderFacade
This classloader can find all the classes ex ported from OSGI bundles loaded in felix.
So, when session attributes are accessed from migrated JSPs in Sling, the objects used to get serialized, and then deserialized. While deserializing, the classes were resolved by org.apache.sling.commons.classloader.impl.ClassLoaderFacade
This classloader can find all the classes ex ported from OSGI bundles loaded in felix.
So, when session attributes are accessed from migrated JSPs in CQ, the objects used to get serialized, and then deserialized. While deserializing, the classes were resolved by org.apache.sling.commons.classloader.impl.ClassLoaderFacade.

Even if it appeared to work fine, this is not the right solution for the problem at all. The worst part here is that, once the object is deserialized, weblogic replaces original object reference to the deserialized object. So if any other WAR needs the object again, it needs to be serialized/deserialized again. But that works only if original object is loaded with weblogic classloader. So once object is serialized/deserialized with Sling classloader, it will never be serialized/deserialized for other WARs and you will always get ClassCastException. e.g. If CustomerDetailVO is once accessed from CQ JSP component, any other WAR, like OnlineCustomerDetail.war, trying to get CustomerDetailVO from session will get ClassCastException. This happens because, when CustomerDetailVO is accessed by CQ component JSP, it is serialized/deserialized and resolved using org.apache.sling.commons.classloader.impl.ClassLoaderFacade. If its accessed in any other WAR after that, it will not be serialized again and we will get ClassCastException.

It did not work with Sling Servlets because, when servlet is executed, the context classloader is weblogic.utils.classloaders.ChangeAwareClassLoader. This classloader finds classes in EAR or classpath, so we get ClassCastException. Even here, some weblogic classloader magic is going on. The context classloader here, is the classloader for launchpad.war. This is the WAR file for CQ. The classes referred by servlet can not be loaded by this classloader, because classes exported from OSGI bundles are not visible to this classloader. So welogic, seeing the ClassNotFoundException from context classloader, uses the WAR classloader of the WAR which set the object in the session. Obviously, we get ClassCastException in the sling servlet.

So class/session sharing should never be done with classes packaged
and exported in an OSGI bundle. Relying on weblogic to serialize and
deserialize is always likely to fail.

System fragment extensions is the only safer approach in this case.

Miscellaneous

Why can't I connect to Sling's WebDAV using Windows NetworkDriveMapping ?

Since Windows XP SP 2 (thus also affects Windows Vista, Windows 7, etc.) support for HTTP Basic authentication is by default switched off unless using HTTPS. Support can be switched on again by setting a Windows registry value. See Microsoft Knowledge Base entry 841215 for full details and warnings regarding modifying registry entries.

Why is my WebDAV connection so slow on Windows ?

...

.

Even if it appeared to work fine, this is not the right solution for the problem at all. The worst part here is that, once the object is deserialized, weblogic replaces original object reference to the deserialized object. So if any other WAR needs the object again, it needs to be serialized/deserialized again. But that works only if original object is loaded with weblogic classloader. So once object is serialized/deserialized with Sling classloader, it will never be serialized/deserialized for other WARs and you will always get ClassCastException.

It did not work with Sling Servlets because, when servlet is executed, the context classloader is weblogic.utils.classloaders.ChangeAwareClassLoader. This classloader finds classes in EAR or classpath, so we get ClassCastException. Even here, some weblogic classloader magic is going on. The context classloader here, is the classloader for launchpad.war. This is the WAR file for Sling. The classes referred by servlet can not be loaded by this classloader, because classes exported from OSGI bundles are not visible to this classloader. So welogic, seeing the ClassNotFoundException from context classloader, uses the WAR classloader of the WAR which set the object in the session. Obviously, we get ClassCastException in the sling servlet.

So class/session sharing should never be done with classes packaged
and exported in an OSGI bundle. Relying on weblogic to serialize and
deserialize is always likely to fail.

System fragment extensions is the only safer approach in this case.

Miscellaneous

Why can't I connect to Sling's WebDAV using Windows NetworkDriveMapping ?

Since Windows XP SP 2 (thus also affects Windows Vista, Windows 7, etc.) support for HTTP Basic authentication is by default switched off unless using HTTPS. Support can be switched on again by setting a Windows registry value. See Microsoft Knowledge Base entry 841215 for full details and warnings regarding modifying registry entries.

Why is my WebDAV connection so slow on Windows ?

One reason might be automatic proxy detection being enabled in the Internet Options. See the Fix Slow WebDAV Performance in Windows 7 for the solution.

Why should I use the sling:Folder node type instead of nt:folder ?

As you can see in the folder.cnd file (in CND notation), sling:Folder inherits from nt:folder and in addition allows any single or multi-valued property, and any child node with sling:Folder as the default child node type. The nt:folder node type is much more restrictive.

In general, using sling:Folder is recommended, as it's more flexible.

How to change the service.ranking of a service through configuration?

This is possible even if that property is not exposed in the configuration admin (either if the service is not a meta type or if the property is private). You can use jcrinstall to configure services by placing the configuration inside a config folder, for example /apps/myapp/config/<myservice-pid>.<extension> (extension depends on the config format). Note that "service.ranking" must be an Integer property, which you need to explicitly specify. This is currently only possible if you use the properties file format (see SLING-2477 for more).

For example, to make a service named "com.foo.app.impl.MyServiceImpl" have a ranking of 1234:

  • create a file /apps/myapp/config/com.foo.app.impl.MyServiceImpl.config
  • contents must be one line: service.ranking=I"1234" (I stands for Integer)