Showing posts with label aem. Show all posts
Showing posts with label aem. Show all posts

Wednesday, 11 April 2018

Authenticating Web Console Users against the JCR Repository

Ever encountered a use case to provide users logged in to the JCR, access to the Felix Web Console?

The Apache Sling Web Console Security Provider bundle verifies user credentials and grants access to the Apache Felix Web console based on registered JCR repository users.

The following configuration is used to add users that have to be granted access:



User Names - The list of users granted access to web console.
Group Names - The list of groups whose members are granted access to the web console.

The default configuration explicitly grants the user 'admin' access to the felix web console.

If the web console security provider bundle is not activated, then the default web console authentication is used. 

Hope this helps!

Tuesday, 13 June 2017

extraClientlibs in AEM

To define styling and behavior of our AEM components, we create client libraries that defines our custom CSS and JS. In order to create clientlibs that load only in the Authoring mode, the general practice is to create a client library and load that only in the Author mode:

<sly data-sly-test.author="${wcmmode.edit || wcmmode.design}" 
data-sly-call="${clientlib.js @categories='custom.authorjs'}" /> </sly>

Further, if we want our client library loaded for all dialogs, we can set the category property to 'cq.authoring.dialog'. This would let the client library load for all dialogs.

This created performance issues sometimes when my client library is too big and I try loading it in all dialogs even when it is not needed. Sometimes, I would just want to have my client library only for a specific component's dialog.

To have my client library loaded solely for my component dialog, I need to the set the property 'extraClientLibs' of my dialog to the category name of the client library.

Here is an example:



Hope this helps!



Wednesday, 7 June 2017

Sling Pipes

Ever encountered a situation where code changes were introduced after the client started authoring and some pages had to be re-authored? Ever spent time writing code just to modify a few hundred pages that were already authored, or with removing a component from hundreds of authored pages? Have you struggled to modify content already in the repository? Need a script to change existing production content? Sling Pipes to the rescue.
Sling Pipes is a tool for doing extract – transform – load operations through a resource tree configuration. This tiny toolset provides the ability to do such transformations with proven and reusable blocks, called pipes, streaming resources from one to the other.
A pipe is a JCR node with:
  • sling:resourceType property – Must be a pipe type registered by the plumber
  • name property – Used in bindings as an id
  • path property – Defines pipe’s input
  • expr property – Expression through which the pipe will execute
  • additionalBinding node – Node you can add to set “global” bindings (property=value) in pipe execution
  • additionalScripts – Multivalue property to declare scripts that can be reused in expressions
  • conf child node – Contains addition configuration of the pipe

Registered Pipes:

Container Pipes
Pipe
Description
sling:resourceType
Container Pipe
assemble a sequence of pipes
slingPipes/container
ReferencePipe
execute the pipe referenced in path property
slingPipes/reference

Reader Pipes
Pipe
Description
sling:resourceType
Base Pipe
outputs what is in input
slingPipes/base
SlingQuery Pipe
executes $(getInput()).children(expression)
slingPipes/slingQuery
JsonPipe
feeds bindings with remote json
slingPipes/json
MultiPropertyPipe
iterates through values of input multi value property and write them to bindings
slingPipes/multiProperty
XPathPipe
retrieve resources resulting of an xpath query
slingPipes/xpath
AuthorizablePipe
retrieve authorizable resource corresponding to the id passed in expression
slingPipes/authorizable
ParentPipe
outputs the parent resource of input resource
slingPipes/parent
FilterPipe
outputs the input resource if its matches its configuration
slingPipes/filter

Writer Pipes
Pipe
Description
sling:resourceType
Write Pipe
writes given nodes & properties to current input
slingPipes/write
MovePipe
JCR move of current input to target path (can be a node or a property)
slingPipes/mv
RemovePipe
removes the input resource
slingPipes/rm
PathPipe
get or create path given in expression
slingPipes/path

Here is a demo video with more on how to use and execute sling pipes in AEM.

Vid
More details can be found in the official documentation at https://sling.apache.org/documentation/bundles/sling-pipes.html

Tuesday, 4 October 2016

adaptTo() 2016 - Day 3

The third and final day at adaptTo() 2016. Finally the grand finale!

Session Details:
  • Managing Cloud Performance and Large Data sets by Mike Tilburg and Tom Blackford
  • OSGi R7 by Carsten Ziegeler and David Bosschaert
  • Test-driven development with AEM by Jan Wloka
  • Introduction to Sling Pipes by Nicolas Peltier
  • AC tool by Jochen Koschorke and Roland Gruber
  • APM - AEM Permission Management by Mateusz ChromiÅ„ski
  • Using Thymeleaf for rendering HTML and Text in AEM 6.x by Oliver Lietz
  • Hey Sling, what are you doing? Sling Tracer to the rescue by Chetan Mehrotra
  • Apache Sling and Karaf for Web Sites and Applications by Oliver Lietz
Loved being a part of adaptTo() 2016!

Wednesday, 28 September 2016

adaptTo() 2016 Day 2

Another knowledgeable day at adaptTo() 2016 Berlin. The sessions started a bit early to accommodate all the speaker slots.

Sessions for Day 2:
  • How AEM Communities leverages and extends the power of Sling by Siddharth Palaniswami
  • Let’s run the whole Web on Apache Sling and Oak! by Bertrand Delacretaz and Chetan Mehrotra
  • Sling Http Testing Framework by Valentin Olteanu and Andrei Dulvac
  • Unit Testing with Sling & AEM Mocks by Stefan Seifert
  • Sling Context-Aware Configuration by Stefan Seifert
  • react components in AEM by Stefan Meyer
  • 0 to O(ak) in 30 by Davide Giannella
  • Playground Session featuring:
    1. Sling Core with Carsten Ziegeler & Stefan Seifert about Sling and OSGi in general 
    2. Sling Scripting with Rado Cotescu & Oliver Lietz about Sightly, Thymeleaf 
    3. DevOps with Bertrand Delacretaz & David Bosschaert & Georg Henzler about Sling/AEM Deployment and Automation 
    4. Tooling with Robert Munteanu & Oliver Lietz about Sling IDE, Karaf, Tools 
    5. Testing with Andrei Dulvac & Stefan Seifert about Integration Tests, Unit Tests, Sling Mocks
    6. JCR/Oak with Michael Dürig & Chetan Mehrotra about JCR and Oak
The playground session was indeed an amazing opportunity to get in touch with some of the great minds working on Sling, Oak, DevOps and JCR.

The event wrapped up with an awesome evening buffet and a round table conference for Sling developers.

What an eventful day indeed!

Tuesday, 27 September 2016

adaptTo() 2016 Day 1

2016 is the sixth edition of adaptTo() and this year's event is hosted at the Kulturbrauerei, Berlin, Germany.
The event primarily focuses on Apache Sling Framework, including Apache Jackrabbit and Apache Felix. Adobe Experience Manager Developers also benefit to a very high extent form this 3-day event since it covers details on how AEM is leveraging its underlying architecture.

Day 1 started with a lot of excitement. Developers and Attendees from different parts of the world gathered at the venue for this interactive community event.

Speakers got a red T-shirt and Attendees got a blue one!

Started with Opening notes from Carsten Ziegeler and Stefan Seifert followed by
  • Microservices and IoT with AEM by Carsten Zeigeler and David Bosschaert
  • Get The Flow by Conrad Wöltge and Dominik Süß
  • 5000+ unattended AEM installations in the last four years - is it DevOps? by Georg Henzler
  • Running AEM in Docker by Andrei Darashenka
  • HTL/Sightly Compilers and Tooling by Radu Cotescu
  • Sling IDE Tooling by Robert Munteanu
  • Integrating Apache Mahout with AEM by Rima Mittal and Ankit Gubrani - It was great to share our POC on the topic which can help various AEM clients with user based recommendations. Clone the code at Github.
  • Into the tar pit: a TarMK deep dive by Michael Dürig
  • Remote Resources by Vlad Bailescu











and this is how a knowledge filled Day 1 came to an end!

Looking forward to Day 2 at adaptTo() 2016!

Friday, 17 July 2015

Connecting AEM 6 with Microsoft SQL Server

Some old applications that you might want to migrate to AEM might still use SQL Server databases. Here are the steps to access an external SQL server from AEM 6:

Building the OSGI bundle for the JDBC driver:

1. Download the appropriate driver from here 
2. Unzip the downloaded driver.
3. Open eclipse indigo.
4. Click on File-> New -> Other -> Plugin from existing JAR archive 
5. Click on Add External and enter the path of the downloaded jar
6. Enter Plugin properties as shown here:
7. Observe the MANIFEST.MF, it shall look like this:
8. Save the project.
9. Right click the project --> Export --> Plug-in Development --> Deployable plug-ins and fragments
10. Choose a directory location --> Save.
11. The OSGI jar is available at the given-directory-location/plugins

Uploading the OSGI jar in felix:

1. Go to http://localhost:4502/system/console/bundles
2. Click on Install/Update
3. Upload the jar:
4. The jar should come in Active state. Look for errors in the error log if it still shows "Installed":
5. Error Log might show:
org.osgi.framework.BundleException: Unresolved constraint in bundle com.myproject.jdbc [398]: Unable to resolve 398.0: missing requirement [398.0] osgi.wiring.package; (&(osgi.wiring.package=javax.xml.transform.stream)(version>=1.3.0))
The bundle might also show unresolved dependencies:
6. Edit the MANIFEST.MF to remove the versions for resolving dependencies:
7. Re-install the bundle and it should be active now:


JDBC Connection Pool Factory config:

1. Go to http://localhost:4502/system/console/configMgr
2. click on "+" to add a configuration:
3. The configuration looks like this:





Test Connection:

1. An example code snippet for testing the connection:


Note: You might have to allow your Microsoft SQL server to accept remote connections! Please refer this

Hope this helps!!!






Monday, 18 May 2015

Hide extra component divs in CQ/AEM

This can be really tedious sometimes when, while developing a component in CQ/AEM, the extra CQ generated divs surrounding your component might disturb the HTML structure intended.

A common usecase is a carousel component in which, lets suppose, for every slide we drop in the carousel wrapper, no extra component div is required just to make sure the plugin driving the carousel runs fine.

An ideal structure would be :
<ul>
<li></li>
<li></li> 
<li></li>  
<li></li>
</ul>

If each li comes from a carousel slide component, here is what it looks like in cq:

<ul>
<div class="carousel-slide"><li></li</div>
<div class="carousel-slide"><li></li</div> 
<div class="carousel-slide"><li></li</div>  
<div class="carousel-slide"><li></li</div>
</ul>

This structure sometimes prevents the carousel JS plugins to stop behaving the way they should.

Solution:
One of the alternatives is to use cq:noDecoration="true", but that makes the component un-editable. Neither the editconfig not the dialog is visible.
Thus, an ideal approach would be :

Just before cq including the component, add this code snippet:

 <%
                        IncludeOptions opts = IncludeOptions.getOptions(request, true);
                        opts.setDecorationTagName("");

 %>
This would require an import:
<%@ page import="com.day.cq.wcm.api.components.IncludeOptions" %>

Now cq inlcude your component, for eg:

<cq:include path="slide"> resourceType="/component/content/carousel-slide"/>

Hope this helps! 

Friday, 27 February 2015

Hide a parsys in CQ edit mode

Often, a situation is encountered in CQ where we have a number of parsys on our page and it is required to show/hide some of them on certain events. A typical use case is that of a Tabbed Component where the parsys associated with a particular tab needs to be shown only on click of that particular tab while the parsys for all the other non active tabs should be hidden.
If my parsys is wrapped by a container div something like this.
<div class="genericTabContent"><cq:include path="par" resourceType="foundation/components/parsys" />
</div>
Then, calling the .hide() method on the div doesn't hide the parsys. Rather, the parsys is visible floating somewhere on the page making the authoring experience very tough.
parsys1
All attempts to hide the parsys through CSS seem to fail.
A possible solution is :
var parsysComp = CQ.WCM.getEditable("path to the parsys");
parsysComp.hide(); // makes the parsys visible
parsysComp.show(); // hides the parsys
To get the path to the parsys, the current node path can be fetched on our jsp page:
<div id="currentNodePath" class="${currentNode.path}"></div>
Once the current node path is known, this code snippet would work:
var parsysComp = CQ.WCM.getEditable(('#currentNodePath').attr('class')+"/par");
Hope this was helpful!

Wednesday, 26 November 2014

java.lang.VerifyError: Bad method call from inside of a branch

Ever encountered this kind of an error with no pages opening up in your cq instance?
Exception in thread "main" java.lang.VerifyError: Bad <init> method call from in
side of a branch
Exception Details:
  Location:
    com/myproject/server/MockWriter.<init>(Ljava/lang/S
tring;)V @71: invokespecial
  Reason:
    Error exists in the bytecode
  Bytecode:
    0000000: b800 164d 04bd 0018 5903 2b53 5910 ff12
    0000010: 04b8 001e 2a5f ab00 0000 0055 0000 0003
    0000020: aad3 b1ff 0000 0022 0000 9b75 0000 0037
    0000030: 60fa 8f17 0000 0040 5f5a 5903 3212 20b8
    0000040: 0024 c000 205f 57b7 0026 a700 2b5f 5a57
    0000050: b700 29a7 0022 5f5a 5903 3212 2bb8 0024
    0000060: c000 2b5f 57b7 002e a700 0dbb 0030 5912
    0000070: 32b7 0033 bf57 2ab6 0037 4e2d 2a5f b500
    0000080: 392d 57b1
  Stackmap Table:
    full_frame(@56,{UninitializedThis,Object[#32],Object[#63]},{Object[#65],Unin
itializedThis})
    full_frame(@77,{UninitializedThis,Object[#32],Object[#63]},{Object[#65],Unin
itializedThis})
    full_frame(@86,{UninitializedThis,Object[#32],Object[#63]},{Object[#65],Unin
itializedThis})
    full_frame(@107,{UninitializedThis,Object[#32],Object[#63]},{Object[#65],Uni
nitializedThis})
    full_frame(@117,{Object[#2],Object[#32],Object[#63]},{Object[#65]})

        at java.lang.Class.getDeclaredConstructors0(Native Method)
        at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
        at java.lang.Class.getDeclaredConstructors(Unknown Source)
        at org.codehaus.groovy.reflection.CachedClass$2$1.run(CachedClass.java:6
9)
Well, this happens to be a problem with the JVM version.
Known versions with this problem:

1.7.0 update 55
1.7.0 update 65
1.7.0 update 67
1.8.0 update 11

Solution:
Edit the start.bat and add JVM argument "-noverify" to have the code working.

The default JVM options look like this:
::* default JVM options
if not defined CQ_JVM_OPTS set CQ_JVM_OPTS=-Xmx2048m -XX:MaxPermSize=512M -noverify -Djava.awt.headless=true

Hope this helped!

Upgrading to Httpcomponents 4.3.5?

Did you encounter the following error after upgrading to httpcomponents 4.3.5?
java.lang.ClassNotFoundException: javax.naming.InvalidNameException not found by org.apache.httpcomponents.httpclient [923]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1500)
at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:75)
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1923)
at java.lang.ClassLoader.loadClass(Unknown Source)

This happens because Httpclient OSGI bundle 4.3.5 doesnt import the package "javax.naming" by default.
The solution would be to edit the manifest.mf file of the bundle to include the javax.naming package.

The Import-Package section in MANIFEST.MF should look like with the only change is to include javax.naming:
Import-Package: javax.crypto,javax.crypto.spec,javax.naming,javax.net,javax.net.ssl,j
 avax.security.auth.x500,org.ietf.jgss,org.osgi.framework;version="[1.5,
 2)",org.osgi.service.cm;version="[1.3,2)",org.apache.commons.logging;ve
 rsion="[1.1.0,1.2.0)",net.sf.ehcache;resolution:=optional,net.spy.memca
 ched;resolution:=optional,org.apache.http.util;version="[4.3.0,4.4.0)",
 org.apache.http.io;version="[4.3.0,4.4.0)",org.apache.http.pool;version
 ="[4.3.0,4.4.0)",org.apache.http.impl.pool;version="[4.3.0,4.4.0)",org.
 apache.http.impl;version="[4.3.0,4.4.0)",org.apache.http.message;versio
 n="[4.3.0,4.4.0)",org.apache.http.impl.entity;version="[4.3.0,4.4.0)",o
 rg.apache.http.params;version="[4.3.0,4.4.0)",org.apache.http.impl.io;v
 ersion="[4.3.0,4.4.0)",org.apache.http;version="[4.3.0,4.4.0)",org.apac
 he.http.concurrent;version="[4.3.0,4.4.0)",org.apache.http.entity;versi
 on="[4.3.0,4.4.0)",org.apache.http.config;version="[4.3.0,4.4.0)",org.a
 pache.http.protocol;version="[4.3.0,4.4.0)"

Having done this,  it is important to note that httpclients imports more than just javax.naming.
The class org.apache.http.conn.ssl.AbstractVerifier.java imports the following javax.naming classes:

javax.naming.InvalidNameException
javax.naming.NamingException
javax.naming.directory.Attribute
javax.naming.directory.Attributes
javax.naming.ldap.LdapName
javax.naming.ldap.Rdn

If not resolved, such kind of errors may be encountered:
java.lang.NoClassDefFoundError: javax/naming/ldap/LdapName
    at org.apache.http.conn.ssl.AbstractVerifier.extractCNs(AbstractVerifier.java:277)
    at org.apache.http.conn.ssl.AbstractVerifier.getCNs(AbstractVerifier.java:265)
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:157)
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:140)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:286)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:276)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:254)
    at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:123)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:318)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
To resolve all these classes, the OSGi manifest file needs the following package imports as well:
javax.naming.directory
javax.naming.ldap

The Import-Package section in MANIFEST.MF should look like this:

Import-Package: javax.crypto,javax.crypto.spec,javax.net,javax.naming,javax.nami
 ng.directory,javax.naming.ldap
,javax.net.ssl,javax.security.auth.x500,org.ietf.jgss,org.osgi.framework;version="[1.5,
 2)",org.osgi.service.cm;version="[1.3,2)",org.apache.commons.logging;ve
 rsion="[1.1.0,1.2.0)",net.sf.ehcache;resolution:=optional,net.spy.memca
 ched;resolution:=optional,org.apache.http.util;version="[4.3.0,4.4.0)",
 org.apache.http.io;version="[4.3.0,4.4.0)",org.apache.http.pool;version
 ="[4.3.0,4.4.0)",org.apache.http.impl.pool;version="[4.3.0,4.4.0)",org.
 apache.http.impl;version="[4.3.0,4.4.0)",org.apache.http.message;versio
 n="[4.3.0,4.4.0)",org.apache.http.impl.entity;version="[4.3.0,4.4.0)",o
 rg.apache.http.params;version="[4.3.0,4.4.0)",org.apache.http.impl.io;v
 ersion="[4.3.0,4.4.0)",org.apache.http;version="[4.3.0,4.4.0)",org.apac
 he.http.concurrent;version="[4.3.0,4.4.0)",org.apache.http.entity;versi
 on="[4.3.0,4.4.0)",org.apache.http.config;version="[4.3.0,4.4.0)",org.a
 pache.http.protocol;version="[4.3.0,4.4.0)"

Hope this was helpful!






 

Tuesday, 2 September 2014

AEM Dispatcher - Manual cache flushing/invalidation

CQ comes with a Default flush agent that flushes cache on activation. But what if you manually want to flush or invalidate the cache?

The solution is:

The CQ cache can be deleted by using an HTTP request which looks like:

POST /dispatcher/invalidate.cache HTTP/1.1
CQ-Action: Activate
CQ-Handle: path-pattern
Content-Length: 0


CQ Actions:  

1.Activate
  • It touches the .stat file( at and above the CQ-handle path heirarchy) to the latest timestamp
2.Delete/Deactivate
  • It touches the .stat file( at and above the CQ-handle path heirarchy) to the latest timestamp 
  • It deletes the cache at the CQ-Handle path provided

We can write a flushcache servlet to serve the purpose:

package com.adobe.example;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Property;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;

@Component(metatype=true)
@Service
public class Flushcache extends SlingSafeMethodsServlet {

    @Property(value="/bin/flushcache/html")
    static final String SERVLET_PATH="sling.servlet.paths";

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
        try{
            //retrieve the request parameters
            String handle = request.getParameter("handle");
            String page = request.getParameter("page");

            //hard-coding connection properties is a bad practice, but is done here to simplify the example
            String server = "localhost:80";
            String uri = "/dispatcher/invalidate.cache";

            HttpClient client = new HttpClient();

            PostMethod post = new PostMethod("http://"+server+uri);
            post.setRequestHeader("CQ-Action", "Activate");
            post.setRequestHeader("CQ-Handle",handle);

            StringRequestEntity body = new StringRequestEntity(page,null,null);
            post.setRequestEntity(body);
            post.setRequestHeader("Content-length", String.valueOf(body.getContentLength()));
            client.executeMethod(post);
            post.releaseConnection();
            //log the results
            logger.info("result: " + post.getResponseBodyAsString());
        }
        catch(Exception e){
            logger.error("Flushcache servlet exception: " + e.getMessage());
        }
    }
}

 

How it works:
The .stat file is touched to the latest timestamp everytime we hit the servlet.

Demo:

Initial .stat file


After hitting http://localhost:4503/bin/flushcache/html?handle=/content&page=/content, the stat file timestamp gets updated: