How do I recursively display all files and subfolders? - alfresco

I'm using the Alfresco Rest Api but I can't find any option that would return the whole tree with all sub-folders.
I want to go down to the last file even if it's 'wrapped' in 3 sub folders.
Any ideas ?

Please refer categoryService to list all files in any nested sub folders. Here
nodeRef is parent folder's noderef
Using categoryService it is also possible to list all the children of a folder.
Collection<ChildAssociationRef> children = categoryService.getChildren(new NodeRef(nodeRef), CategoryService.Mode.ALL, CategoryService.Depth.ANY);

I don't think you can.
You could execute a PATH query though, since it can be written in a way to return all children, too.
For example:
var folder = search.luceneSearch("+PATH:\"/app:company_home/cm:Test_x0020_Folder//*\" AND (TYPE:\"cm:content\" OR TYPE:\"cm:folder\")");

Create a java baked webscript which will return the node of below object.
public class ReportNode {
private NodeRef currentNode;
private List<ReportNode> children;
private Map<String, String> properties = new HashMap<>();
private boolean isFolder;
private String name;
private String type;
private List<String> aspects;
//Getter Setters
}
In above structure
currentNode represents the current nodered in list
children represents the children of a node
Other things are well understood.
Fill up the data in above linked list structure by node crawling.
For displaying the crawled data.You can use the below freemarker template.
<#macro recurse_macro nodeRef>
<ul>
<li>
<#print_properties reportNode=nodeRef/>
</li>
</ul>
</#macro>
<#macro print_properties reportNode>
<ul>
<li>
<a>Properties</a>
<ul>
<#list reportNode.properties?keys as key>
<li>${key} : ${reportNode.properties[key]}
</#list>
</ul>
</li>
</ul>
</#macro>
<#recurse_macro nodeRef=nodeRef/>
where noderef is root node of the linked list which is created by crawling the nodes.

To retrieve all documents you can use this service
http://localhost:8080/share/service/components/documentlibrary/data/doclist/all/site/XXXX/documentLibrary?filter=all&noCache=1521477198549
Or you can create your custom webscript and get nodes recursively like that for example:
/**
*
* #param type
* #param nodeRef
* #return true if node type equals or inherit from type <code>type</code>
*/
protected boolean hasSubType(QName type, NodeRef nodeRef) {
List<QName> subTypes = new ArrayList<>();
subTypes.addAll(dictionaryService.getSubTypes(type, true));
QName nodeType = nodeService.getType(nodeRef);
return nodeType.equals(type) || subTypes.contains(nodeType);
}
private void getNodesRecursive(NodeRef node, List<NodeRef> documents) {
if (hasSubType(ContentModel.TYPE_FOLDER, node)) {
List<ChildAssociationRef> children = nodeService.getChildAssocs(node, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef child : children) {
NodeRef childNode = child.getChildRef();
if (hasSubType(ContentModel.TYPE_CONTENT, node)) {
documents.add(childNode);
} else if (hasSubType(ContentModel.TYPE_FOLDER, node)) {
// documents.add(childNode);
getNodesRecursive(childNode, documents);
}
}
} else {
documents.add(node);
}
}

Related

How to get Alfresco node knowing its text string representation of a node ref?

I have a string representation of Alfresco node, saying "workspace://SpacesStore/1ed7e740-9d01-4b5a-8a63-8284094e6c71" and need a NodeRef object from it.
NodeRef connectedDocument = new NodeRef(s);
nodeService.getProperty(connectedDocument, NDBaseDocumentModel.PROP_MARK)
When I trying to get its property I got error:
org.alfresco.service.cmr.repository.InvalidNodeRefException: Node does not exist: "workspace://SpacesStore/1ed7e740-9d01-4b5a-8a63-8284094e6c71" (status:null),
org.alfresco.repo.node.db.DbNodeServiceImpl.getNodePairNotNull(DbNodeServiceImpl.java:198),
org.alfresco.repo.node.db.DbNodeServiceImpl.hasAspect_aroundBody38(DbNodeServiceImpl.java:1043),
org.alfresco.repo.node.db.DbNodeServiceImpl$AjcClosure39.run(DbNodeServiceImpl.java:1),
org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:149),
org.alfresco.traitextender.RouteExtensions.intercept(RouteExtensions.java:100),
org.alfresco.repo.node.db.DbNodeServiceImpl.hasAspect(DbNodeServiceImpl.java:1037),
sun.reflect.GeneratedMethodAccessor284.invoke(Unknown Source),
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43),
java.lang.reflect.Method.invoke(Method.java:498),
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317),
and when I tried "solr-alfresco" search I got an exception:
org.alfresco.repo.search.impl.lucene.LuceneQueryParserException: 11170021 Request failed 400
Please tell me, how to get a node knowing its string representation?
Below is the code to Get all properties from the node or a single property from the node.
String nodeId = request.getParamater("nodeId"); //You can get the param from request for example
if (StringUtils.isNumeric(nodeId)) {
final NodeRef nodeReference = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<NodeRef>() {
#Override
public NodeRef doWork() {
return nodeService.getNodeRef(Long.valueOf(nodeId));
}
}, AuthenticationUtil.getSystemUserName());
if (nodeReference !=null){
//Get all properties from the node
final Map<QName, Serializable> properties = nodeService.getProperties(nodeReference);
//OR
//Get A property from the node. Example: ContentModel.PROP_TITLE
final QName aProp = nodeService.getProperty(nodeReference, propQName);
//OR
nodeService.setProperty(actionedUponNodeRef, propQName, "A value");
}
}
Update :
getNodeFromString
public ScriptNode getNodeFromString(String nodeRefString)
Gets a JS node object from a string noderef
Parameters:
nodeRefString - string reference to a node
Returns:
a JS node object
UPDATE :
https://github.com/Alfresco/alfresco-repository/blob/master/src/main/java/org/alfresco/repo/jscript/ScriptUtils.java
* Gets a JS node object from a string noderef
*
* #param nodeRefString string reference to a node
* #return a JS node object
*/
public ScriptNode getNodeFromString(String nodeRefString)
{
NodeRef nodeRef = new NodeRef(nodeRefString);
return (ScriptNode)new ValueConverter().convertValueForScript(this.services, getScope(), null, nodeRef);
}

JcrExportCommand filter to exclude "mgnl:page" in magnolia cms

I would like filter out "mgnl:page" nodes for the JcrExportCommand in magnolia when I execute it on a node with a custom action.
The filter I wrote in the code below doesn't work. It still gives me mgnl:page children nodes in the exported file.
//set filter to only export mgnl:area subnodes
DefaultFilter filter = new JcrExportCommand.DefaultFilter();
NodeFilteringPredicate nodePredicate = new NodeFilteringPredicate();
nodePredicate.setNodeTypes(Lists.newArrayList("mgnl:area"));
filter.setNodePredicate(nodePredicate);
How do I set the correct filter to export everything but "mgnl:page" subnodes? I believed that setting the NodeFilteringPredicate to "mgnl:area" I get only nodes that are of that type.
You have to set the filter on JcrExportCommand for it to take effect:
DefaultFilter filter = new DefaultFilter();
filter.getNodePredicate().getNodeTypes().add("mgnl:page");
jcrExport.setFilter(Collections.singletonMap("website", filter));
* this is not the answer to my question but instead the answer to a comment since code is not properly formated in a comment *
As #michid suggested I created a custom Predicator and used JcrExportCommand.DefaultFilter#setNodePredicate()to apply it.
I am expecting to get an exported YAML with filtered nodes according to the Predicate but instead I am still getting all the nodes (including children of type mgnl:page).
My custom Predicate class is:
public class MyPredicate extends NodeFilteringPredicate {
public boolean evaluate(Node node) throws AccessDeniedException, ItemNotFoundException, RepositoryException {
//only nodes that are not of type mgnl:page
if((node.getParent().getPrimaryNodeType().getName().contains("mgnl:page"))&&(node.getPrimaryNodeType().getName().contains("mgnl:page"))) {
return false;
}else{
return true;
}
}
}
My custom Action class is:
public class MyAction extends AbstractMultiItemAction<UzhVersioning> {
private AbstractPredicate<Node> MyPredicate;
public MyAction(xxxVersioning definition, JcrItemAdapter item, UiContext uiContext) {
super(definition, item, uiContext);
// TODO Auto-generated constructor stub
}
#Override
public void execute() {
//export nodes from a JCR workspace
JcrExportCommand exporter = new JcrExportCommand();
//sets export format to yaml
exporter.setFormat("yaml");
exporter.setRepository("website");
//set filter to only export top mgnl:page and its mgnl:area nodes
DefaultFilter filter = new JcrExportCommand.DefaultFilter();
AbstractPredicate<Node> predicate = new MyPredicate();
filter.setNodePredicate(predicate);
exporter.setFilters(Collections.singletonMap("website", filter));
//setup the root directory for exports
File rootDir = new File("/Users/asusti/Downloads/yamlExport");
// clean up first
rootDir.delete();
rootDir.mkdirs();
//get root node
Node node = (Node) getItems().get(0).getJcrItem();
try {
//set export path
exporter.setPath(node.getPath());
File file = new File(rootDir, node.getName()+".yaml");
FileOutputStream out = new FileOutputStream(file);
exporter.setOutputStream(out);
exporter.execute(MgnlContext.getInstance());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

how can I iterate over a list of objects in sightly?

I have created a Java class method getmyPages() which returns iterator<Page>.
Now in HTML page I am able to instantiate the class and access other properties of this class.
However I want to iterate over this iterator the way currentPage.listChildren works.....
Since currentPage.listChildren returns iterator<Page>
I am also returning same.
However I am not able to ...... the HTML tag in which I am printing this comes out empty.
You can use data-sly-list attribute to loop over an iterator. Here's an excerpt from Feike Visser's Sightly tutorials :
<ul data-sly-list.child="${currentPage.listChildren}">
<li>${child.title}</li>
</ul>
data-sly-unwrap attribute can be used to prevent enclosing tag of the loop from being part of the final mark up
<ul data-sly-list.child="${currentPage.listChildren}" data-sly-unwrap>
<li>${child.title}</li>
</ul>
Link to the tutorials : http://blogs.adobe.com/experiencedelivers/experience-management/sightly-intro-part-1
Documentation of data-sly-list : link
java class
public class TabControl extends WCMUse {
#Override
public void activate() throws Exception {
// nothing to be done here in this case
}
public Iterator<Map<String, Object>> getTabTitles(){
final I18n i18n = new I18n(getRequest());
List<Map<String, Object>> infos = new LinkedList<Map<String,Object>>();
String[] tabTitles = getProperties().get("tabs", String[].class);
if (tabTitles == null || tabTitles.length == 0) {
tabTitles = new String[1];
tabTitles[0] = i18n.get("Tab One from sightly");
Map<String, Object> map = new HashMap<String, Object>();
map.put("tabTitle", tabTitles[0]);
infos.add(map);
}else if(tabTitles.length > 0){
for (String tab : tabTitles) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("tabTitle", tab);
infos.add(map);
}
}
return infos.iterator();
}
}
In my Java code I'm returning a List then using Sightly
Java Class
public class ListFilesUse extends WCMUsePojo{
private String name;
private List<TrFile> files = new ArrayList<TrFile>();
Sightly
<div data-sly-use.test="apps.ecolorado.components.sharedcontent.ListFilesUse">
${test.name}
<ul data-sly-list.child="${test.files}">
<li>${child.fileName}</li>
</ul>
</div>
And this is working in progress code.

Retrieve property by name

I'm struggling to create a dynamic view generation utility for javafx. I've a handful of Classes that have ObjectProperty's or StringProperty's I'd like to create a ComboBox for each property and bind directly the combo selected value to the Class property by name if possible. Is there some helper or method in any of the javafx.beans.binding that would allow me to specify an Object and a String name and retrieve the property. Or to just retrieve a list of properties. I have a method now that takes the string and matches it to the property by name but it requires I have a case for each property on the object, which on an object with 20+ properties is a lot of duplicate code.
I guess to specify I'm looking for javafx.bean.property as a return type.
You can always use Java Reflection.
Getting a list of properties
for (Method method : Node.class.getMethods()) {
String name = method.getName();
if (name.endsWith("Property")) {
Type returnType = method.getReturnType();
String propName = name.replace("Property", "");
System.out.println(propName + " : " + returnType);
}
}
Here is reflective method for binding and example:
public class ReflectiveBind extends Application {
/**
* Reflection call for code like
* slider1.valueProperty().bindBidirectional(slider2.valueProperty());
*
* #param bindee Node which you want to be changed by binding
* #param propertyName name of the property, e.g. width
* #param bindTarget Node which you want to be updated by binding
*/
private static void bind(Object bindee, String propertyName, Object bindTarget) throws Exception {
// here we get slider1.valueProperty()
Method methodForBindee = bindee.getClass().getMethod(propertyName + "Property", (Class[]) null);
Object bindableObj = methodForBindee.invoke(bindee);
// here we get slider2.valueProperty()
Method methodForBindTarget = bindTarget.getClass().getMethod(propertyName + "Property", (Class[]) null);
Object bindTargetObj = methodForBindTarget.invoke(bindTarget);
// here we call bindBidirectional: slider1.valueProperty().bindBidirectional(slider2.valueProperty())
Method bindMethod = bindableObj.getClass().getMethod("bindBidirectional", Property.class);
bindMethod.invoke(bindableObj, bindTargetObj);
}
#Override
public void start(Stage stage) {
Slider slider1 = new Slider();
Slider slider2 = new Slider();
VBox root = new VBox(20);
root.getChildren().addAll(slider1, slider2);
stage.setScene(new Scene(root, 200, 100));
stage.show();
try {
//same call as slider1.valueProperty().bindBidirectional(slider2.valueProperty());
bind(slider1, "value", slider2);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) { launch(); }
}
Check out apache commons bean utils
http://commons.apache.org/beanutils/
You say you want to...
Get the value of the property:
http://commons.apache.org/beanutils/api/org/apache/commons/beanutils/BeanUtils.html#getProperty%28java.lang.Object,%20java.lang.String%29
Get List of Properties:
http://commons.apache.org/beanutils/api/org/apache/commons/beanutils/BeanUtils.html#describe%28java.lang.Object%29
Lots of other useful methods there, and for UI work they are particularly convenient since many of them return the string form which is what you want to display.
If you want objects rather than strings use the PropertUtils class instead
Get the value of the property (not as a string)
http://commons.apache.org/beanutils/v1.8.3/apidocs/org/apache/commons/beanutils/PropertyUtils.html#getProperty%28java.lang.Object,%20java.lang.String%29
Get list of properties:
http://commons.apache.org/beanutils/v1.8.3/apidocs/org/apache/commons/beanutils/PropertyUtils.html#describe%28java.lang.Object%29

Elegant way to bind html radio buttons <=> Java enums <=> mysql enums in Play?

The Goal is to have a list of options (that a user can chose through radio buttons) in one place(for eg: a yaml config file). No other place should have this list hard-coded
I've done something similar to create select elements, and I think enums worked just fine. Doing radio buttons should be very similar. I've set it up so that the labels can be defined in the messages file. I'm going to try to excerpt the relevant portions from my larger auto-form-generation code (using FastTags) the best I can. It's a bit heavy for this one case but it makes sense in the larger system.
I use the tag like #{form.selector 'order.status' /}, which looks find the variable named order in the template, sees that status is declared as public Status status, and then goes to find all the values of the Status enum and generate options for them in the select element.
First, I use a FieldContext object which just contains a bunch of info that's used by the other code to determine what to generate along with some utility methods:
public class FieldContext {
public final Map<?,?> args;
public final ExecutableTemplate template;
public final int fromLine;
public Class clazz = null;
public Field field = null;
public Object object = null;
public Object value = null;
private Map<String,String> attrs = new HashMap<String,String>();
private Map<String,Boolean> printed = new HashMap<String,Boolean>();
private List<Option> options;
...
Then I have this in another helper class (its info gets added to the FieldContext):
public List<Option> determineOptions(FieldContext context) {
List<Option> options = new ArrayList<Option>();
if (context.field.getType().isEnum()) {
for (Object option : context.field.getType().getEnumConstants()) {
options.add(new Option(option.toString(), Message.get(option.toString())));
}
}
return options;
}
then the tag declaration is
public static void _selector(Map<?,?> args, Closure body, PrintWriter out, ExecutableTemplate template, int fromLine) {
String field_name = args.get("arg").toString();
TagContext.current().data.put("name", field_name);
SelectHelper helper = HelperFactory.getHelper(SelectHelper.class);
try {
FieldContext context = new FieldContext(field_name, args, template, fromLine);
helper.autoconfigure(context);
TagContext.current().data.put("selected", helper.determineValue(context));
out.print("<div class=\"formutil-field formutil-selector\">");
out.print("<label for=\"" + context.getAttr("id") + "\">");
out.print(helper.findOrCreateLabel(context));
out.print("</label>");
out.print("<select");
context.printAttribute(out, "id", "name");
out.print(">");
if (context.hasOptions()) {
for (Option option : context.getOptions()) {
out.print("<option value=\"" + option.value + "\">" + option.label + "</option>");
}
}
out.print("</select>");
context.printErrorIfPresent(out);
context.printValidationHints(out);
out.println("</div>");
}
...
}

Resources