Programmatically arranging contents in aem 6.4 - java

everyone. I'm new in working with aem. I'm using aem 6.4. My task is to programmatically sort the order of the contents of a cq:project in aem depending on the content of a JSON file.
The content of the JSON file should be set as the initial child instead of the children sorted by their creation date.
This is the current structure of my cq:page. If the child2 is the one indicated in the JSON file, it should be the first one to be displayed. The content of the JSON file is just the name of one child so even though there are 10 children, the content of the JSON file should always be the first one in the list.
I've spent hours researching on how I can implement this although I still can't find any solution. Any insights on how should I create this? Thanks!

As I understand it, you want a way to order a named child of a cq:Page to be first in the list.
This is possible because cq:Page is an orderable node. This would not be possible otherwise. you chan check any nodetype in CRX Explorer.
I think adding the bit about JSON complicates the question. You just need a simple method such as the following:
private void orderAsFirstChild(String childName, Node parentNode) throws RepositoryException {
if (parentNode.hasNode(childName)) {
// find current first child name
String firstChildName = Optional.ofNullable(parentNode.getNodes())
.map(NodeIterator::nextNode)
.map(node -> {
try {
node.getName();
} catch (RepositoryException e) {
e.printStackTrace();
}
return (String) null;
}) //
.orElse(null);
parentNode.orderBefore(childName, firstChildName);
}
}
You should probably clean this up a little, but this is the general idea using Node#orderBefore

This may helps -
Get the children from the parent node.(you will get 'iterator' convert it to list here-Convert Iterator to ArrayList)
Delete all child nodes now. And keep the back up of above list.
iterate through the list , identify the node which you want place first(by title or some other property) add that to a separate set(LinkedHashSet- to maintain order).
Now add the remaining items/nodes in the same order after your specific node in the above set.(you may need to iterate through again)
Now this Set has nodes/Resources in the order which you want, iterate , create nodes and save your changes.

Related

Weird stuff happening when moving objects from one YAML list to other

I have a problem regarding YAML files.
When I try moving objects from one list to another inside of a .yml file and save it, weird stuff like this happens:
queued: &id001 []
current: *id001
What's supposed to happen:
current: Fraithor # <= Minecraft username, from queued, moved when running reQueue()
queued: [] # <= Or just nothing / delete list
reQueue() method:
for (String path : FileBasics.FILETYPE.BANWAVE.getConfig().getStringList("queued")) {
List<String> list = FileBasics.FILETYPE.BANWAVE.getConfig().getStringList("current");
List<String> arrayList = new ArrayList<>();
arrayList.add(path);
list.addAll(arrayList);
FileBasics.FILETYPE.BANWAVE.getConfig().set("current", list);
list.remove(path);
FileBasics.FILETYPE.BANWAVE.getConfig().set("queued", list);
try {
FileBasics.FILETYPE.BANWAVE.getConfig().save(FileBasics.FILETYPE.BANWAVE.getFile());
} catch (IOException e) {
e.printStackTrace();
}
}
}
Obviously, I'm using a seperate class/emnum for the File saving (FileBasics). It's a pretty long code, so I pasted it on pastebin HERE (https://pastebin.com/XsqvYTBb)
You're pushing the same list to both current and queued. Java has reference semantics meaning that if you push arrayList to current, current holds a reference to arrayList so if you alter it, current will point to the altered list.
Since you push the very same list to queued, YAML will add an anchor &id001 when the list first occurs, and an alias *id001 to refer to the same list afterwards.
Since you don't want a list in current at all, it seems you want to do
FileBasics.FILETYPE.BANWAVE.getConfig().set("current", path);
Though I have no idea what kind of API this is and whether it accepts a string.

TableViewer.getElementAt() returning a filtered element

I'm trying to automatically select the first item in a filtered table.
I'm essentially doing the following:
table = new TableViewer(...);
table.addFilter(filter);
table.setContentProvider(contentProvider);
table.setInput(input);
first = table.getElementAt(0);
table.setSelection(new StructuredSelection(first));
The surprising thing is that (depending on the filter) I can get an element that is filtered out from getElementAt(0). The result is that ultimately, no item will be selected.
I have tried calling table.refresh() before getting the element with the same results.
If I call getElementAt(0) at a later point, I do indeed get the correct first element (that is not filtered out).
How can I make getElementAt respect the filtering immediately?
In my experience, the most reliable way to select the first (visible) element is - for once only - to bypass JFace, rely on its internal data model, and use SWT API to select the first TableItem like this:
static Object selectFirstElement(TableViewer tableViewer) {
Object firstElement = null;
Table table = tableViewer.getTable();
if (table.getItemCount() > 0) {
firstElement = table.getItem(0).getData();
tableViewer.setSelection(new StructuredSelection(firstElement), true); // true == reveal
}
return firstElement;
}
I've been using this code successfully for several years with sorted, filtered, and virtual tables.
Well, I found what was wrong and it was my own fault. The filter I set is mutable so it can filter more or less strictly. The problem was that I activated the more strict filtering after I set the selection.
Thanks everyone for the help anyways.

How to set the content of a RichTextItem field in a Notes document?

This one seems like it should be simple enough. I'm writing a Notes Agent in Java; it calculates a fairly large amount of numeric data (a 6400-entry array of doubles) that I want to store in an existing document, updating a field. Because of Notes' field limitations, I figured I needed to use a RichText field to do that. (My initial attempt to write to a multi-value Number field resulted in it failing to save somewhere between an array of size 4000 and 5000.) It's not clear to me how one stores that value in a RichTextItem, though. All my attempts have failed. In one case, using doc.replaceItemValue(), it seemed to convert the item to a Text List. Getting the item, casting it to a RichTextItem, and calling setValues() or setValueString() doesn't seem to do anything. This shouldn't be this hard! Any pointers?
(Alternately: Any better suggestion for how to store my array in a document in the database?)
Thanks,
Reid
You'll need to create a RichTextItem and use the methods on that object to populate it:
import lotus.domino.*;
import java.util.Vector;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
AgentContext agentContext =
session.getAgentContext();
// (Your code goes here)
Database db = agentContext.getCurrentDatabase();
Document doc = db.createDocument();
Item subject = doc.replaceItemValue("Subject",
"Project description");
RichTextItem body = doc.createRichTextItem("Body");
body.appendText("Cartoon book for children
ages 9-12");
// Print text of subject and body
System.out.println(subject.getText());
System.out.println(body.getText());
// Save the document
doc.save(true, true);
} catch(Exception e) {
e.printStackTrace();
}
}
}
UPDATE:
If you need to edit an existing document, instead of creating a new rich text item, you would get the existing one.
RichTextItem body = doc.GetFirstItem("Body"); // instead of createRichTextItem
You can bypass the Notes' field limitations. You can flag your item as «contains non-summary data» by using the NotesItem.IsSummary property. You need to set this property to false. But remember, you cannot use this item in views and folders.
Here is example:
Vector vector = new Vector();
for (int index = 0; index<6400;index++)
vector.addElement(new Double(Math.random()*100));
Item item = document.replaceItemValue("YourFieldName", vector);
item.setSummary(false);
document.save(true,true);
As for the question of "better" solution. I've recently written some code where I serialize/deserialize Java objects as JSON strings. This way they are well readable and easily restorable. I guess for the plain array it's a little problem. Especially if you do not want to restore it and have not interest to look at it (well, but probably it should be one or other :-)
And yes, you have to store it in the rich text anyway. Alternative you might write a text document and attach it in the RT field (again RT :-). Pretty usual scenario and easy to do.
Finally you could store data as database objects, but I guess from Java you do not really have access to do it. And it does not seem to be in any way better.

How to get all existing groups in jcr?

I want to fetch a list of all existing groups in CQ5 JCR. I am able to fetch a list of all existing users in the JCR using following code,
UserManager userManager = jkrSession.getUserManager();
final List<String> users = new ArrayList<String>();
Iterator<Authorizable> iter = userManager.findAuthorizables(
"jcr:primaryType", "rep:User");
while (iter.hasNext()) {
Authorizable auth = iter.next();
if (!auth.isGroup()) {
users.add(auth.getID());
}
}
I haven't found any way to get a list of all existing users. Although, I can see the parent nodes /home/users and /home/groups and I can iterate over the child nodes to fetch users and groups.
I am looking for an easier way out.
The title of your question doesn't sync with your question's content.
First, the following code is really unnecessary, as you are searching for rep:User, and hence only users would be available in the iterator, thereby making your if check fail every time.
Authorizable auth = iter.next();
if (!auth.isGroup()) {
users.add(auth.getID());
}
Hence the while loop could be rewritten as
users.add(iter.next().getID());
Second, if it is the list of all existing groups that you want to fetch, then you can use
Iterator<Authorizable> iter = userManager.findAuthorizables(
"jcr:primaryType", "rep:Group");
This would return only the groups that are present in your instance.
But, if it is both, users and groups that you want to fetch, may be you can try this.
Iterator<Authorizable> iter = userManager.findAuthorizables(
"profile/jcr:primaryType", "nt:unstructured", UserManager.SEARCH_TYPE_AUTHORIZABLE);
This would return all the authorizables that are present in the instance. It is not mandatory that you have to specify only profile/jcr:primaryType and nt:unstructured as the property and value. You can use the relative path to any property which would be present in all the authorizables, containing the same value if you want to list all the authorizables(in my case profile/jcr:primaryType caught my eye first), else the results would be filtered to those authorizables for whom the property value matches.
For further reference you can check the docs.

Getting Lotus Notes data from Document

I am using a local database in my version of Lotus notes(8.5.2), and I am trying to get the data for two things:
The highlighted document/item in a NotesUIView
The document selected in a NotesUIDocument
However, all I get are the Notes URLs and I don't know what I should do with those. Can anyone help me out/throw me a breadcrumb?
P.S. Yes I am using the Java API for Eclipse.
Here is a code sample of what I do:
NotesUIWorkspace workSpace = new NotesUIWorkspace();
NotesUIElement currentElement = workSpace.getCurrentElement();
if (currentElement instanceof NotesUIView) {
NotesUIView currentView = (NotesUIView) currentElement;
NotesUIViewEntryCollection collection = currentView
.getActionableEntries();
Iterator docIterator = collection.documentIterator();
while (docIterator.hasNext()) {
NotesUIDocumentEntry entry = (NotesUIDocumentEntry) docIterator.next();
//I can't seem to get to the NoesUIDocument case like I can below... I want fields!
}
}
if(currentElement instanceof NotesUIDocument){
NotesUIDocument document = (NotesUIDocument) currentElement;
//Seem to be able to get the correct data fields only in this case!
document.getFields();
}
Fetching the "current" document is usually done via the NotesAgentContext.UnprocessedDocuments. In a view, that might return a collection of documents if the user as ticked several.
If you already have an NotesUIView, NotesUIView.getActionableEntries will give you the selected document(s).
When you have a NotesDocumentData instance, NotesUIWorkspace.openDocument can be used to open it up in edit mode. Then NotesUIWorkspace.getCurrentDocument can be used to get hold of the UI Document.
Notice that if you only want to read values from the document, it is more convenient to use the back-end classes like Document.
Have you got a URL as an example? If it includes the UUID of the document in question then you should be able to reference it directly with a getDocument(). Otherwise, the URL should include a view reference and a lookup key for that view in question.

Categories

Resources