How to replace sling:resourceType value in bulk using query or script - aem

How to replace sling:resourceType value in bulk using Query and Scipt.
For example I want to change sling:resourceType value
from app/component/linkButton to app/component/content/linkbutton1.
The component is being used on 20 pages, and I want change it using query rather than manually on each page.

the best choice for the purpose is groovy console .
Bellow script which do the job:
import javax.jcr.Node
getNode('/content/').recurse { resourceNode ->
if (resourceNode.hasProperty('sling:resourceType')) {
final def resourceType = resourceNode.getProperty('sling:resourceType').string
if (resourceType.equals('OLD_RESOURCE_TYPE')) {
println "changing " + resourceNode.path
resourceNode.setProperty('sling:resourceType', 'NEW_RESOURCE_TYPE')
resourceNode.save();
}
}
}

You can use the ACS AEM Tools open source project which includes AEM Fiddle. AEM Fiddle allows you to run scripts directly on the AEM instance without have to build.
If you use AEM Fiddle, navigate to http://localhost:4502/miscadmin#/etc/acs-tools/aem-fiddle, click the plus sign in the top right and select .java. Insert this code and run. Make sure you update the query's path.
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import javax.jcr.query.Query;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
public class fiddle extends SlingAllMethodsServlet {
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = response.getWriter();
ResourceResolver resolver = null;
out.println("starting...");
try {
resolver = request.getResourceResolver();
if (resolver != null) {
Iterator<Resource> resources = resolver.findResources("/jcr:root/content/mysite//*[#sling:resourceType='app/component/linkButton']", Query.XPATH);
while (resources.hasNext()) {
Resource resource = resources.next();
ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class);
properties.put("sling:resourceType", "app/component/linkButton1");
resolver.commit();
out.println(resource.getPath());
}
}
} catch(Exception e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
e.printStackTrace(out);
} finally {
if (resolver != null && resolver.isLive()) {
resolver.close();
resolver = null;
}
}
out.println("...finished");
}
}
If you'd rather use JSP as you've stated, the code is the same:
<%#include file="/libs/foundation/global.jsp"%><%
%><%#page session="false" contentType="text/html; charset=utf-8"
pageEncoding="UTF-8"
import="org.apache.sling.api.resource.*,
java.util.*,
javax.jcr.*,
com.day.cq.search.*,
com.day.cq.wcm.api.*,
com.day.cq.dam.api.*,
javax.jcr.query.Query,
org.apache.sling.api.resource.ModifiableValueMap"%><%
Iterator<Resource> resources = resourceResolver.findResources("/jcr:root/content/mysite//*[#sling:resourceType='app/component/linkButton']", Query.XPATH);
while (resources.hasNext()) {
Resource current = resources.next();
ModifiableValueMap props = current.adaptTo(ModifiableValueMap.class);
props.put("sling:resourceType", "app/component/linkButton1");
resourceResolver.commit();
%>
<%=current.getPath()%>
<%
}
%>

Another dirty method, but worked for me. :)
Package the path and download the zip file.
Extract to a folder.
Based on your operating system,
If using Windows, use Notepad++ to find an replace in all files under directory with your search pattern.
If linux, use find or sed commands to replace all occurrences inside a director

How about AEM ACS TOOLS?
It is bulk updating tool for sling:resourceType or cq:Template.
Click here for the article on Getting Started
Click here for the Github Repo
Good Luck...

You can also have a look at sling pipes.
https://sling.apache.org/documentation/bundles/sling-pipes.html
this is the perfect solution for your problem

Related

Get path for clientlibs files

I'm trying to preload assets like explained here.
I've included these in /apps/foundation/components/page/head.html:
<sly data-sly-use.appConfig="${'../../../utils/AppConfig.js'}">
<link rel="preload" href="${appConfig.assetsURL}/etc/designs/myapp/jquery/jquery-3.1.1.min.js">
<link rel="preload" href="${appConfig.mainStyle}/mainstyle.css">
</sly>
Now the final files that need to be included are clientlibs.js and clientlibs.css which are put together for each page, having a different paths depending on the page. For example for homepage (/content/homepage.html) the path to clientlibs.js is /etc/designs/myapp/homepage/clientlibs.js whereas for recent posts (/content/recent-posts.html) the path is /etc/designs/myapp/posts/clientlibs.js
The question is how do I compose the URL for these assets?
I tried using global variables from this gist but with no luck. Neither of them return the right path to the assets.
Since the mapping of clientlibs paths to pages seems to be application-specific, you will need to implement a way to detect the page type and needed clientlibs.
You could use clientlib categories to assemble the correct bits for each page type (have a look at https://docs.adobe.com/docs/en/aem/6-3/develop/the-basics/clientlibs.html and how clientlib inclusion is implemented in /libs/granite/sightly/templates).
Also, if using AEM 6.3, consider using editable templates and setting the clientlibs at template level.
If you already use clientlib categories and just want to rewrite the output of clientlib include you can create your own helper to extract the URLs:
package apps.test;
import javax.script.Bindings;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.sling.scripting.sightly.pojo.Use;
import libs.granite.sightly.templates.ClientLibUseObject;
public class Test implements Use {
ClientLibUseObject obj = null;
Pattern pattern = Pattern.compile("(?:href|src)=\"(.*?)\"");
List<String> srcs = null;
public void init(Bindings bindings) {
obj = (ClientLibUseObject) bindings.get("clientLibUseObject");
}
public List<String> getSrcs() {
if (srcs == null && obj != null) {
srcs = new ArrayList<>();
String tmp = obj.include();
Matcher matcher = pattern.matcher(tmp);
while (matcher.find()) {
srcs.add(matcher.group(1));
}
}
return srcs;
}
}
and then call it in your scripts:
<link data-sly-use.clientLibUseObject="${'libs.granite.sightly.templates.ClientLibUseObject' # categories='jquery,jquery-ui', mode='all'}"
data-sly-use.rewriter="${'Test' # clientLibUseObject=clientLibUseObject}"
data-sly-repeat="${rewriter.srcs}"
rel="preload" href="${item}"/>

Set FopFactoryBuilder baseURI to jar classpath

I'm upgrading an Apache FOP 1.0 project to Apache FOP 2.1. In this project, all necessary files are packaged within the jar file.
I've added the new FopFactoryBuilder to generate a FopFactory
FopFactoryBuilder builder = new FopFactoryBuilder(new File(".").toURI());
builder = builder.setConfiguration(config);
fopFactory = builder.build();
but all my resouces are loaded from the relative path on my file system, not from the jar. How can I set the baseURI to the jar's classpath?
Thanks
We also used FOP 2.1 and want to achieve, that images inside jars-classpath will be found. Our tested and used solution is the following:
Create your own ResourceResolver
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.xmlgraphics.io.Resource;
import org.apache.xmlgraphics.io.ResourceResolver;
public class ClasspathResolverURIAdapter implements ResourceResolver {
private final ResourceResolver wrapped;
public ClasspathResolverURIAdapter() {
this.wrapped = ResourceResolverFactory.createDefaultResourceResolver();
}
#Override
public Resource getResource(URI uri) throws IOException {
if (uri.getScheme().equals("classpath")) {
URL url = getClass().getClassLoader().getResource(uri.getSchemeSpecificPart());
return new Resource(url.openStream());
} else {
return wrapped.getResource(uri);
}
}
#Override
public OutputStream getOutputStream(URI uri) throws IOException {
return wrapped.getOutputStream(uri);
}
}
Create the FOPBuilderFactory with your Resolver
FopFactoryBuilder fopBuilder = new FopFactoryBuilder(new File(".").toURI(), new ClasspathResolverURIAdapter());
Finally address your image
<fo:external-graphic src="classpath:com/mypackage/image.jpg" />
Because you use our own Resolver it is possible to do every lookup which you want.
By specifying the URL as a classpath URL like:
<fo:external-graphic src="classpath:fop/images/myimage.jpg"/>
In this example the file is a resource in the resource-package fop.images but the actual file gets later packed to some entirely different place inside the JAR, which is - however - part of the classpath, so the lookup as above works.

de.hybris.eventtracking.model.events.AbstractTrackingEvent cannot be resolved to a type

I just finished configuring hybris and tried to set up the eclipse project. As per guidelines in the wiki.hybris, I imported all the extensions into the eclipse project. When I try into build and clean, I get more than 3000 compiler errors. One of the errors is the class AbstractTrackingEvent cannot be resolved to a type. I looked for the particular class in the project folder. I could not find the folder events under de.hybris.eventtracking.model, which is the cause of the issue.
Am I missing anything while importing the project? There are many such type of issues in my eclipse project. Please let me know how to fix it. I have attached the screenshot for reference.
Note: I am using hybris-commerce-suite 5.7.0.8
As requested, I am adding the source code.
package de.hybris.eventtracking.services.populators;
import de.hybris.eventtracking.model.events.AbstractTrackingEvent;
import de.hybris.eventtracking.services.constants.TrackingEventJsonFields;
import de.hybris.platform.servicelayer.dto.converter.ConversionException;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* #author stevo.slavic
*
*/
public abstract class AbstractTrackingEventGenericPopulator implements
GenericPopulator<Map<String, Object>, AbstractTrackingEvent>
{
private final ObjectMapper mapper;
public AbstractTrackingEventGenericPopulator(final ObjectMapper mapper)
{
this.mapper = mapper;
}
public ObjectMapper getMapper()
{
return mapper;
}
protected Map<String, Object> getPageScopedCvar(final Map<String, Object> trackingEventData)
{
final String cvar = (String) trackingEventData.get(TrackingEventJsonFields.COMMON_CVAR_PAGE.getKey());
Map<String, Object> customVariablesPageScoped = null;
if (StringUtils.isNotBlank(cvar))
{
try
{
customVariablesPageScoped = getMapper().readValue(cvar, Map.class);
}
catch (final IOException e)
{
throw new ConversionException("Error extracting custom page scoped variables from: " + cvar, e);
}
}
return customVariablesPageScoped;
}
}
"As per guidelines in the wiki.hybris, I imported all the extensions into the eclipse project."
I don't think the guidelines tell you this. Basically, you want the projects loaded to be the same as those defined in your localextensions.xml and their dependencies. The reason you can't see those is they are not built.
Ensure you have run 'ant build' successfully, refresh the platform project, remove any extensions from your workspace that are not needed for your project, and clean and build in eclipse.
Make sure you have provided the project dependencies in each project by checking their individual extensioninfo.xml files as shown in below image.
Also sometimes dependent libraries are not imported properly check for those too.

Selenium WebDriver Stale Element Reference Exception for GWT

Ok I read all the other links, and i tried variants of the different solutions mentioned, however none of them work for me.
My Issue, I have the following Code:
package com.autotest.test.css;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.By;
import com.google.common.base.Predicate;
import java.util.concurrent.TimeUnit;
import cucumber.annotation.*;
import cucumber.annotation.en.*;
import static org.junit.Assert.assertEquals;
public class SaleStepsPre {
private WebDriver driver;
private String baseUrl;
#Before
public void setUp() {
System.setProperty("webdriver.chrome.driver", "/Users/AppData/Local/Google/Chrome/Application/chromedriver.exe");
driver = new ChromeDriver();
baseUrl = "http://xxxxx";
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
#Given("^I navigate to the css application$")
public void I_navigate_to_the_css_application() {
driver.get(baseUrl + "/care/a#brochureware-home");
}
#When("^I select the prepaid catalog$")
public void I_select_the_prepaid_catalog() {
driver.findElement(By.xpath("//div[#id='brochureware-home']/div/div/div/div[2]/div[2]/div/div")).click();
}
#When("^I select the add to basket for product$")
public void I_select_the_add_to_basket_for_product() {
driver.findElement(By.xpath("//*[#id='salesItem']/div[1]/div[1]/div/div[5]/div[1]/button")).click();
}
#When("^then I Click on the basket icon to go to basket$")
public void then_I_Click_on_the_basket_icon_to_go_to_basket() {
// times out after 5 seconds
// while the following loop runs, the DOM changes -
// page is refreshed, or element is removed and re-added
//driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
//WebElement searchBox;
//searchBox = driver.findElement(By.xpath("//input[#type='text']"));
//driver.findElement(By.xpath("html/body/div[2]/div[1]/nav/div[1]/div[3]/div[2]/div/ul[1]/li[5]/a/img")).click();
driver.findElement(By.cssSelector("c-menuimage")).click();
}
//#When("^then I click on the checkout button$")
//public void then_I_click_on_the_checkout_button() {
//driver.findElement(By.xpath("(//button[#type='button'])[9]")).click();
//}
#Then("^show product y$")
public void show_product_y() {
}
}
However I get following error:
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
B
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
This is the css path of basket icon, which is on a menu.
body > div:nth-child(3) > div:nth-child(1) > nav > div.container-fluid.c-wide > div.c-kill > div.collapse.navbar-collapse.c-2ndmenu > div > ul.nav.navbar-nav.navbar-left > li:nth-child(5) > a > img
The website is GWT, and the steps are:
1. Click on item add to basket
2. Adds to basket
3. Click on basket to go to basket.
However I cant seem to get this right.
I had problems, that the implicit wait only works for real page reloads, when the page is dynamicaly reloaded (like ajax) , then this will fail.
You can try expected conditions to wait for for items, they are nice and easy to use and robust. You can configure them to ignore certain exceptions,
so you can try to locate an element for a given time and then fail. This works even with ajax
In my case i have a small method like (it ignored the NoSuchElement exception):
protected <T> T waitForPageToLoad(ExpectedCondition<T> condition, String errorMessage) {
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(MAX_WAITING_TIME, SECONDS).ignoring(StaleElementReferenceException.class).ignoring(NoSuchElementException.class).pollingEvery(100, MILLISECONDS).withMessage(errorMessage);
T result = wait.until(condition);
return result;
}
MAX_WAITING_TIME is the time until this method throws an exception
Then you can use this with an expected condition like this:
public static final ExpectedCondition<Boolean> WAIT_FOR_BASKET = ExpectedConditions.visibilityOfElementLocated(By.cssSelector("c-menuimage"));
I have plenty of them in a utility class so they are static. you can do it like you want.
The full usage looks like:
WebElement elem = waitForPageToLoad(waitForPageToLoad);
elem.click();
This solution is originated here at stack overflow but i cant find the original question/answer, so kudos to the real guy who posted this

CQ5 - displaying a CQ.Notification in the frontend, when a workflow finished

I implemented workflows, but it would be nice to know if there are hooks provided by the client library which allow to hook in. When a workflow was triggered and finished, a CQ.Notification should be displayed. Or do i need to implement a polling library by myself?
As far as I know, there is no built-in CQ area to see when something is done, aside from looking here:
http://yoursite.com:port/libs/cq/workflow/content/console.html
Once there, you can go to the 'Instances' tab and see what's happening.
In one application that I worked on, we ended up writing our own method that sends notifications to us based on one of our workflows (our workflow ties into it - from the workflow models area, you can set your process to be a servlet that you've put into CQ). Here is the main piece of code from our servlet that catches the process being active, and then calls our methods to email us based on what it finds:
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.workflow.exec.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import java.util.Arrays;
public class YourServletName implements WorkflowProcess {
#Override
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args) throws WorkflowException {
session = workflowSession.getSession();
final WorkflowData data = workItem.getWorkflowData();
String type = data.getPayloadType();
String[] argStrings = args.get("PROCESS_ARGS", ARG_UPDATED).split(",");
String reason = argStrings[0];
String baseUrl = argStrings[1];
try {
if (type.equals(TYPE_JCR_PATH) && data.getPayload() != null) {
String resourcePath = data.getPayload().toString();
logger.info("Send Notification that {} has been {}.", resourcePath, reason.toLowerCase());
if (resourcePath != null && !resourcePath.isEmpty()) {
ResourceInfo resourceInfo = new ResourceInfo(resourcePath, baseUrl);
sendEmail(resourceInfo, reason);
}
}
} catch (EmailException ex) {
logger.warn("Failed to send Email");
throw new WorkflowException(ex);
} catch (MailingException ex) {
logger.warn("Failed to send Email");
throw new WorkflowException(ex);
}
}
}
You can find more info in the documentation for Extending Workflow Functionality.
Look at the first code block on that page, and that will give you the best idea of how you can implement a custom workflow handler.
EDIT
If you want to see it on the front-end, you could do an AJAX call to get the JSON list of currently running workflows - you can hit this url:
http://localhost:4502/etc/workflow/instances.RUNNING.json
Then you could loop through them and see if yours is in there. This isn't very nice though, since they are all just listed by IDs. I would instead suggest using the querybuilder, or again, just doing an AJAX GET. This is one example:
1_group.0_path=/etc/workflow/instances
2_group.0_type=cq:Workflow
0_group.property.2_value=COMPLETED
0_group.property=status
0_group.property.and=true
3_group.property=modelId
3_group.property.2_value=/etc/workflow/models/your-model-name/jcr:content/model
3_group.property.and=true
Then the URL would look something like this:
http://yoursiteurl:port/libs/cq/search/content/querydebug.html?_charset_=UTF-8&query=http%3A%2F%2Fyoursiteurl%3Aport%3F%0D%0A1_group.0_path%3D%2Fetc%2Fworkflow%2Finstances%0D%0A2_group.0_type%3Dcq%3AWorkflow%0D%0A0_group.property.2_value%3DRUNNING%0D%0A0_group.property%3Dstatus%0D%0A0_group.property.and%3Dtrue%0D%0A3_group.property%3DmodelId%0D%0A3_group.property.2_value%3D%2Fetc%2Fworkflow%2Fmodels%2Fyour-model-name%2Fjcr%3Acontent%2Fmodel%0D%0A3_group.property.and%3Dtrue
It's ugly, but it gets you the results you need, and then you can parse them to get further information you need.