Quantcast
Channel: AEM Guide
Viewing all 162 articles
Browse latest View live

Asset Grabber – oEmbed a complete asset embed solution

$
0
0
If you are an AEM/CQ developer and had worked on multiple projects, then you might be very well familiar with how exasperating is to create components for embedding assets in for web page. Here’s how actually it goes from development perspective.
Things starts with video component. Now create a component for YouTube, let’s assume you created. Next day client knock’s your door and say’s, “We are now planning to embed Vimeo also, please add this into your requirement and start working“. Somehow you managed to create a Vimeo component. After 2 days, client again shoots a missile, “We had an internal discussion and now we are planning to feature Ted videos as well, please get started“. At this point what development team and with  how much anger they get into you will be aware, But before leaving for the day you run this command: “project XYZ: Completed Ted Video module“. It means you have completed this as well.
When it comes to assets, it’s very strenuous to take care of all scenarios. Let me introduce youoEmbed, we call it as “Assets Grabber”. Yes, you heard right, it’s having secret magnetic attraction power to pull things from other sites and show in yours. That’s so called secret magnetic attraction is it’s ability to handle and support huge amount of sites starting from VimeoYouTube for videos to Flickr for images to Infogram for charts to Slideshare for slide to Meetup for meetings.

Chrome Console Magic

$
0
0
Chrome Console Magic
Chrome has many timesaving and neat tools built into it, many of these tools are not necessarily obvious on the surface. This post is a deeper dive into what is available. If you are not familiar with Chrome Dev Tools at all, this post is probably not for you.

$ selectors

Chrome has built-in selectors much like jquery.
On this page you will see 3 divs, two with a selector-test class and one with selector-test id.
There are 4 useful types of $ selectors in Chrome.

$()

$() selects the first matching element. (If jquery is active on the page, it will select all matching elements). It will match classes prefaced with ‘.’, IDs prefaced with ‘#’, or regular elements such as ‘p’, 'div', etc.
Example 1 (in the console type):
 $('.selector-test')
Chrome returns:
<div class="selector-test">Test selector content (.selector-test)</div>
Example 2:
  $('div')
Chrome returns:
<div class="selector-test">Test selector content (.selector-test)</div>
The same div is selected in both examples as both the first item with class "selector-test" and the first div on the page.

$$()

$$() selects all matching elements (similar to jquery)
Example:
  $$('.selector-test')
Chrome returns, the expandable array:
  [<div class=​"selector-test">​Test selector content (.selector-test)​</div>​, <div class=​"selector-test">​Test selector content (.selector-test)​</div>​]

$_

$_ returns the last valued and returned result. If you did this directly after the last example, it will return the same results ([<div class=​"selector-test">​Test selector content...).
Example:
  1+1; //hit enter here so 2 is returned
$_ + 2;
Chrome returns:
  4 (because 1+1+2 = 4)

$0 - $4

Returns the current or previous inspector selected item. $0 selects the current, $1 previous, $2 item before previous… etc.
Example:
  [select an item via element/inspector, I’ve selected the h1]
$0
Chrome returns:
<h1> Selectors</h1>
This can come in handy for things like copy($0) which copies the current selection to the clipboard.
Screencap of selectors exercise
Screencap of above exercises.

Advanced console commands

Console.log everything right? Well yeah, obviously, but there are some other alternatives that may help. You may continue to use selectors.html for this section as all of the examples will be done directly in the console, but may also be included in your javascript files in the future.

console.error/console.warn

Much like console.log except with special styling and will note an error or warning in the error/warning count. Console.error also comes with a stack trace, console.warn does not.
Example:
console.error('this shouldn’t happen');
console.warn('this probably shouldn’t happen');
Chrome returns:
Error and Warning console
And notes it in the error/warning count:
Error and Warning console count

console.clear

Seems simple, but is relatively unknown.
Example:
  console.clear();
Chrome returns:
"Console was cleared", (also clears error and warning counts)

console.table

This is most useful for displaying xml, json, arrays, or similar in a sortable table format.
Example:
  var newArray = [{a:1, b:2, c:3},{a:2, b:3, c:4},{a:3, b:4, c:5},{randomVar:"woah"}]
console.table(newArray);
Chrome returns:
Console table
You can also edit which keys you want displayed by passing in an additional array.
Example:
  var newArray = [{a:1, b:2, c:3},{a:2, b:3, c:4},{a:3, b:4, c:5},{randomVar:"woah"}]
console.table(newArray, ['a', 'c']);
Chrome returns:
Console table filtered

console.groupCollaped/console.groupEnd

This is used for grouping lots of console messages together.
Example:
  console.groupCollapsed('My condensed messaging');
//loops 49 times, logs msg each time
for(i=0;i<50;i++){
console.log('logging number: ' + i);
}
console.groupEnd();
Chrome returns:
Condensed messaging
Which expands to reveal all grouped messages:
Condensed messaging expanded
...
Message grouping can also be nested.
Example:
  console.groupCollapsed("nest1");
console.log('message nest 1');
console.groupCollapsed("nest 2");
console.log('message nest 2');
console.groupEnd();
console.groupEnd();
Chrome returns:
Condensed messaging nested

console.group

Same as groupCollapsed, except not collapsed by default.

console.time/console.timeEnd

These are used for time tracking. Note that timing is used for estimation purposes only, and should not be considered 100% accurate or used for time critical syncing. It can be used however for optimization and code efficiency.
Example:
  console.time("Array initialize");
var array= new Array(1000000);
for (var i = array.length - 1; i >= 0; i--) {
array[i] = new Object();
};
console.timeEnd("Array initialize");
Chrome returns:
  Array initialize: 1415.537ms

console.count

This is used similar the example above for grouping, but can work outside separate functions automatically.
Example:
  function funct1(){
console.count('I am counting');
};
function funct2(){
console.count('I am counting');
};
funct1();
funct2();
Chrome returns:
  I am counting: 1
I am counting: 2
What happens here is the first function is called and produces the message, then counts and appends how many times that message has been stated. Then the second function is called and does the same, but keeps track of how many times the count expression is called, in this case twice. Note that if you clear the console, this number does get reset.

console.assert

This tests that a condition is met, then shows an error message (console.error) if NOT met.
Example 1:
  var fruit = "orange";
console.assert(fruit!="orange", "Fruit is an orange!");
Chrome returns:
  Assertion failed: Fruit is an orange!
Example 2:
  var newArray = [1, 2, 3, 4];
console.assert(newArray.length > 5, "new array length is not greater than 5");
Chrome returns:
  Assertion failed: new array length is not greater than 5
Example 3:
  var newArray = [1, 2, 3, 4, 5];
console.assert(newArray.length > 4, "new array length less than 4");
Chrome returns:
  [Nothing, because assertion is true.]

And console.log?!

Console.log is just a message, what’s there to learn?
COMBINING COMPLEX SELECTORS WITH MESSAGING:
Example:
  console.log("Elements on page with .selector-test:", $$('.selector-test'));
Chrome returns:
Console log complex selector
The key here is the comma. That makes the selector object expandable and elements able to be found in the dom. If the commas was a plus instead, the results would look like this: “Elements on page with .selector-test:[object NodeList]”, which is not as useful if you’re looking for the actual object.
NEXT YOU CAN STYLE MESSAGES:
The ability to use console log vars is built into chrome, for this example we are using ‘%c’ which is Chrome’s console inspector formatted styling variable.
Example:
  console.log(" %c🐜🐜🐜%c What is this a console log for ants? %c🐜🐜🐜",  "color:black; background:tan; font-size: 15px", "color:black; background:brown; font-size: 9px",  "color:black; background:tan; font-size: 15px");
Chrome returns:
Console log styling
You can see the formatting is similar to css, each “%c” notes a new style in order as comma separated.
  • first %c: "color:black; background:tan; font-size: 15px"
  • second %c: "color:black; background:brown; font-size: 9px"
  • third %c: "color:black; background:tan; font-size: 15px"
Understand this concept before moving on to the next example.
OVERLOADING WITH INCLUDE VARS:
There are number of other % calls that can be used here. The example below is similar to the top although the expandable object is being passed via the ‘%o’ into the console string, this allows you make complex and expandable strings.
Example 1 (augmented first example from above):
  console.log("Elements on page with .selector-test: %o (with auto object in string)", $$('.selector-test'));
Chrome outputs:
Console log overloading 1
Example 2:
  var conString = "Names"
var conInteger = 1.123
var conFloatingPoint = conInteger
var conObject = $$('.selector-test')
var conJSObject = ["Tumpy", "Clintoc", "Robburn"]
console.log("formatted as string: %s \nformatted as Integer: %d \nformatted as floating point: %f \nformatted as dom object: %o \nformatted as JS Object: %O", conString, conInteger, conFloatingPoint, conObject, conJSObject);
Chrome outputs:
Console log overloading 2
It is important to note here that each var is used in the order it is comma separated to the console.log display string. Meaning if you swap %s and %d in the previous example, it would stringify 1.123/conInteger and attempt to convert “Names” into a integer, which will result in a NaN.

Installing Bundles by Runmode

$
0
0
If I had a dollar for every bundle configuration I've looked at where there was a little checkbox titled "Enabled", I'd have, like, maybe $31 dollars and I could afford a new Indie Steam game or perhaps 12 of them if I waited for the summer or holiday sales... In reality, I've been on countless projects where the prevailing approach for ensuring a bundle only runs for a specific runmode is to make it configurable via the aformentioned checkbox. While this approach certainly works, there's a much easier and, in my opinion, cleaner and better way to handle this that I think gets overlooked
For starters, consider that you can provide runmode-specific configurations for your bundles via simple naming convention. I'd cover this myself, but Krtisian Wright does an excellent job of doing so here. In short, you'll typically see structures along the following lines:
  • /apps/skynet/config.author
  • /apps/skynet/config.publish
  • /apps/skynet/config.<some-other-runmode>
And, yes, Skynet is being built on top of AEM. You heard it here first... Back on topic, the same naming conventions apply for installation of bundles as well. For example
  • /apps/skynet/install.publish
will have any bundles therein installed only if the current runmode is publish. Also, for what it's worth, you can even chain runmodes together for both the configuration and installation of bundles. For example
  • /apps/skynet/install.publish.staging
will install any bundles underneath so long as the instance's runmode is both publish and staging. For the unaware, yes, you can have as many runmodes as you want for any particular instance. This allows you to set up environment-specific configurations. Further, note that the runmodes "author" and "publish" are just two default runmodes for AEM that have a bunch of predefined configuration set up for you. In fairness, one advantage to using the "Enabled" checkbox approach is that you could then test your bundle on any instance by configuring it. However, configuring bundles directly through Felix instead of doing so via sling:OsgiConfig nodes can open up its own can of worms in the generation of an nt:file and actually overwriting your sling:OsgiConfig with this nt:file if it exists :(. So, for future projects, I highly recommend setting up runmodes for your specific environments and building out your configurations and bundle installation for each exactly as you want them using the above approach.

Indexing Properties and Nodes for AEM 6.0 and 6.1

$
0
0
To index a particular property, create a node directly under your oak:index of type oak:QueryIndexDefinition with the following properties:
name = propertyNames, type String[], value is the name of the property(ies) you want to index
name = type, type String, value = property
name = reindex, type Boolean, value = true
To index entire nodes so that you don’t have to list all their property names (for example, if they are coming from an outside source and you don’t know them all ahead of time), you have to do different things depending on if you are on 6.0 or 6.1. The following steps concern indexing nodes (and their properties) in the DAM, but they should work for general cases:
For 6.1:
  1. In CRXDE Lite, navigate to this path: /oak:index/damAssetLucene/aggregates/dam:Asset. You should see a list of nodes with names that start with “include” and then a number.
  2. To this list, add a new node of type nt:unstructured that follows the same naming convention and a new number one higher than the current highest (for example, if “include7” is the highest number with 7 then make a node with the name “include8”). The name probably doesn’t matter but we don’t tempt fate around here.
  3. Add a property to this node with the name “path” with a String value set to “”, for example: “jcr:content/metadata”.
  4. Click Save All.
  5. Navigate up the tree to /oak:index/damAssetLucene.
  6. Change the value of the “reindex” property on this node to “true”. This should perform a reindex on the repository.
For 6.0:
  1. In CRXDE Lite, find the node /oak:index.
  2. Under the oak:index node, create a new node of type oak:QueryIndexDefinition with the name “damAssetLucene”.
  3. Set the following properties on this new node:
    1. Name: async, type: String, Value: async
    2. Name: compatVersion, type: Long, Value: 1
    3. Name: evaluatePathRestrictions, type: Boolean, Value: true
    4. Name: reindex, type: Boolean, Value: false (you don’t want to trigger a reindex yet!)
    5. Name: type, type: String, Value: lucene
  4. Click Save All.
  5. Under the damAssetLucene node you just created, create a new node of type nt:unstructured with the name “aggregates”.
  6. Click Save All.
  7. Under the aggregates node you just created, create a new node of type nt:unstructured with the name “dam:Asset”.
  8. Click Save All.
  9. Under the dam:Asset node you just created, create a new node of type nt:unstructured with the name “include0”.
  10. Add a property to the include0 node with the name “path” with a String value set to “”, for example: “jcr:content/metadata”.
  11. Click Save All.
  12. Navigate back up the tree to the damAssetLucene node you created earlier.
  13. Change the value of the “reindex” property on this node to “true”. This should perform a reindex on the repository.
The key thing to note here is that you are replicating some of the same node structure on 6.0 that already exists by default on 6.1, but the compatVersion property is set to 2 in 6.1 and must be set to 1 on 6.0.
With the transition to Jackrabbit Oak, a lot of people are still working out what the best practice is for indexing Oak nodes; this may not be the definitive way to do indexing for properties and nodes in AEM, but it is one way we have found that seems to work well.

Create a OSGI Configuration Listener in AEM 6.1

$
0
0
Following article demonstrate business scenario where you need to execute a job, call a method or simply log when there in change in XYZ OSGI configuration. Taking forward the OSGI Configuration Management and Reading of OSGI Configuration, I will show you how you can create a OSGI Configuration listener. Before that’s take a look at below…
ConfigurationListener[Interface] objects are registered with the Framework service registry and are notified with a ConfigurationEvent object when an event is fired. ConfigurationListenerobjects can inspect the received ConfigurationEvent object to determine its type, the pid of theConfiguration object with which it is associated, and the Configuration Admin service that fired the event.
I have used com.day.cq.wcm.notification.email.impl.EmailChannel service but you can use any service based on your requirements and will read property email.from when their is a change. Let’s get started..
1. Create a Service which Implement ConfigurationListener interface
2. Override ConfigurationEvent method and its implementation
3. Invoke a custom define method to read required property
4. Change the email.from property inservice com.day.cq.wcm.notification.email.impl.EmailChannel
Change OSGI config
5. See the updated log file snippet
Updated Log File
6. Here is complete code you can use

Implement Use-Interface using Sightly in AEM 6.x

$
0
0
Implementing sightly can be basically done with two important APIs (although few others are also available). In my other article I have cover up how you can  Access OSGI ser­vice from the WCMUse-class in Sightlyhere we are going to cover next important one which shows how you can implements the Use-interface in Java and combine your business logic with component file. 
Let’s see Use interface first, later we will jump to code. 
All you need to make sure is to implement public void init(javax.script.Bindings bindings) The initmethod will be called on initialization of the class with a Bindings object that holds all the context objects and any parameters passed into the use-class. Business logic will be present in this method, although you are free to create custom method which will be called from init().
Binding object is an mapping of key/value pairs, all of whose keys are Strings.

Useful AEM articles

$
0
0
These are some of the useful kb articles of AEM
AEM 6.x
  1. AEM_6_TarMK_Online_Compaction : If you are seeing rapid repository growth on an AEM 6.x instance
  2. aem6-available-hotfixes : Adobe Experience Manager 6.0 hot fixes
  3. aem61-available-hotfixes : Adobe Experience Manager 6.1 hot fixes
  4. DisableLineChecker : Disable the CQ5 Link Checker
AEM 5.x
  1. AnalyzeMemoryProblems :  AEM over a period of time may become slower and finally runsout of memory or you see an error in the logs or in the console output OutOfMemoryError
  2. AnalyzePersistenceProblems : If CRX doesn’t start, or if there are exceptions and stack traces in the log file that are related to persistence (such as TarPersistenceManager or FileDataStore)
  3. AnalyzeSlowAndBlockedProcesses : CRX/CQ process uses 100% of the CPU, the system doesn’t respond, or the system is slow
  4. AnalyzeUnclossedSession : In AEM application, developer has to ensure the proper closure of the JCR sessions. If not, such sessions will not be subject of garbage collection and thus will stay in memory, causing out of memory issue or system slowness. Each CRX Session creates and maintains its own set of caches which adds to the overall resource consumption.https://helpx.adobe.com/experience-manager/kb/AnalyzeUnclosedSessions.html
  5. AnalyzeUsingBuiltInProfiler : Sometimes the application will be running fine but only few of the process will be really slow
6. cacheentrycollector-cache-size-is-too-small : If permissions / ACLs in AEM or CRX is used extensively, then it can affect the search         performance in the repository because when search results are being retrieved they must be filtered against the permissions in the CRX repository.
7. CloneInstance : Cloning an existing instance
8. crx-disk-and-memory-monitoring-shutdown-too-aggressively : CRX automatically shuts downthe repository due to a monitoring feature
9. DataStoreGarbageCollection :  to remove any unused files in the Data Store, use Garbage collection.
10. datastore-inconsistency-record-not-found : If you are facing Datastore inconsistency and seeing ‘FileNotFoundException’

Personalization in AEM

$
0
0
Personalization: Personalization is a technique to serve personalized content to each user. It can be based on user logged in by city, country
Here are the steps involved in implementing personalization.

Step1: Create the Segments.(Segments hold the rule to be checked while displaying a teaser on any page)

Go to Tootls > Segmentation
                                  


Double click on created segment and configure the test condition to be evaluated. For eg: We are going to display the teaser for ‘Male’ users.

For this, drag the ‘User properties’ from side kick.
                      




Edit the property to check the condition ‘gender=male’
                      

Now the segment will look as below.

                  



Step2:  Create Brand, Campaign Container (Brand holds campaigns, campaign holds teasers)


Once segment is created, Go to > Campaigns (http://localhost:4505/mcmadmin#/content/campaigns)

Create Brand selecting brand template,

           
           
Now create Campaigns by selecting campaign template
                 
    


Step3:  Create Teasers
Once campaign is created, go to lists view and create offer page(from aem 6.0). Earlier it was Teaser Page.

                   

Add some text and image to teaser by editing it. Sample is shown below.


Configure the touch point properties of teaser by selecting the segment in ‘Advanced section’as shown below.
This is the linking point between segment and teaser.

               


Now the campaign page looks as below.



Step4:  Add Teasers to any page
Now go to the page where you want to display the teaser, drag and drop teaser
                      



Enter the configuration selecting campaign to be run for the page as shown below.

                  




Step5:  Test the teaser by setting client context. (Client Context is used to check/modify any user attributes during testing the personalization)



Now go to client context (CTRl+Alt+C) and select a ‘male’ user. You can see the teaser is displayed as shown below.
                 




AEM Context JUnit Rule

$
0
0

The AEM mock context can be injected into a JUnit test using a custom JUnit rule named AemContext. This rules takes care of all initialization and cleanup tasks required to make sure all unit tests can run independently (and in parallel, if required).
Example:
publicclassExampleTest{

@Rule
publicfinal AemContext context = new AemContext();

@Test
publicvoidtestSomething(){
Resource resource = context.resourceResolver().getResource("/content/sample/en");
Page page = resource.adaptTo(Page.class);
// further testing
}

}

In-container testing for AEM projects

$
0
0
Nowadays it’s easier than ever to encapsulate the state used by AEM components into objects – commonly referred to as models – which can then be used while rendering the response. For example, the Sling Modelsframework is a great way to do this. If the Sightly format is used for your template, you can only use very simple presentation logic, meaning you must use a model class to do more complex operations.

One of the many benefits of this approach is that your model classes can be automatically tested as part of a continuous integration (CI) set-up. When using Java models, a common approach is to use unit tests to do this, and rely on 
Mockito or similar frameworks to simulate the behaviour of the AEM environment. Within such a rich environment, however, the test code quickly becomes hard to follow, as most of it is setting up the AEM simulation. Worse still, it’s very easy to get the simulation wrong, meaning your tests pass but your code is actually buggy.



These problems are magnified when writing other types of AEM code. For example, a feed importer that imports product data into the JCR becomes very cumbersome to test in this manner. Also, consider if you create an OSGi service using SCR annotations - it’s possible your code is correct but the annotation is wrong, meaning your service may never be made available within AEM. Your unit tests would pass but your code would never work when deployed.
In-container testing for AEM projects
This article will look at running integration tests via HTTP against a running AEM instance or container. For a continuous integration set-up, the AEM instance is created, started and shut down as part of the Maven build cycle. For local development, the same tests can be run against an already running AEM instance to speed up the test process.
Maven will be used as the build tool, as this is the usual standard in AEM projects. However, although some Maven plugins are used for build set-up, this approach can be used with any build tool.
For the purpose of this article I’ll be using the terms unit test and integration test rather loosely. By unit test I mean a test that can be set up and run very quickly (no more than half a second or so) outside of any container. By integration test I mean any test that is run within an AEM instance.
Sling testing tools
The good news is that the Apache Sling project supplies the Sling Testing Tools module, which provides several ways to run tests in a Sling environment. As AEM has Sling at its core, we can use these tools to test our code.
The SlingTestBase class can be used as a superclass for tests to be run against a running AEM instance. By default, the first time this class is used it will try to locate the Sling runnable jar and start it. The AEM quickstart.jarcan be run in the same manner.
Setting up and running the example
You will need a valid AEM licence and the AEM quickstart.jar file checked into a Maven repository. The quickstart.jar file should contain the following Maven co-ordinates:
<dependency>
    <groupId>com.adobe.aem</groupId>
    <artifactId>cq-quickstart</artifactId>
    <version>6.0.0</version>
    <classifier>standalone</classifier>
</dependency>
If you don’t have a Maven repository readily available, there are several ways to set one up. A very convenient way is to use Amazon S3 as a Maven repository: Bruce Li has created a working example. Then follow this guide to deploy the quickstart jar file.
Check out the example project and edit the license.properties file. Put your valid licence details in there.
You also need to configure Maven to use the repository you installed the quickstart into. One way to do this is to add into the top-level pom. Find the section with the adobe-public repository and duplicate, omitting the<pluginRepository\> section and rename/configure as appropriate. Read the README file for further setup details.
To run the example, execute the following from the root of the project
mvn clean verify -P integrationTests
You should see Maven build the project, start up a new AEM instance, deploy the project and run the tests against this.
The AEM start-up sequence
The integration tests are run from the it.launcher pom, when theintegrationsTests Maven profile is specified. The steps are as follows:
1.     The AEM quickstart.jar file is retrieved as a Maven dependency and copied to /target/dependency, along with other bundles that will need to be deployed to the new instance.
2. <plugin>
3.     <groupId>org.apache.maven.plugins</groupId>
4.     <artifactId>maven-dependency-plugin</artifactId>
5.     <version>2.8</version>
6.     <executions>
7.         <execution>
8.             <id>copy-runnable-jar</id>
9.             <goals>
10.                 <goal>copy-dependencies</goal>
11.             </goals>
12.             <phase>process-resources</phase>
13.             <configuration>
14.                 <includeArtifactIds>cq-quickstart</includeArtifactIds>
15.                 <excludeTransitive>true</excludeTransitive>
16.                 <overWriteReleases>false</overWriteReleases>
17.                 <overWriteSnapshots>false</overWriteSnapshots>
18.             </configuration>
19.         </execution>
20.         <execution>
21.             <!--
22.             Consider all dependencies as candidates to be installed
23.             as additional bundles. We use system properties to define
24.             which bundles to install in which order.
25.             -->
26.             <id>copy-additional-bundles</id>
27.             <goals>
28.                 <goal>copy-dependencies</goal>
29.             </goals>
30.             <phase>process-resources</phase>
31.             <configuration>
32.                 <outputDirectory>${project.build.directory}/sling/additional-bundles</outputDirectory>
33.                 <excludeTransitive>true</excludeTransitive>
34.                 <overWriteReleases>false</overWriteReleases>
35.                 <overWriteSnapshots>false</overWriteSnapshots>
36.             </configuration>
37.         </execution>
38.     </executions>
 </plugin>
39.   The AEM license.properties file is copied into the right place.
40. <plugin>
41.    <groupId>org.apache.maven.plugins</groupId>
42.    <artifactId>maven-antrun-plugin</artifactId>
43.    <executions>
44.        <execution>
45.            <id>copy-aem-license</id>
46.            <phase>process-resources</phase>
47.            <configuration>
48.                <tasks>
49.                    <mkdirdir="${jar.executor.work.folder}"/>
50.                    <copyfile="${project.basedir}/src/test/resources/license.properties"
51.                          toDir="${jar.executor.work.folder}"verbose="true"/>
52.                </tasks>
53.            </configuration>
54.            <goals>
55.                <goal>run</goal>
56.            </goals>
57.        </execution>
58. 
59.    </executions>
 </plugin>
60.   A random port is reserved for the AEM server.
61. <plugin>
62.     <!-- Find free ports to run our server -->
63.     <groupId>org.codehaus.mojo</groupId>
64.     <artifactId>build-helper-maven-plugin</artifactId>
65.     <version>1.9.1</version>
66.     <executions>
67.         <execution>
68.             <id>reserve-server-port</id>
69.             <goals>
70.                 <goal>reserve-network-port</goal>
71.             </goals>
72.             <phase>process-resources</phase>
73.             <configuration>
74.                 <portNames>
75.                     <portName>http.port</portName>
76.                 </portNames>
77.             </configuration>
78.         </execution>
79.     </executions>
 </plugin>
80.   The JaCoCo plugin is configured to record our test coverage.
81. <plugin>
82.     <groupId>org.jacoco</groupId>
83.     <artifactId>jacoco-maven-plugin</artifactId>
84.     <version>0.7.2.201409121644</version>
85.     <configuration>
86.         <append>true</append>
87.     </configuration>
88.     <executions>
89.         <execution>
90.             <goals>
91.                 <goal>prepare-agent-integration</goal>
92.             </goals>
93.             <configuration>
94.                 <dumpOnExit>true</dumpOnExit>
95.                 <output>file</output>
96.                 <includes>
97.                     <include>com.ninedemons.*</include>
98.                 </includes>
99.                 <append>true</append>
100.                           <propertyName>jacoco.agent.it.arg</propertyName>
101.                       </configuration>
102.                   </execution>
103.               </executions
 </plugin>
104.The Maven failsafe plugin is then configured with various settings needed as system properties, and starts running the integration tests.
The quickstart.jar is configured to not start a browser, run in author mode and to not install the sample content to reduce start-up time:
 <!-- Options for the jar to execute. $JAREXEC_SERVER_PORT$ is replaced by the selected port number -->
 <jar.executor.jar.options>-p $JAREXEC_SERVER_PORT$ -nobrowser -nofork -r author,nosamplecontent</jar.executor.jar.options>
105.The very first test to run will start the AEM instance: wait for it to start (by polling the URL set in the <server.ready.path.1> property) and then install additional bundles.
The additional bundles installed are the Sling Testing bundles, our project bundles and the httpclient-osgi and httpcore-osgi dependencies needed by Sling Testing:
 <!--
     Define additional bundles to install by specifying the beginning of their artifact name.
     The bundles are installed in lexical order of these property names.
     All bundles must be listed as dependencies in this pom, or they won’t be installed.
 -->
 <sling.additional.bundle.1>org.apache.sling.junit.core</sling.additional.bundle.1>
 <sling.additional.bundle.2>org.apache.sling.junit.scriptable</sling.additional.bundle.2>
 <sling.additional.bundle.3>example.models</sling.additional.bundle.3>
 <sling.additional.bundle.5>example.core</sling.additional.bundle.5>
 <sling.additional.bundle.6>org.apache.sling.junit.remote</sling.additional.bundle.6>
 <sling.additional.bundle.7>org.apache.sling.testing.tools</sling.additional.bundle.7>
 <sling.additional.bundle.8>httpclient-osgi</sling.additional.bundle.8>
 <sling.additional.bundle.9>httpcore-osgi</sling.additional.bundle.9>
106.From this point onwards, the tests can use HTTP to set up and run tests within AEM.
107.When all tests are finished, the running AEM instance is shut down by default. This means that JaCoCo test coverage is finalised in a file atit.launcher/target/jacoco-it.exec and can be used together with tools such as SonarQube to report test coverage.
How the tests are written
In our example we have one Java model beancom.ninedemons.aemtesting.models.title.TitleModel. This model is used in the title component Sightly file title.html.
We have a test class for this model: TitleModelTest.java This class extendsSlingTestBase, which in turn takes care of starting up the AEM instance, if needed. It makes use of all the standard JUnit annotations to mark tests and set up code.
The first thing that the test does is to create an instance of SlingClient.
private SlingClient slingClient = new SlingClient(this.getServerBaseUrl(), this.getServerUsername(), this.getServerPassword());
This now allows the test to speak to the AEM instance using the Sling RESTful API.
Setting up a test component
The first place the SlingClient is used is to set up a test component. There’s a minimal JSP used for testing the model – remember, we’re testing the model not the Sightly markup: titleModelTest.jsp. This JSP simply creates an instance of the model and renders it as pretty plain HTML:
<sling:adaptToadaptable="${slingRequest}"adaptTo="com.ninedemons.aemtesting.models.title.TitleModel"var="model"/>

Element is '${model.element}'<br/>
Title is '${model.text}'<br/>
Our test creates an apps folder in the AEM instance and uploads the JSP:
privatevoid uploadTestJsp() throws IOException {

    slingClient.upload(
            TEST_APP_FOLDER_PATH + "/title-model-test.jsp",
            TitleModelTest.class.getClassLoader().getResourceAsStream(
                    "jsp/title-model/titleModelTest.jsp"), -1, true);
}
Once this is done, we can use this test component by setting thesling:resourceType of a JCR node to test/title-model-test.
Creating test pages
Now the test creates a test page and JCR nodes to reference the test component:
privatevoid createTestPageComponent() throws IOException {

    slingClient.createNode(PATH_TO_TEST_NODE,
            JcrConstants.JCR_PRIMARYTYPE,JcrConstants.NT_UNSTRUCTURED,
            JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, "test/title-model-test",
            "type", TITLE_TYPE,
            JcrConstants.JCR_TITLE,EXPECTED_TITLE,
            JcrConstants.JCR_DESCRIPTION,"Test Node For SimpleModel"
    );
}
Running a test scenario
Now the test component and pages are in place, a test can be run against the AEM instance:
@Test
publicvoid whenAllPropertiesSetAgainstComponent() throwsException {

    // Given a component instance where the title and type are set against
    // the instance node

    // When the component is rendered
    RequestExecutor result = getRequestExecutor().execute(
            getRequestBuilder().buildGetRequest(
                    PATH_TO_TEST_NODE + ".html").withCredentials(
                    this.getServerUsername(), this.getServerPassword()));

    // Then the model should return the values defined in the instance node
    result.assertStatus(200)
            .assertContentContains("Element is \'"+ EXPECTED_ELEMENT + "\'")
            .assertContentContains("Title is \'" + EXPECTED_TITLE + "\'");

}
This test requests that the test component be rendered as HTML, meaning our test JSP is used. The test checks the response is a HTTP OK code (200), and that the expected HTML element and title text is used.
Using an already running AEM instance
Waiting for the AEM instance to start up each time you want to test during development is impractical. On a powerful MacBook Pro Retina with 16Gb of memory and an SSD it takes around four minutes to run a test cycle. Instead, it’s much better to use an already running AEM instance to run the tests against. Thankfully, this is very easy by using a property calledtest.server.url passed to Maven:
mvn clean verify  -P integrationTests -Dtest.server.url=http://localhost:4502
In this mode, the SlingTestBase class simply checks that the URL is accessible and skips starting up the instance. However, the additional bundles are installed as per the pom.
The AEM instance is not terminated after the tests finish, allowing any investigation needed for failing tests. It also means debugging by attaching an IDE is possible.
Other test modes
The Sling Testing Tools project allows for other ways of running tests – for example, running unit tests within the AEM instance itself. It’s well worth reading up on the various tools that the project supplies.
Conclusion
This approach to testing has several benefits above using unit tests and mocking AEM behaviour. The test code is easier to read and maintain, and gives a high level of confidence that your code is correct as it’s running in a real AEM instance. It’s also very easy to run your tests against a new version of AEM – simply update the AEM dependency in your pom to reference the new version.
There are, however, some disadvantages – the most obvious being the overhead involved in the AEM start-up. As described above, on a powerful workstation this can be four minutes, and on a typical build server it’s usually around 10 minutes.
A more serious limitation is around service packs or similar updates to AEM. It would be possible to install these in a similar manner to additional bundles, but some service packs have needed human intervention to restart the instance at the necessary points. This, of course, is not possible from our tests.
You must also make the quickstart.jar file available in a Maven repository somewhere, and embed your AEM licence details in your source tree.
These limitations can be addressed by using an already running AEM instance with all the updates applied. The problem here is ensuring the instance is clean before the tests start and resetting after the tests finish, and ensuring only one build is testing against this AEM instance at any one time.
A very effective and powerful method to solve these issues is to use Dockerto provision new AEM instances quickly for every build.
The source code referred to in this article is available onGitHub.


Populate Tags based on Selection in Pathfield – Classic UI

$
0
0
This simple use case has been taken from AEM community, I thought an article for this would really help people who are looking for this or may need in future.
Component Overview
We have two field, one is pathfield (which helps to browse repository) and another a tag input field. Author selects an asset from pathfield and based on the the selection Tag input field is populated with tags available for selected assets.
Authoring Experience
Component dialogComponent


Select an asset from pathfield
Authored Component 1
Select different asset from pathfield, tags gets updated.
Authored Component 2 
Code Look Up
To make this work, you simply need to add a widget listener to the asset pathfield. Listener will listen for event dialogclose which means when you select an asset from pathfield browse asset dialog and click ‘Ok’ will cause the event to trigger.
Widget Listener
In above image it can be seen that dialog close listener has been added to asset pathfield.
Javascript which gets the tags
<pre class="brush: JScript">








function(d){
path=this.value+"/jcr:content/metadata.json";
varx=CQ.shared.HTTP.eval(path);
vartags=[];
tags=x['cq:tags'];
dialog=this.findParentByType('dialog');
field=  dialog.getField('./tags');
field.setValue(tags);
}
</pre>
We simply create complete path where tags are present for particular asset and get the response on JSON. In complete JSON response we have many properties values and one of them is our property name cq:tags. In line we are getting the value for cq:tags and setting this value to tag input field.

Implement DataSource for drop down using Sightly AEM 6.1

$
0
0
In Touch UI component, DataSource is very useful when it comes populate drop down dynamically. This article will help you to understand how datasource can be used with Sightly and leaving JSP behind.
Let’s get started with authoring…
Sightly DataSource Component Authoring
Component contains a simple drop down, values for this will be populate dynamically using DataSource.
Here is the code used…
1. DataSource is present at /apps/sightlydatasource/components/content/sample-ds
<sly data-sly-use.data="com.sightlydatasource.core.sightly.SightlyDataSourceExample">
</sly>It simply calls the Java class which act as DataSource
2com.sightlydatasource.core.sightly.SightlyDataSourceExample
package com.sightlydatasource.core.sightly;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;

import com.adobe.cq.sightly.WCMUse;
import com.adobe.granite.ui.components.ds.DataSource;
import com.adobe.granite.ui.components.ds.SimpleDataSource;
import com.adobe.granite.ui.components.ds.ValueMapResource;

/**
 * Sightly class act as a data source returning dynamic data.
 * 
 * @author Praveen
 */
public class SightlyDataSourceExample extends WCMUse {
 @Override
 public void activate() throws Exception {
  ResourceResolver resolver = getResource().getResourceResolver();

  // Create an ArrayList to hold data
  List<Resource> resourceList = new ArrayList<Resource>();

  ValueMap vm = null;

  for (int i = 1; i <= 5; i++) {
   vm = new ValueMapDecorator(new HashMap<String, Object>());
   String Value = "samplevalue" + i;
   String Text = "Sample Text " + i;
   vm.put("value", Value);
   vm.put("text", Text);

   resourceList.add(new ValueMapResource(resolver,
     new ResourceMetadata(), "nt:unstructured", vm));
  }

  // Create a DataSource that is used to populate the drop-down control
  DataSource ds = new SimpleDataSource(resourceList.iterator());
  this.getRequest().setAttribute(DataSource.class.getName(), ds);
 }

}
Line 45: Create new SimpleDataDource object and pass the iterator of our list which contains data.
Here is the AEM Helpx article which shows same in JSP 
Let me know if you need any help in implementation.

AEM Search with Adobe Search and Promote

$
0
0
Adobe AEM can be integrated with Adobe Search and Promote to get metrics driven relevant search results.

Search and promote(S&P) offers the following features:

  • Search features like auto-complete and "Did you mean?" help the users to get relevant search results.
  • Real-time metrics, merchandising rules, and customer intent.
  • Refinements based on facets and filtering options.
  • Built-in linguistics help in spell-checking and searching for non-English languages.
  • Real-time analytics allow search results to be dynamically ranked according to business objectives.
  • Easily scalable and reliable because S&P is provided as SaaS using cloud infrastructure.
  • Incremental indexing helps in ensuring that visitors are always shown with the up-to-date search results.

Also, for high-traffic websites with huge content, it is always advised to offload the search requests to a dedicated search server to get better performance for search results.
S&P is offered as a SaaS product by Adobe. To login to S&P use the following URL.

Creating an AEM Headline Component

$
0
0
Discusses how to create an Adobe Experience Manager component that uses Sightly and a Sling Servlet to display headline news. 
A special thank you to Praveen Dubey, a top AEM community member, for contributing code towards this community article.   
This article covers many AEM concepts that are important to understand as an AEM developer. This article covers the following concepts. 
  • How to create a Sightly component that displays data from a third party service
  • How to use AJAX that invokes a servlet with a Sightly component
  • How you include a clientlibs folder using Sightly
  • How to pass dialog values to a Sling Servlet
This article uses an Adobe Maven Archetype project to build an OSGi bundle. If you are not familiar with an Adobe Maven Archetype project, it is recommended that you read the following article: Creating your first AEM Service using an Adobe Maven Archetype project.

Touch UI dynamic selection of multiple drop downs in AEM 6.1

$
0
0
This articles show the use case of have multiple chained drop down in Touch UI. Values in the next drop down depends on what has been selected on previous one. 
Brief on how it works:-
There are two drop downs with name Language and Country. When you select a Language from drop down, Country down down gets populated with the name of the countries using that language. For example if you select “German” as a language then all countries using German as language will get populated in second drop down.


Enable JS and CSS minification

$
0
0
The CQ "CQ Html Library Manager" component control the handling of client libraries (JavaScript, CSS) minification to remove CRLF and whitespace characters in order to reduce the size of the file. In Earlier version of CQ with minification enabled OR disabled, both the minified OR unminified library version has the same URL.  

This blog post will take you through the steps on how to enable minification.
You need to go to http://localhost:4502/system/console/configMgr. This is a configuration page listing all the services that has configurations. Just look for ‘HTML Library Manager’ and click it. You will see the configurations like following:





Now check the ‘Minify’ checkbox. That’s it. Now you would get all the js and css in minified form.


This is very important from performance perspective. Less size will take less time over the network resulting in better load time when you render the form.

With AEM 5.6 onwards  enabling minification adds a selector "min", There by differentiates the difference in URL for both minified and unminified version of library. 
  • It helps to test both unminified & minified version irrespective of osgi configuration by directly requesting the file from browser. I.e, Once you develop your client library by following [1] you can test directly how much it minifies by adding a selector "min".   Example the granite library the URL for raw (unminified) and minified file looks like [A] & [B].  
[A]   http://<host>:<port>/etc/clientlibs/granite/jquery/granite.js
[B]   http://<host>:<port>/etc/clientlibs/granite/jquery/granite.min.js
  • If you have minified enabled in "CQ Html Library Manager"& all your library follows basic functionality of Client Library [1]. Then while restricting access via the Dispatcher make sure to have stricter filter like [C]
[C]
     # enable specific mime types in non-public content directories 
      /0041 { /type "allow" /glob "* *.min.css *"   }  # enable css
      /0044 { /type "allow" /glob "* *.min.js *"    }  # enable javascript

Creating your first AEM Service using an Adobe Maven Archetype project

$
0
0
In some business use cases, you create an OSGi bundle when creating an Adobe Experience Manager (AEM) application. Although there are different ways to create an OSGi bundle, a recommended way is to use Maven and the Adobe Maven Archetype. This development article walks you through creating a basic OSGi bundle that contains a simple service namedKeyService. All this service does is accept an input value and sets a key value. It also exposes a method that returns the key value and the value can be displayed within an AEM web page.

Creating a custom Excel Service for Adobe Experience Manager

$
0
0
You can create a custom AEM service that accepts an Excel spreadsheet, extracts the data from the spreadsheet, and persists the data in the AEM JCR. For example, consider the following spreadsheet that contains customer data. Once you upload this file to AEM, the custom AEM Excel service reads the customer data and persists the data in the AEM JCR.


Adobe Experience Manager 6.2 Released - Apr 21, 2016

$
0
0
The release cycle for this version of Adobe Experience Manager started May 21, 2015, went through 21 iterations of quality assurance and bug fixing, and ended April 6th, 2016. The total number of customer related issues including enhancements and new features fixed in this release is 972.
Adobe Experience Manager 6.2 is generally available since April 21, 2016. Major changes include the new design of navigation system.
References:

Issue: Page displays i18n keys instead of values

$
0
0

Issue Description: 

AEM i18n keys values are displayed instead of values.

Solution:

This issue is observed when "Apache Sling Internalization Support" bundle is in resolved state. By restarting this bundle, i18n issue will be solved.



Viewing all 162 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>