Java - GraphStream node modified event listener - graphstream

In my code, I have a listener on mouse released, and in there, I have a snippet like this:
for (Node n : gs){
Object o = n.getAttribute("ui.selected");
if (o != null && (Boolean)(o)){
nodes[num++] = n;
}
}
The problem is that the event manager hasn't updated all of the selected nodes to set the ui.selected attribute. This is a race condition.
I seem to be missing how to add an event listener to a node, or to the view for when nodes are modified.
I am trying to calculate metrics on a set of selected nodes.

Related

programmatically setting cq:tags save blank value in the node in AEM

I am trying to programmatically extract data from a json string, converts into a string array and adding it as cq:tags property and corresponding values into a node, however when I do so, though cq:tags property is added but with blank values.
My node is something like this: /content/<my project node>/ContentPage/jcr:content
ResourceResolver resolver = CommonUtils.getResourceResolver(resourceResolverFactory);
String[] strValue = tagList.stream().toArray(String[]::new); // tagList has String values in form of array.
Resource resource = resolver.getResource(CONTENT_DATA_NODE);
if (resource != null) {
Node node = resource.adaptTo(Node.class);
if (node != null) {
NodeIterator nodeIterator = node.getNodes();
while (nodeIterator.hasNext()) {
innerNode = nodeIterator.nextNode();
innerNode.setProperty(CQ_TAGS, strValue);
innerNode.getSession().save();
}
}
}
and my sling user mapper service is mybundle.core:datawrite=userdatawriter , also if my resource resolverfactory is null, I get resolver from request directly.
Initially, I thought it could be an access issue, so I programmatically tried with any random property and value:
property: xyz , values: aa,bb,cc,dd
Which is written by my code without any issues,
it is only when programmatically adding cq:tags is when the problem arises. Though I can add cq:tags with any long list of values manually without any issues, either from page properties or in the crxde node itself.
What am I missing here and doing wrong in the code which can not only add cq:tags but also overwrite if cq:tags exists.
P.S: my AEM version is AEM 6.5 SP2
I can see the same thing happen in AEM 6.4.3. Immediately upon saving the property, the value can be read as expected. Here's a few quick examples I ran in the AEM Groovy console.
def node = getNode('/content/screens/we-retail/apps/virtual-showroom/en/jcr:content')
String[] arr = ['a', 'b', 'c'];
String[] tagArr = ['we-retail:equipment', 'we-retail:activity/biking']
node.setProperty('foo', arr)
println node.getProperty('foo').values // prints the a, b,c tags
node.setProperty('cq:tags', tagArr)
session.save()
println node.getProperty('cq:tags').values // prints the a, b,c tags
println node.getProperty('foo').values // prints the a, b,c tags
However, upon inspecting the page in CRXDE, I can see that the property is empty. This does not happen when the values you use match existing tags in AEM. For example:
def node = getNode('/content/screens/we-retail/apps/virtual-showroom/en/jcr:content')
String[] arr = ['a', 'b', 'c'];
String[] tagArr = ['we-retail:equipment', 'we-retail:activity/biking']
node.setProperty('foo', arr)
println node.getProperty('foo').values
node.setProperty('cq:tags', tagArr)
println node.getProperty('cq:tags').values // prints the we-retail tags
session.save()
println node.getProperty('foo').values
println node.getProperty('cq:tags').values // prints the we-retail tags
and the same values are visible in CRXDE.
This behaviour, I believe, is controlled by the Day CQ Tagging Service (com.day.cq.tagging.impl.JcrTagManagerFactoryImpl)
Unchecking the box will disable validation and allow you to persist those values. However, tagging a page with tags that don't exist will cause its own share of problems. Instead, I would suggest making sure to create those tags before using them.

ag-Grid set filter and sort model without triggering event

I am updating sort & filter models via api:
this.gridApi.setFilterModel(filterModels);
this.gridApi.setSortModel(sortModels);
The problem with this is I have a server request bound to the change even of both sort & filter so when user changes then the data is updated. This means when I change model on code like restoring a state or resetting the filters it causes multiple requests.
Is there a way to update the filter/sort model without triggering the event?
I see there is a ColumnEventType parameter but couldn't see how it works. Can I specify some variable that I can look for inside my event handlers to get them to ignore calls that are not generated from user?
I am trying to manage URL state so when url query params change my code sets the models in the grids but this ends up causing the page to reload multiple times because the onFilter and onSort events get called when the model is set and there is no way I can conceive to prevent this.
At the time, you are going to have to manage this yourself, ie, just before you call the setModel, somehow flag this in a shared part of your app (maybe a global variable)
Then when you react to these events, check the estate of this, to guess where it came from.
Note that at the moment, we have added source to the column events, but they are not yet for the model events, we are planning to add them though, but we have no ETA
Hope this helps
I had to solve similar issue. I found solution which working for my kind of situation. Maybe this help someone.
for (let j = 0; j < orders.length; j++) {
const sortModelEntry = orders[j];
if (typeof sortModelEntry.property === 'string') {
const column: Column = this.gridColumnApi.getColumn(sortModelEntry.property);
if (column && ! column.getColDef().suppressSorting) {
column.setSort(sortModelEntry.direction.toLowerCase());
column.setSortedAt(j);
}
}
this.gridApi.refreshHeader();
Where orders is array of key-value object where key is name of column and value is sorting directive (asc/desc).
Set filter without refresh was complicated
for (let j = 0; j < filters.length; j++) {
const filterModelEntry = filters[j];
if (typeof filterModelEntry.property === 'string') {
const column: Column = this.gridColumnApi.getColumn(filterModelEntry.property);
if (column && ! column.getColDef().suppressFilter) {
const filter: any = this.gridApi.getFilterApi(filterModelEntry.property);
filter['filter'] = filterModelEntry.command;
filter['defaultFilter'] = filterModelEntry.command;
filter['eTypeSelector'].value = filterModelEntry.command;
filter['filterValue'] = filterModelEntry.value;
filter['filterText'] = filterModelEntry.value;
filter['eFilterTextField'].value = filterModelEntry.value;
column.setFilterActive(true);
}
}
}
Attributes in filter:
property - name of column
command - filter action (contains, equals, ...)
value - value used in filter
For anyone else looking for a solution to this issue in Nov 2020, tapping into onFilterModified() might help. This gets called before onFilterChanged() so setting a value here (eg. hasUserManuallyChangedTheFilters = false, etc.) and checking the same in the filter changed event is a possible workaround. Although, I haven't found anything similar for onSortChanged() event, one that gets called before the sorting is applied to the grid.
I am not sure any clean way to achieve this but I noticed that FilterChangedEvent has "afterFloatingFilter = false" only if filterModel was updated from ui.
my workaround is as below
onFilterChanged = event:FilterChangedEvent) => {
if(event.afterFloatingFilter === undefined) return;
console.log("SaveFilterModel")
}

How to sessionize stream with Apache Flink?

I want to sessionize this stream: 1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,0,3,3,3,5, ... to these sessions:
1,1,1
2,2,2,2,2
3,3,3,3,3,3,3
0
3,3,3
5
I've wrote CustomTrigger to detect when stream elements change from 1 to 2 (2 to 3, 3 to 0 and so on) and then fire the trigger. But this is not the solution, because when I processing the first element of 2's, and fire the trigger the window will be [1,1,1,2] but I need to fire the trigger on the last element of 1's.
Here is the pesudo of my onElement function in my custom trigger class:
override def onElement(element: Session, timestamp: Long, window: W, ctx: TriggerContext): TriggerResult = {
if (prevState == element.value) {
prevState = element.value
TriggerResult.CONTINUE
} else {
prevState = element.value
TriggerResult.FIRE
}
}
How can I solve this problem?
I think a FlatMapFunction with a ListState is the easiest way to implement this use-case.
When a new element arrives (i.e., the flatMap() method is called), you check if the value changed. If the value did not changed, you append the element to the state. If the value changed, you emit the current list state as a session, clear the list, and insert the new element as the first to the list state.
However, you should keep in mind that this assumes that the order of elements is preserved. Flink ensures within a partition, i.e, as long as elements are not shuffled and all operators run with the same parallelism.

How do I add EventTriggers to Multiple instantiated prefabs from a list?

I have a prefab which I am spawning a dynamic amount of.
I want to attach an event trigger to each one of them, on pointerclick, to call a method accepting an int as parameter.
I have the following code which partly works, however the event added to each prefab uses the same parameter, even though they are given as beign different.
foreach (EasterEgg EE in AllEasterEggs.List)
{
Transform x = Instantiate(EasterEggPrefab);
...
EventTrigger.Entry Entry = new EventTrigger.Entry();
Entry.eventID = EventTriggerType.PointerClick;
Entry.callback.AddListener((eventData) => { EasterEggClicked(EE.ID); });
x.GetChild(1).GetComponent<EventTrigger>().triggers.Add(Entry);
}
EE.Id on the first item will be 0, then it will be 1, then 2 etc. I have debugged to ensure that when it is adding the listener that EE.Id is the correct number, and this is true. The trigger is being added correctly.
However when I trigger the trigger (how to say that?), the parameter beign passed is always the parameter of the last item in that list. For example, if AllEasterEggs.List contains 5 elements, all elements will have a trigger on pointer click calling EasterEggClicked(4), whereas they should be EasterEggClicked(0) thru EasterEggClicked(4).
As a request, this is the answer:
Instead of passing EE object to anonimous delegate, just store value of EE.ID before and pass this:
foreach (EasterEgg EE in AllEasterEggs.List)
{
Transform x = Instantiate(EasterEggPrefab);
...
EventTrigger.Entry Entry = new EventTrigger.Entry();
Entry.eventID = EventTriggerType.PointerClick;
int ID = EE.ID;
Entry.callback.AddListener((eventData) => { EasterEggClicked(ID); });
x.GetChild(1).GetComponent<EventTrigger>().triggers.Add(Entry);
}

Implementing Enqueue and Dequeue for Queue using Alloy

Having the following:
sig Queue { root: Node }
sig Node { next: lone Node }
fact nextNotReflexive { no n:Node | n = n.next }
fact nextNotCyclic { no n:Node | n in n.^next }
Can anyone help on the implementation of the Enq and Deq?
pred Enq[q,q':Queue, n:Node]{}
pred Deq [q,q':Queue]{}
Any help is appreciated.
You can define enqueue easily:
pred Enq[q, q': Queue, n: Node] {
q'.root = n and n.next = q.root
}
But dequeue is not nearly as easy. The problem is that you need to modify a Node, not a Queue, in order to make the change to the last node that's required to dequeue an element. You actually need to replace the second-to-last Node in the Queue with a different Node whose "next" field is empty -- but since you're using atom identity to represent node uniqueness, that Node will actually be a different Node.