Detecting dom changes with DOMSubtreeModified event - dom

Is there any way to subscribe to DOMSubtreeModified event?
module Subscriptions.Suscription exposing (subscriptions)
import Html.Events exposing (on)
import Json.Decode as Decode
import Models.MyModels exposing (MyModel)
import Update.Messages exposing (Msg(..))
subscriptions : MyModel -> Sub Msg
subscriptions model =
on "DOMSubtreeModified" (Decode.succeed (MyMSg model 0))
I get the following error:
This `on` call produces:
Html.Attribute Msg
But the type annotation on `subscriptions` says it should be:
Sub Msg

Related

Katalon: How to use the result of one test case in an another test case?

I have 2 different test cases which have different URL's.
Common thing between two URL's is the unique ID. I have captured the URL of one test case and split the URL of that test case and stored the ID in a variable. I made that variable a global variable and tried to use it in 2nd test case.
Now, I want to use that ID obtained from 1st test case in 2nd test case.
I got the error below:
**Test Case FAILED because (of) org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'ba0eed2c-cba8-11e8-86a5-02e9072e0d95' with class 'java.lang.String' to class 'internal.GlobalVariable'**
**Code for Test Case A is as follows:**
import static com.kms.katalon.core.checkpoint.CheckpointFactory.findCheckpoint
import static com.kms.katalon.core.testcase.TestCaseFactory.findTestCase
import static com.kms.katalon.core.testdata.TestDataFactory.findTestData
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import com.kms.katalon.core.checkpoint.Checkpoint as Checkpoint
import com.kms.katalon.core.checkpoint.CheckpointFactory as CheckpointFactory
import com.kms.katalon.core.mobile.keyword.MobileBuiltInKeywords as MobileBuiltInKeywords
import com.kms.katalon.core.mobile.keyword.MobileBuiltInKeywords as Mobile
import com.kms.katalon.core.model.FailureHandling as FailureHandling
import com.kms.katalon.core.testcase.TestCase as TestCase
import com.kms.katalon.core.testcase.TestCaseFactory as TestCaseFactory
import com.kms.katalon.core.testdata.TestData as TestData
import com.kms.katalon.core.testdata.TestDataFactory as TestDataFactory
import com.kms.katalon.core.testobject.ObjectRepository as ObjectRepository
import com.kms.katalon.core.testobject.TestObject as TestObject
import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WSBuiltInKeywords
import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUiBuiltInKeywords
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import internal.GlobalVariable as GlobalVariable
import org.openqa.selenium.Keys as Keys
WebUI.click(findTestObject('PO_ID_Details_Passport/label_Select Document Type'))
WebUI.click(findTestObject('PO_ID_Details_Passport/li_Passport'))
WebUI.setText(findTestObject('PO_ID_Details_Passport/input_PO_PASSPORT_NUMBER'), 'Test123456')
WebUI.setText(findTestObject('PO_ID_Details_Passport/input'), '25')
WebUI.setText(findTestObject('PO_ID_Details_Passport/input_1'), '05')
WebUI.setText(findTestObject('PO_ID_Details_Passport/input_2'), '2025')
// Capture the current URL and split the URL to get the unique ID.
String url = WebUI.getUrl()
String getQueryString = url.split("\\?")[1]
String[] getFields = getQueryString.split("&")
Map<String, String> fieldValueMap = new HashMap<String, String>()
for(String field : getFields) {
fieldValueMap.put(field.split("=")[0], field.split("=")[1])
}
println fieldValueMap.get("JID")
GlobalVariable JourneyID=fieldValueMap.get("JID")
//return JourneyID
Thread.sleep(5000)
WebUI.click(findTestObject('PO_ID_Details_Passport/Upload_File'))
Thread.sleep(3000)
//Sample path. Change it to your saved location of autoIT script
Runtime.getRuntime().exec('ABC')
Thread.sleep(5000)
WebUI.click(findTestObject('PO_ID_Details_Passport/i'))
]
How can I use the value of JourneyID in different test case?
you can use A global variable to store value as shown below.
GlobalVariable.JourneyID=fieldValueMap.get("JID")
But before using this variable, create a Global Variable named 'JourneyID' and pass some static value to it.
Now you can use it in other test cases.
Hope this will help you.

Catching AEM Content installation event

The use case here is to get the information of content with type cq:Page and dam:Asset that is being installed/updated in the JCR using package manager in AEM.
I would like to know if there are any event listener or API's that can be used for this purpose.
Is there a way to know if the content was installed/updated using the package manager?
AEM 6.2 is being used here.
Thanks!!
To detect Resource changes, you need to create a ResourceChangeListener
Here is an example based on ACS commons SampleResourceChangeListener but restricted to ADDED and CHANGED events.
import org.apache.felix.scr.annotations.*;
import org.apache.sling.api.resource.observation.ExternalResourceChangeListener;
import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChangeListener;
import org.apache.sling.event.jobs.JobManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* The Sling Resource Change Listener is the preferred method for listening for Resource Change events in AEM.
* This is preferred over the Sling Resource Event Listener, or the JCR Event Handler approaches.
*
* ResourceChangeListener Javadoc:
* - https://docs.adobe.com/docs/en/aem/6-2/develop/ref/javadoc/org/apache/sling/api/resource/observation/ResourceChangeListener.html
*
* Note: To listen for External events, implements the ExternalResourceChangeListener. If ONLY local events are in scope, implement only the ResourceChangeListener.
*/
#Component(
label = "Sample - Resource Change Listener",
description = "A sample implementation of the Sling Resource Change Listener",
metatype = true
)
#Properties({
// Scope the paths as tightly as possible based on your use-case.
#Property(
label = "Paths",
description = "[ Required ] A list of resource paths this listener will listen for change events.",
name = ResourceChangeListener.PATHS,
value = {"/content"}
),
// Scope the types as tightly as possible based on your use-case.
// If This property is not provided, ALL ChangeTypes will be accepted.
// Available values are defined on: ResourceChange.ChangeType
#Property(
label = "Change Types",
description = "[ Optional ] The change event types this listener will listener for. ",
name = ResourceChangeListener.CHANGES,
value = {"ADDED", "CHANGED"}
)
})
#Service
public class SampleResourceChangeListener implements ResourceChangeListener, ExternalResourceChangeListener {
private static final Logger log = LoggerFactory.getLogger(SampleResourceChangeListener.class);
#Reference
private JobManager jobManager;
public void onChange(#Nonnull List<ResourceChange> changes) {
// Iterate over the ResourceChanges and process them
for (final ResourceChange change : changes) {
// Process each change quickly; Do not do long-running work in the Resource Change Listener.
// If expensive/long-running work is required to handle the event, create a Sling Job to perform that work.
if (change.isExternal()) {
// Since this implements BOTH the ResourceChangeListener AND ExternalResourceChangeListener
// we can conditionally handle local vs external events.
}
switch (change.getType()) {
case ADDED:
log.debug("Change Type ADDED: {}", change);
if (change.getAddedPropertyNames().contains("someProperty")) {
// Do some work
// In this case we will pass some some data from the Event to a custom job via a custom Job topic.
final Map<String, Object> props = new HashMap<String, Object>();
props.put("path", change.getPath());
props.put("userId", change.getUserId());
jobManager.addJob("com/adobe/acs/commons/samples/somePropertyAdded", props);
}
break;
case CHANGED:
log.debug("Change Type CHANGED: {}", change);
if (change.getChangedPropertyNames().contains("someOtherProperty")) {
// Do some other work
}
break;
default:
// Do nothing
}
}
}
}
Alternatively, you can use a JcrEventListener, again ACS has a good example here: SampleJcrEventListener.java
I don't know of a way to detect if the cause of the add/update is package manager. However, if you want to execute some code before a package is installed, you can use InstallHook. I have not tried this before.

Handling events using ResourceChangeListener AEM 6.3

Can someone please help me in understanding how to implement a ResourceChangeListener and handle events using osgi R6 annotations?
I saw a similar post with no answer.AEM 6.3 - Creating Event handler using OSGi R6 annotations
The code snippet below registers a ResourceChangeListener with OSGI R6 annotations. The comments inline have the explanation.
import java.util.List;
import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChangeListener;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Component(
service = ResourceChangeListener.class,
property = {
// filter the notifications by path in the repo. Can be array and supports globs
ResourceChangeListener.PATHS+"="+"/content",
//The type of change you want to listen to.
//Possible values at https://sling.apache.org/apidocs/sling9/org/apache/sling/api/resource/observation/ResourceChange.ChangeType.html.
ResourceChangeListener.CHANGES+"="+"ADDED",
ResourceChangeListener.CHANGES+"="+"REMOVED",
ResourceChangeListener.CHANGES+"="+"CHANGED"
//PS: If you want to declare multiple values for a prop, you repeat it in OSGI R6 annotations.
//https://stackoverflow.com/questions/41243873/osgi-r6-service-component-annotations-property-list#answer-41248826
}
)
public class SampleResourceChangeListener implements ResourceChangeListener{ // Use ExternalResourceChangeListener to listen for changes that happen in a different node
public static final Logger LOGGER = LoggerFactory.getLogger(SampleResourceChangeListener.class);
//This method will be called with paths and types of change that occurred
//The task in this should be fast. In case it takes more time, trigger a sling job from here.
//The listener can be blacklisted if it's slow [it does for event handler, should be same for ResourceListener IMHO]
#Override
public void onChange(List<ResourceChange> list) {
list.forEach((change) -> {
LOGGER.info(change.getPath());
LOGGER.info(change.getType().toString());
//the methods to identify the property that changed are deprecated.
});
}
}
Some reference implementations within Sling
https://github.com/apache/sling-org-apache-sling-discovery-commons/blob/4f7d7ca3224239d52798cc8418ec8283f5eddc9e/src/main/java/org/apache/sling/discovery/commons/providers/spi/base/IdMapService.java
https://github.com/apache/sling-org-apache-sling-scripting-java/blob/89c28859a7df17a40eaaf2c26ee2433c98830204/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java

How to create an initial Observable<T> in an Angular2 service

I am currently attempting to return an observable from a service in Angular2. If you look at the following code, if I uncomment the line in the constructor, everything works fine, and the consumer of the service won't break. But when I try to remove the call from the constructor, it crashes with:
Error: XHR error (404 Not Found) loading http://localhost:3847/rxjs/observable
I believe that it is trying to subscribe to the todo$ property prior to initialisation. So how can I create an initial observer that doesn't actually make the call to the get method straight away? That is, I need some sort of empty Observer that will stop the subscribe line from falling over.
How am I supposed to achieve this?
Tony
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import {Todo} from './todo';
import {Observable} from 'rxjs/observable'
#Injectable()
export class TodoService {
public todos$: Observable<Todo[]>;
constructor(private http: Http) {
//this.todos$ = this.http.get('api/Todo').map(res => <Array<Todo>>res.json());
}
loadData() {
this.todos$ = this.http.get('api/Todo').map(res => <Array<Todo>>res.json());
}
}
import {Observable} from 'rxjs/observable'
should be
import {Observable} from 'rxjs/Observable';
^

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.