Showing posts with label Resource Resolver. Show all posts
Showing posts with label Resource Resolver. Show all posts

October 13, 2020
Estimated Post Reading Time ~

Getting Resource Resolver in Sling Model

For getting the node properties we need the resourceResolver. To get resource resolver we generally use SlingHttpServletRequest. But if we are using Resource.class and SlingHttpServletRequest in @Model annotation then we don’t get the other injected values from the dialog.

So following is the method through which we can use Resource.class and as well as get the resource resolver.

We just to need to add @Source(“sling-object”) while injecting resource Resolver.

Following is the implemented code and highlighted are the key points to keep in mind.

@Model(adaptables = { Resource.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)

public class CheckoutModel extends AbstractComponentModel {

private static final Logger logger = LoggerFactory.getLogger(CheckoutModel.class);

/** The Constant serialVersionUID. */

private static final long serialVersionUID = -2053795867922610987L;
private String seoURL;

@Inject
@Source("sling-object")
private ResourceResolver resourceResolver;

public String getCartSeoUrl() {
return getSeoUrl(ApplicationConstants.CART_SEO_URL);
}

public String getLogoOnSeoUrl() {
return getSeoUrl(ApplicationConstants.LOGON_SEO_URL);
}

@JsonIgnore
public String getSeoUrl(String path) {
Node node = null;
Resource res = resourceResolver.getResource(path);
if (res != null) {
node = res.adaptTo(Node.class);
}

try {
if (node != null && node.hasProperty(ApplicationConstants.SEO_URL_KEY)) {
seoURL = node.getProperty(ApplicationConstants.SEO_URL_KEY).getValue().toString();
}

} catch (ValueFormatException e) {
logger.error("Inside Value Format", e);
} catch (PathNotFoundException e) {
logger.error("Inside Path NOt Found", e);
} catch (RepositoryException e) {
logger.error("Inside Repository Exception", e);
}

return seoURL;

}
}


By aem4beginner

September 19, 2020
Estimated Post Reading Time ~

How to create a session from resourceResolver objects?

Sometimes we need a session to work with some special JCR API which we can,t use with the help of resourceResolver then we can create an instance of a session in the same class file using the object of resourceResolver. Below is the code snippet.

First, we need to inject the ResourceResolverFactory interface to create a new resourceResolver in AEM. You could inject using the SCR annotation @Reference or Sling Model annotation @Inject.

@Reference

private ResourceResolverFactory resolverFactory;

Now create the ResourceResolver object using resourceResolverFactory. This line of code will create a rsourceResolver with administrator login.

ResourceResolver resourceResolver=resolverFactory.getServiceResourceResolver(null);

Now will create the instance of Session using the object of resourceResolver.

Session session = resourceResolver.adaptTo(Session.class);



By aem4beginner

May 26, 2020
Estimated Post Reading Time ~

ResourceResolver Object in AEM 6.1/6.0 Sling Services

In this article, we’ll discuss eight related questions around ResourceResolver Object in AEM 6.0 or 6.1 Sling services that most developers working on this technology will also have.

As we know, getAdministrativeResourceResolver() method has been deprecated from the ResourceResolverFactory interface in AEM6 and above versions. This brings up many questions in the minds of stakeholders, especially developers, involved in AEM projects. I’ve discussed some of those questions and provided answers to them.

Q1) How to get ResourceResolver object in Sling services in AEM6.0 and above versions?
If you are working with AEM6 or AEM6.1, then you have two options to get a ResourceResolver object.
If you know the credentials of a user and want that user credential in your service, then go with the getResourceResolver() method.

Map<String, Object> param = new HashMap<String, Object>();            
param.put(ResourceResolverFactory.USER,"admin");
param.put(ResourceResolverFactory.PASSWORD,"admin".toCharArray());
try {
      resourceResolver = resourceResolverFactory.getResourceResolver(param);
}catch (Exception e){
      System.out.println(e.getMessage());
}

If you don’t have user credentials and want to access ResourceResolver object, then you have to use getServiceResourceResolver() method as shown below

Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE,"testService");
try {
    resourceResolver = resourceResolverFactory.getServiceResourceResolver(param);
}catch (Exception e){
    System.out.println(e.getMessage());
}

Note: In this case you have to add a configuration in the Felix Console of your AEM instance.

Q2) What configuration do I need to make for AEM6.0?
For AEM6.0, the configuration steps are –
Go to Felix Console configuration tab i.e. http://<host>:<port>/system/console/configMgr
Search for User Mapping as shown in figure-

Click on this service to edit its configuration.
Here you have to add one entry and the syntax of the entry is –
“Bundle symbolic Name”:”SubServieName”=” User Name”

1. “Bundle symbolic Name”:- Here you have to add the bundle symbolic name where you are creating service.
2. “SubServiceName”:- This is the name you provided as a value of ResourceResolverFactory.SUBSERVICE property i.e. “testService”.
3. “User Name”:- This is the user name for ex. “admin”So in my case this configuration field value becomes “com.blog.blog-bundles:testService=admin”
After adding this entry, your configuration looks like

Now everything is set for AEM6.0

Q3) Will these configurations work for AEM6.1?
No.

Q4) What extra configuration do I need for AEM6.1?
If you are working with AEM6.1, then you have to complete all the steps explained for AEM6.0. Then, to make these configurations working for AEM6.1, you have to ensure that the “jcr:PrimaryType” of your user is “rep:SystemUser” i.e if you are trying to use “admin” user. Then it will not work as its “jcr:PrimaryType” value is “rep:User”
Q5) What do you mean by “jcr:PrimaryType” as “rep:SystemUser”?
It means that the user is just not a repository user. It must be a system user.

Q6) How to create a System User in AEM6.0?
To create a System User, follow these steps-
Go to CRX Explorer http://<host>:<port>/crx/explorer/index.jsp
Log in as Administrator i.e. using “admin:admin”
Click on “User Administration”, you will see a screen just like this

Here you will see the option of “Create System User.” Click on this button.
Add a value for User Id field for ex. “testUser”
Click on the green button.
Close the window.
Go to CRXDE Lite, your “testUser” will be created under /home/system directory. If you are not able to find it, then search for “testUser” in the home screen. You will get the location.

Q7) How to use this user?
In your “Apache Sling Service User Mapper Service,” the configuration changes your entry from –
com.blog.blog-bundles:testService=admin to com.blog.blog-bundles:testService=testUser

Q8) Should I do this configuration at the “Apache Sling Service User Mapper Service” configuration or should I create an “Apache Sling Service User Mapper Service Amendment” service configuration?
You can do it both ways. However, as “Apache Sling Service User Mapper Service” is a service factory in AEM6.1 so as to best practices you should create another service configuration by clicking on the plus button in front of the “Apache Sling Service User Mapper Service Amendment”.

When you click on the + button, one new configuration will be created at the end. Click on that service and do this configuration there. Your code will work in the same manner as before.


By aem4beginner

May 20, 2020
Estimated Post Reading Time ~

Programmatically find the Sling Resource from a Given a URL

In CQ, ResourceResolver class can be used for resolving a Request into a Sling Resource. However, given a random URL served by a CQ instance, how do you figure out the corresponding Sling Resource of the given URL as a result of Resource Mapping definition?

Let's assume we have some Resource Mapping rules (mapping definition) set up on our Author node via /etc/map so that a sample request to,

URL: http://dictionary.mycompany.com/definition/visa-validity.html

will be served by the resource at,

Sling Resource: /content/public/dictionary/legal-terms/v/visa-validity.html

You can have as many Resource Mapping rules (mapping definition) as you want. The above mapping is just an example. I want to use this example to demonstrate how did I programmatically figure out the corresponding resource from a given URL.

ResourceResolver

ResourceResolver class was implemented to return Resource. Specifically, the resolve() functions exist for this type of resolution. However, even there are three overloaded resolve() functions, none of them takes in a URL String.

Resource resolve(HttpServletRequest request)
Deprecated. as of 2.0.4, use resolve(HttpServletRequest, String) instead.

Resource resolve(HttpServletRequest request, String absPath)
Resolves the resource from the given absPath optionally taking HttpServletRequest into account, such as the value of the Host request header.

Resource resolve(String absPath)
Resolves the resource from the given absolute path.

The thought process
Given ResourceResolver takes in HttpServletRequest as input, if I can transform (adapt) a given URL into a HttpServletRequest using HttpServletRequestWrapper, the problem will be solved. Therefore, I implemented a ResolverRequest class which extends HttpServletRequestWrapper.

Code Sample:
package com.company.util.http;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;

public class ResolverRequest extends HttpServletRequestWrapper {

private final URI uri;

public ResolverRequest(HttpServletRequest request, String uriString)
throws URIException {
super(request);
uri = new URI(uriString, false);
}

@Override
public String getScheme() {
return uri.getScheme();
}
@Override
public String getServerName() {
try {
return uri.getHost();
} catch (URIException ue) {
return null;
}
}

@Override
public int getServerPort() {
return uri.getPort();
}

@Override
public String getPathInfo() {
try {
return uri.getPath();
} catch (URIException ue) {
return "";
}
}
}

Once you have ResolverRequest class implemented and available to you, you can construct a ResolverRequest from an URL string, and pass the ResolverRequest into resolve() function of ResourceResolver to find the Resource. Problem solved:

<?xml version="1.0" encoding="UTF-8"?>
<%@page session="false"
content
pageEncoding="utf-8"
import="org.apache.sling.api.request.*,
com.company.util.http.ResolverRequest" %>
<%@include file="/libs/foundation/global.jsp" %>
<cq:defineObjects/>

<%
RequestParameter url_request_param = slingRequest.getRequestParameter("url"); // 1
pageContext.setAttribute("url_request_param", url_request_param);
%>

<result>
<c:choose>
<c:when test="${url_request_param == null}">
<error>
url parameter needed!
</error>
</c:when>

<c:otherwise>
<%
HttpServletRequest wrappedRequest = new ResolverRequest(request, url_request_param.getString());
Resource r = resourceResolver.resolve(wrappedRequest, wrappedRequest.getPathInfo());
%>

<%=r.getPath() %>

</c:otherwise>
</c:choose>
</result>

Get the value of url parameter from the request (e.g., "http://localhost:4502/apps/company/tools/dispatcher/invalidate?url=http://dictionary.mycompany.com/definition/visa-validity.html")



By aem4beginner

May 19, 2020
Estimated Post Reading Time ~

What is Apache Sling and how it makes AEM a great CMS

CQ5 (AEM) is a brilliant content management system. It's different from the rest of the herd because of the framework it's built on, i.e Sling and its repository system (JCR).

Websites have a tree structure, but in traditional CMS pages are just rows in an RDBMS table and child pages are not really child pages. They just have a special entry to tell which is the parent page. Not in cq5, pages are nodes and child pages are nodes under the parent page, this makes so much sense as a developer to visualize a website. This also leads to url's that make sense, no ugly urls with post id's or content id's as parameters. All this is possible because of Sling.

Sling is a web framework built to be used with JCR as a data store. Sling is built on REST principles. It's the JCR and REST that make Sling a match made in heaven for content management systems.

So whats REST?? I won't enlist the REST principles, there are too many articles out there on REST. From a content management point, it means every atomic object of data on your website is a resource, something that can be rendered on it's own. What this means is every page is a resource. Not just the page, the images in it are resources too. So is the slider, navigation, and the page body. You get to control how fine the resources are, i.e the title could be a resource or it can be a part of the page resource. The bottom line is data has to be a resource.

The url tells what resource you're looking for. The url can select a page or the slider on the page. The reason you get to have such urls is because of JCR (Java content repository), unlike a traditional RDBMS there are no tables and rows. The JCR is a tree, similar to your file system. They have nodes starting from the root. So your page is node. Under it lie the child pages as child nodes. Apart from the child pages they also have a content node under which the resources of the page (the sliders, page body) are stored as nodes.[You can create a similar effect with traditional RDBMS tables too using apis like web api of asp.net with entity framework or Jersey api in java. It isn't still as clear as JCR ]

Now that the url uniquely identifies a resource, next rule is that a GET request to the resource returns a representation of the resource (i.e GET to an image returns an image and its rendered by the browser, GET to a page node returns html to be rendered by the browser). You cannot update the values or delete them in a GET call. Now the page node only has data not the HTML. How does a GET request to page return HTML?? Actually there is no hard and fast rule telling a page should return HTML on a GET. It can return JSON or XML or anything of your choice. What happens on GET to an URL is, the url identifies the resource then the data in the resource is processed by the system (a script renders the node) and returns the value. The GET is not returning the resource, it returning a representation of the resource. So who decides which script renders the node ?? In sling the ResourceResolver does, any GET call to a resource is taken over by it and it uses a script to render the resource. A resource can be rendered by multiple scripts, the script is a resource too. So a resource tells which resource will render it. In a sling, it's done by sling:resourceType property. This property identifies who will render the resource. There can be multiple scripts for a resourceType, one among them is chosen based on the rules of resource resolution.

[It is this feature that is leveraged to create templates in cq5, you tell which script renders a template. Any page created using the template gets the sling:resourceType value you defined for the template added to it on creation. It is for this reason that when you change resourceType for a template , the pages already created out of it before the change don't reflect it.]

A post to a resource updates the resource(even create one if there is no resource at the url). The parameters in the post request are stored as name-value pairs on the node. How does this happen ? Any post request is intercepted by Sling's default POST servlet and it cycles through the parameters and stores them. You will need to have appropriate rights to do a POST to a resource else the request gets denied.

[This is the backbone behind content authoring in sling, the dialogs you see in the authoring interface are forms. On hitting OK they do a post to the node instantly updating the values. (keep your firebug console ON and edit a dialog) ] So this behavior of GET and POST in Sling makes it perfect for content management.

Now you know how Sling is leveraged in CQ5 let's see how it's all put together. Every component you create is a resource. The data needed to display it is stored as name-value pairs on the node. So if you made a GET request all the way until the components node you will set it just returns the output of your component's JSP.

So why is a GET to a page returning the output of all the components on it?? The answer is cq:include and Parsys. You include components using cq:include or parsys. So when a request comes along to the page the cq:include includes response from the components within the response of the page (the response of the node at the path you mentioned in the directive is retrieved and the node [resource] is rendered by the resourceType you mentioned in the directive ). Parsys is cq included too. So when you drag and drop a component on it , it actually creates a node for the component under it. when a request for the page comes along, the script of the parsys is invoked which in turn includes responses of nodes under it. A huge servlet chaining process underneath but works like a charm for content management.

Day Software (creators of cq5) designed the Sling framework especially for CQ5 and then made it open source by donating it to Apache. Sling is now an incubator project of Apache.


By aem4beginner

May 15, 2020
Estimated Post Reading Time ~

Resource Resolver Object in AEM6.x Service

As we know that getAdministrativeResourceResolver() method has been deprecated from ResourceResolverFactory interface in AEM6 and above versions. Then the question is-

Q1). How to get ResourceResolver object in Sling services in AEM6.0 and above versions?
If you are working with AEM6 or AEM6.1 then you have two options-
If you know the credentials of a User and want that user credential in your service, then go with getResourceResolver() method.

Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.USER,”admin”);
param.put(ResourceResolverFactory.PASSWORD,”admin”.toCharArray());
try {
resourceResolver = resourceResolverFactory.getResourceResolver(param);
}catch (Exception e){
System.out.println(e.getMessage());
}

If you don’t have user credentials and want to access ResourceResolver object then you have to use
getServiceResourceResolver() method. as shown below –

Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE,”testService”);
try {
resourceResolver = resourceResolverFactory.getServiceResourceResolver(param);
}catch (Exception e){
System.out.println(e.getMessage());
}

Note: – In this case you have to add a configuration in your Felix Console to your AEM instance.

Q2). What configuration I need to do for AEM6.0?
For AEM6.0, configuration steps are-
Go to Felix Console configuration tab i.e. http://localhost:4502/system/console/configMgr
Search for User Mapping as shown in figure-


Click on this service to edit it’s configuration.
Here you have to add one entry and the syntax of the entry is-

“Bundle symbolic Name”:”SubServieName”=”User Name”

1. Bundle symbolic Name:- Here you have to add the bundle symbolic name where you are creating a service.

2. SubServieNaem:- This is the name you provided as a value of ResourceResolverFactory.SUBSERVICE property i.e. “testService”.

3. User Name:- This is the user name for ex. “admin” So in my case this configuration field value becomes “com.blog.blog-bundles:testService=admin” After adding this entry to configuration looks like-


Now everything is set for AEM6.0.

Q3). Will these configurations work for AEM6.1?

No

Q4). What configuration, do I need for AEM6.1?

If you are working with AEM6.1 that you have to complete all steps explained for AEM6.0. To make these configurations working for AEM6.1, you have to ensure that the “jcr:PrimaryType” of your user is “rep:SystemUser” i.e if you are trying to use “admin” user. Then it will not work as it’s “jcr:PrimaryType” value is “rep:User”.

Q5). What do you mean by “jcr:PrimaryType” as “rep:SystemUser”?

It means that user is just not a repository user. It must be system user.

Q6). How to create System User in AEM6.0?

For creating System Users, follow these steps-



Go to CRX Explorer http://localhost:6502/crx/explorer/index.jsp
Login as Administrator, i.e. using “admin: admin”
Click on “User Administration”, you will see a screen just like this-
Here you will see a option of “Create System User”, Click on this button.
Add a value for User Id field for ex. “testUser“.
Click on green button. Close the window. Go to CRXDE Lite, your “testUser“ will be created under /home/system directory. If you are not able to find then search for “testUser“ in home screen. You will get the location.

Q7). How to use this user?

In your “Apache Sling Service User Mapper Service” configuration changes your entry from-
com.blog.blog-bundles:testService=admin to com.blog.blog-bundles:testService=testUser

Q8). Should I do this configuration at “Apache Sling Service User Mapper Service” configuration or should I create a “Apache Sling Service User Mapper Service Amendment” service configuration?
You can do it by both ways. But as “Apache Sling Service User Mapper Service” is a service factory in AEM6.1 so as best practices you should create another service configuration by clicking on plus button at the front of “Apache Sling Service User Mapper Service Amendment”.
When you click on “+” button, one new configuration will be created at the end. Click on that service and do this configuration there. Your code will work in the same manner as working before.


By aem4beginner

May 2, 2020
Estimated Post Reading Time ~

AEM OSGi service dive — Resource Resolver Factory

For day to day development the resource resolver factory service is probably the most commonly used, most critical OSGI service inside of AEM. Let’s take a look at the settings and go over what they do.


Resource Search Paths: If you have attended Adobe’s AEM or CQ5 developer training, they undoubtably told you that sling would look for components “First in /apps, then in /libs”. Well the truth is that sling will go down this list and look for resources by going through this list in order. Thus, things in /apps (unless specified using /libs at the beginning of the path) will be found first and that is why how that overlay works.

This can be helpful if, for some reason, you want to overlay something in /libs with a generic version of something (e.g. shared code you install on all projects) and then overlay again in /apps.

Still, I suggest leaving this setting alone. Many AEM developers are not aware of this configuration and can become confused if you change it.

Namespace Mangling: This is usually enabled by default. It replaces the “:” character in ‘jcr:content’ for instance with an _, and prefixes such items with another underscore. Thus, “jcr:content” becomes “_jcr_content”. As the description notes, this is because the colon character doesn’t get handled well in filenames or URLs on a number of systems. Even though it’s a valid character for a URL, it isn’t regularly a valid character in filenames which will cause issues for dispatcher down the line.

Allow Direct Mapping: This enabled (which it usually should be) injects a “org.apache.sling.jcr.resource.internal.helper.Mapping.DIRECT” object at the beginning of the mappings list, which supplies direct 1:1 url mapping according to the source. Note: even if you disable this, by default the property for URL Mappings (resource.resolver.mappings) is set to /-/, which is essentially the same as direct mapping. In general (for your own sanity in testing) you should leave this option on, especially if you are otherwise playing with URL mappings below.

Virtual URLS: Stored in a “org.apache.commons.collections.BidiMap” — I point this out because this is built into the system and a useful class to be aware of, allowing equally fast lookups for key->value or value->key. In this case, I’ve never really used this feature. The idea is to allow you to set up “fake” urls that get translated to “real” urls. NOTE: this is for URLs not paths. So a sample value would be

/my/vanity/url.html:/content/myproject/myhomepage.html

At this point, going to http://server/my/vanity/url.html would load the same thing as going to http://server/content/myproject/myhomepage.html

Because I haven’t used this much, I’m not sure how this setting responds to a multi-site install.

URL Mappings: Related to “Allow Direct Mappings” above — the resource resolver factory stores an internal array of Mapping objects. If allow Direct is set to true, it prefixes that mapping with one that is essentially identical to the “/:/” map that comes as default. A setting like “/content/myproject/home-page/:/” will inject /content/myproject/home-page as a prefix to all incoming requests. This can be useful for removing such path prefixes. Unfortunately, I’ve found it doesn’t play nice with everything. For instance, the ACS commons multifield widget will find things in the wrong location, etc. Mapping to “/” is the problem. It’s easier when you just shorten a prefix, e..g “/en/”, which as mapping against the root “/” path has a large range of possible conflicts and interactions.

Mapping Location: Defaults to /etc/map. Look at the documentation for sling mappings. This setting is used to have different mappings for author/publisher or different mappings for different environments, e.g. QA, Development, and Production servers.

Default Vanity Path Redirect Status: Defaults to “302”. When you have sling:redirect set to true on a resource with a sling:vanityPath set, the server will respond with this status code. Should be left alone. In recent projects, I’ve completely overridden the built-in redirect behavior to better handle SEO, server load, and caching. Using vanity redirects like this will prevent the dispatcher from caching the redirect path, resulting in extra server load. Thus, it’s better to detect this at the page level (without using sling:redirect at all) and output a JS-based redirect page using document.location.replace and setting a canonical URL — this also makes the back button work properly.

Enable Vanity Paths: Pretty self-explanatory. With this turned off, sling ignores the sling:vanityPath property. Internally, vanitypaths are added to a mapping table that is used by the resource resolver to do the mapping. If this is off, those paths are never added to the table, and thus not used for resource resolution.

Optimize alias resolution: Creates an internal cache of aliases, meaning that if a mapping is successful that result is cached to avoid as much computation in the future. But building the cache and updating it can also get expensive over time — but that’s extremely rare. This should almost always be left enabled.

Allowed Vanity Path Location: When sling looks for resources with sling:vanityPath set it only looks under the trees specified in this setting. By default, /apps/, /libs/, and /content/ are configured. If blank the whole repository is fair game.

Denied vanity path location: Overrides settings in the “allowed” setting. For instance, you can allow “/content/” but deny certain subpaths under /content using this setting — in fact, that’s the exact usage of the default “/content/usergenerated” setting.

Vanity Path Precedence: Normally, mappings that come from resources with a sling:vanityPath and mappings pulled from the sling mappings location are pulled into one big table and then sorted by the STRING LENGTH (craziness) of that mapping. This rather odd choice can result in some very bizarre behavior, especially fighting between vanity paths and mappings under /etc/map or your custom location. By enabling this setting, vanity paths take precedence. Defaults to false, I suggest setting it to true unless that causes you issues.


By aem4beginner

April 16, 2020
Estimated Post Reading Time ~

How to get ResourceResolver From ResourceResolverFactory

In AEM, sometimes there is a need for having resourceResolver in our java code. But if we are not using a servlet, means don’t have any request or resource initially then how can we get it?

The focus of this tutorial is to learn how we can get ResourceResolver from ResourceResolverFactory. ResourceResolverFactory provides us ResourceResolver object with the help of apache sling service user Mapper Amendment.

There are a lot of ways to get resourceResolver, but mainly we get ResourceResolver either by using request or Resource :
The syntax for getting ResourceResolver from Request object:
ResourceResolver resourceResolver=request.getResourceResolver();
The syntax for getting ResourceResolver from Resource object:
ResourceResolver resourceResolver= resource.getResourceResolver();
Steps to get ResourceResolver From ResourceResolverFactory:


First of all, open your Felix Console console and search for your project and get its symbolic name.


Go to the configuration of the Felix console.
Search for apache sling service user Mapper Amendment.
Click on the plus sign to add a new user mapper service.
Enter the below details.


The format of Service Mapping will be like this:
Symbolic Name of the project: SUBSERVICE =userName
Symbolic Name of the project: group-id-mobile.project-AEM-bundle
SUBSERVICE : getResourceResolver.
userName : testSystemUser

Note: Remember that the user you define here must be a system user. If it is a normal user aem 6.1 will not work for this. So you can create your own system user and provide the privilege to them according to your needs.

Now let’s try this in code:
Below servlet is trying to get resource from the ResourceResolver using ResourceResolverFactory

@Component(immediate = true, metatype = false, label = "Getting Resource Resolver")
@Service
@Properties(value = {
@Property(name = "sling.servlet.paths", value = "/bin/resource")
})
public class MyResourceResolver extends SlingSafeMethodsServlet {
@Reference ResourceResolverFactory resourceResolverFactory;

public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
try {

Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "getResourceResolver");
ResourceResolver resourceResolver = resourceResolverFactory.getServiceResourceResolver(param);
String path = resourceResolver.getResource("/apps/sling").getPath();
response.getWriter().write(path);
} catch (Exception e) {
e.printStackTrace();
response.getWriter().write(e.getMessage());
}
}
}


Hit the servlet i.e. localhost:4502/bin/resource and check the output.

In Addition to that,
Sometimes the servlet is not resolved, you can check it from here.
It will open Adobe Experience Manager Web Console Sling Servlet Resolver for checking your servlet path, whether it is resolving your servlet or not.



Please drop a comment, if you face any issue in implementing it.


By aem4beginner

April 10, 2020
Estimated Post Reading Time ~

Access Content Repository via getServiceResourceResolver() in AEM6/Sling7

JCR Sessions and Sling Based Authentication are always important in code where someone needs to get access to the Content Repository. But this same way to get access over content repository was remained controversial due to its administrative privileges. So with the new AEM6 version below methods have been deprecated to get access to admin sessions which can cause the security vulnerabilities :

1) ResourceResolverFactory.getAdministrativeResourceResolver
2) ResourceProviderFactory.getAdministrativeResourceProvider
3) SlingRepository.loginAdministrative

The latest release of Sling provides an alternative to access the repository without using admin session via Service-Based Authentication. In Service-Based authentication, each service will bind to a specific set of users which will have different access privileges. These users also refer to service users. Below is the implementation steps of service-based authentication.

Step 1: Create two users with different access privileges, gives one to read and others to read/write.
Step 2: Create two services which try to write some property inside the node:

WriteOpService
@Service
@Component(immediate = true)
public class WriteOpServiceImpl implements WriteOpService{

private final Logger logger = LoggerFactory.getLogger(WriteOpServiceImpl.class);

@Reference
private ResourceResolverFactory resolverFactory;

@Override
public void writePropToNode(String resourcePath) {

Map<String, Object> serviceParams = new HashMap<String, Object>();
serviceParams.put(ResourceResolverFactory.SUBSERVICE, "writeService");
ResourceResolver resolver = null;

try {
resolver = resolverFactory.getServiceResourceResolver(serviceParams);
logger.info(resolver.getUserID());
Resource res = resolver.getResource(resourcePath+"/jcr:content");
logger.info("Path is ::: "+res.getPath());
ModifiableValueMap modMap = res.adaptTo(ModifiableValueMap.class);

if(modMap != null){
modMap.put("propname", "propValue");
resolver.commit();
logger.info("Successfully saved");
}

} catch (Exception e) {
logger.error("Exceptions is ::: ",e);
}finally{
if(resolver != null){
resolver.close();
}
}
}

ReadOpService:

@Service
@Component(immediate = true)
public class ReadOpServiceImpl implements ReadOpService {
private final Logger logger = LoggerFactory.getLogger(ReadOpServiceImpl.class);

@Reference
private ResourceResolverFactory resolverFactory;
@Override
public void readPropFromNode(String resourcePatb) {
Map<String, Object> serviceParams = new HashMap<String, Object>();
serviceParams.put(ResourceResolverFactory.SUBSERVICE, "readService");
ResourceResolver resolver = null;
try {
resolver = resolverFactory.getServiceResourceResolver(serviceParams);
logger.info(resolver.getUserID());
Resource res = resolver.getResource(resourcePatb+"/jcr:content");
logger.info("Path is ::: "+res.getPath());
ModifiableValueMap modMap = res.adaptTo(ModifiableValueMap.class);
if(modMap != null){
modMap.put("propname", "propValue");
resolver.commit();
logger.info("Successfully saved");
}
} catch (Exception e) {
logger.error("Exceptions is ::: ",e);
}finally{
if(resolver != null){
resolver.close();
}
}
}

Step 3: Configure the Apache Sling Service User Mapper service via Felix Console as below:

Syntax will be : [bundle-symbolic-name]:[subServiceName]=[Service-User]

Step 4: Create some authoring stuff, in such a way we will pass the page path than on submit, property propname with value propValue will be set to the page.

Step 5: Below is the sample associated component script :
<%@include file="/libs/foundation/global.jsp"%>
<%@page session="false" %>
<% String prop = properties.get("pagePath","");

com.aem.services.WriteOpService writeOpService = sling.getService(com.aem.services.WriteOpService.class);

com.aem.services.ReadOpService readOpService = sling.getService(com.aem.services.ReadOpService.class);

//readOpService.readPropFromNode(prop);

writeOpService.writePropToNode(prop); %>

If we look both the services they are performing the write operation but in the success will depend on via which user you logged in & which operation you call, as different services are associated with different service users. Refer the below link for further information :
https://cwiki.apache.org/confluence/display/SLING/Service+Authentication


By aem4beginner

April 8, 2020
Estimated Post Reading Time ~

Which user is resolved when used ‘request.getResourceResolver()’ in AEM 6.3?

Question: When you are accessing the resource resolver from a sling request object, what user is this resolver mapped to?

Answer: If you do request.getResourceResolver(), the user is used of the current session. That is the recommended way, because the permissions are respected of the current user.

Source


By aem4beginner

Access to ResourceResolver in OSGi Services: AEM 6.1



We all know that from AEM 6.0, usage of Admin Session to access the ResourceResolver is deprecated which means we cannot use session = repository.loginAdministrative(null); anymore !

Instead, AEM comes with the concept of Service based authentication to get access to ResourceResolver.

Let us see how to create the Service Users and Use the same to get access to ResourceResolver in the OSGi service

Step1: Creating Service User Mapping
Go tohttp://<host>:<port>/system/console/configMgr
Search for ‘Apache Sling Service User Mapper Service’ and click on edit
Add an entry by clicking ‘+’
<bundleId>:<subServiceName> = <systemUserName>

Ex: org.test.core:readService=testreaduser
User Mapping Service

Step 2: Create a User Mapper Service Amendment
Add a new Amendment as shown below
User Mapping Service Amendment

If you are using multiple User Mapping for the same service, then the highest Ranking User will be used to authenticate the access for the ResourceResolver.

Step 3: Create the System User
In AEM 6.0, even the normal user could be used in mapping the service but from AEM 6.1 it is mandatory to use only the ‘System User’ in the Mapping.

Goto http://<host>:<port>/crx/explorer/index.jsp

Click on ‘User Administration’
CRX Explorer

Click on ‘Create System User’
User Administration

Add a userId ‘testreaduser’ and click the tick mark to create System User

Step 4: Permissions to the System User

Once you have created the system User, goto /useradmin
Select the user you created and click on the ‘Permission’ tab
Enable the ACLs accordingly and ‘Save’.
User Permission

Step 5: OSGi Service
Now you have successfully created the service users which can be used in your services to get access to ResourceResolver. Below is an example that shows how to use the service user to get https://www.acheterviagrafr24.com/viagra-online/ the access.

Create an Interface
package org.test.test.core.service;
public interface ReadService {
public void listTitles();
}

Create an Impl class
package org.test.test.core.service.impl;
import java.util.HashMap;
import java.util.Map;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.test.test.core.service.ReadService;
import com.day.cq.wcm.api.Page;
@Component(immediate = true) @Service public class ReadServiceImpl implements ReadService {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Reference private ResourceResolverFactory resourceFactory;
@Override @Activate public void listTitles() {
Map < String, Object > paramMap = new HashMap < String, Object > (); //Mention the subServiceName you had used in the User Mapping paramMap.put(ResourceResolverFactory.SUBSERVICE, "readService"); log.info("After the param"); ResourceResolver rr = null; try{ rr = resourceFactory.getServiceResourceResolver(paramMap); log.info("UserId : " + rr.getUserID()); Resource res = rr.getResource("/content/geometrixx"); log.info("Resource : " + res.getPath()); Page page = res.adaptTo(Page.class); log.info("page path : " + page.getPath()); log.info("page title : " + page.getTitle()); }catch(Exception e){ log.error(e.getMessage());
}
}
}

Once you install the bundle, you should be able to see the mentioned logs in your <project>.log file

This is slightly different from AEM 6.0 were in just having the UserMapping and the User would be sufficient to get access in ResourceResolver. In 6.1 it's changed a bit with Amendments and the compulsory of creating System User only to work.


By aem4beginner

April 3, 2020
Estimated Post Reading Time ~

Get Resource Resolver from session CQ5/AEM

Oddly, it is easy enough to get a resourceResolver from the session. // Below, is how you can do it.

public ResourceResolver getResourceResolverFromSession(final Session session, final ResourceResolverFactory resourceResolverFactory) {

try {
return resourceResolverFactory.getResourceResolver(Collections.singletonMap(“user.jcr.session”, (Object) session));
} catch (LoginException e) {
throw new IllegalStateException(e);
}
}



By aem4beginner

How to get an impersonated Resolver in CQ5/AEM?

It is very easy to get an impersonated resolver:

Try the below code. Just pass the user id and resourceResolverFactory instance.

private ResourceResolver getImpersonatedResolver(final String userId) {
try {
return resourceResolverFactory.getAdministrativeResourceResolver(Collections.singletonMap(ResourceResolverFactory.USER_IMPERSONATION, (Object) userId));
} catch (LoginException e) {
throw new RuntimeException(e);
}
}



By aem4beginner

April 1, 2020
Estimated Post Reading Time ~

How to Use Sessions and Resource Resolver through Service Authentication In AEM 6

Use Case: As per http://sling.apache.org/documentation/the-sling-engine/service-authentication.html and http://docs.adobe.com/content/docs/en/aem/6-0/develop/ref/diff-previous/changes/changes-summary.html using admin session and admin resource resolver through ResourceresolverFactory is now deprecated. Using Service based Authentication for Resourceresolver and Respository session solves problem like (Directly From Sling Doc),

Prevent over-use and abuse of administrative ResourceResolvers and/or JCR Sessions
Allow services access to ResourceResolvers and/or JCR Sessions without requiring to hard-code or configure passwords
Allow services to use service users which have been specially configured for service level access (as is usually done on unixish systems)
Allow administrators to configure the assignment of service users to services

Solution:
NOTE: Use Service Accounts for alice and bob users [jcr:primaryType=rep:SystemUser] instead of regular accounts.

Lets see we have two user "alice" and "bob", with following property,

"alice" only have READ access to document under /content/somepath path
"bob" has both read and write access to document under /content/somepath path
Now we have two service "ReadService" and "WriteService", with following property

ReadService should only be allowed to read anything under /content/somepath path
WriteService should be allowed for both read and write under /content/somepath path

Assume your package name is blog.aem4beginner.com
Step 1: Create ReadService and WriteService using resourceResolver Or adminSession using new Authentication Service based API

@Service
@Component(immediate=true)
public class WriteServiceImpl implements WriteService {

private final Logger log = LoggerFactory.getLogger(getClass());

@Reference
private ResourceResolverFactory resolverFactory;

//If you are planning to use repository session
//@Reference
//private SlingRespository repository;
//private Session session = null;

@Activate
public void doAWriteOperation(ComponentContext ctx) {
Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "writeService");
ResourceResolver resolver = null;
try {
//Deprecated Method using admin resolver
//resolver = resolverFactory.getAdministrativeResourceResolver(null);
resolver = resolverFactory.getServiceResourceResolver(param);
//If you are planning to use repository session instead of repository.loginAdministrative
//session = repository.getService("writeService",null);
log.info(resolver.getUserID());
Resource res = resolver.getResource("/content/somepath");
ValueMap readMap = res.getValueMap();
log.info(readMap.get("jcr:primaryType", ""));
ModifiableValueMap modMap = res.adaptTo(ModifiableValueMap.class);
if(modMap != null){
modMap.put("myKey", "myValue");
resolver.commit();
log.info("Successfully saved");
}
} catch (LoginException e) {
log.error("LoginException",e);
} catch (PersistenceException e) {
log.error("LoginException",e);
}finally{
if(resolver != null && resolver.isLive()){
resolver.close();
}
//Close session if you are using session
}
}
}

view rawWriteService.java hosted with ❤ by GitHubStep 2: Create ReadService same way


@Service
@Component(immediate=true)
public class ReadServiceImpl implements ReadService{

private final Logger log = LoggerFactory.getLogger(getClass());

@Reference
private ResourceResolverFactory resolverFactory;

//If you are planning to use repository session
//@Reference
//private SlingRespository repository;
//private Session session = null;

@Activate
public void doAReadOperation(ComponentContext ctx) {
Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "readService");
ResourceResolver resolver = null;
try {
//Deprecated Method using admin resolver
//resolver = resolverFactory.getAdministrativeResourceResolver(null);
resolver = resolverFactory.getServiceResourceResolver(param);
//If you are planning to use repository session instead of repository.loginAdministrative
//session = repository.getService("readService",null);
log.info(resolver.getUserID());
Resource res = resolver.getResource("/content/datatoreadandwrite/jcr:content");
ValueMap readMap = res.getValueMap();
log.info(readMap.get("jcr:primaryType", ""));
ModifiableValueMap modMap = res.adaptTo(ModifiableValueMap.class);
if(modMap != null){
modMap.put("myKey", "myValue");
resolver.commit();
log.info("Successfully saved");
}
} catch (LoginException e) {
log.error("LoginException",e);
} catch (PersistenceException e) {
log.error("LoginException",e);
}finally{
if(resolver != null && resolver.isLive()){
resolver.close();
}
//Close session if you are using session
}
}
}

view rawReadService.java hosted with ❤ by GitHubStep 3: Update org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl config by creating osgi:config node under /apps/<your-apps>/config.<Place where you want to run this>/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml you can directly go to osgi config through Felix console and change this as well look for “Apache Sling Service User Mapper Service” for that.



Syntax for service mapping to user is ‘serviceName [ ":" subServiceName ] “=” username’.
and Entry of OSGI config will look like this,

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
user.mapping="[com.adobe.granite.oauth.server=oauthservice,com.adobe.granite.oauth.server:authentication-handler=admin,com.day.cq.cq-search-suggest=suggestionservice,blog.
aem4beginner.com:writeService=bob, blog.aem4beginner.com:readService=alice]"/>


After installing the bundle and configuration and code, You would see something like this in log

*INFO* blog.
aem4beginner.com.ReadServiceImpl alice
*INFO* blog.
aem4beginner.com.ReadServiceImpl <node type of somepath>

*INFO* blog.
aem4beginner.com.WriteServiceImpl bob
*INFO* blog.
aem4beginner.com.WriteServiceImpl <node type of somepath>
*INFO* blog.
aem4beginner.com.WriteServiceImpl Successfully saved

If you need to use an admin session for the configuration you can do something like a blog.
aem4beginner.com:WriteService=admin in osgi config above. Good practice is to have these session based on groups depending upon which group have access to what service.

You might need following dependencies in your POM for API to be available

<dependency>
    <groupid>com.adobe.aem</groupid>
    <artifactid>aem-api</artifactid>    <version>6.0.0.1</version>    <scope>provided</scope>
</dependency>


Please check http://stackoverflow.com/questions/31350548/resourceresolverfactory-getserviceresourceresolver-throws-exception-in-aem-6-1 with some of the changes in AEM6.1 of how to use this.


By aem4beginner