Welcome to XMLPortletFactory Home Site

XMLPortletFactory is a software tool that creates database tables maintenance (CRUD) portlets from XML files.  Portlets generated only work on Liferay portals, and come out with source files (JSPs, .java, etc.) so programmers can extend and modify whatever is being generated to suit your software development needs.  In Help and Support section you will find Wikis, Tutorials and samples to get started.

With XMLPortletFactory you will be able to generate full CRUD working portlets with ease, accelerating your development process, allowing you to focus on higher level tasks.

XMLPortletFactory is licensed under the terms of GNU General Public License version 3.0 (GPLv3), and is OS Independent.

Note: XMLPortletFactory is still a young project, which ha not passed all possible tests and although is very solid and I use it in production environments, you should use it after appropriate tests.

Some of the most noticeable benefits

  • Frees you of 99% coding time in CRUD table maintenance portlets. You obtain full working portlet with all source code, programmers heaven!!!.
  • No more problems with versions. You make one XML file, generate portlet in all 6.0.x, 6.1.x and 6.2.x versions of Liferay.
  • Forget about creating tables. Because XMLPortletFactory uses Liferay's  service builder, tables are automatically created for you at portlet deployment.
  • Languages English, French, Italian, Finnish and Spanish allready implemented, easy to implement other languajes.
  • Is GPLv3 licensed. The GNU General Public License is a free, copyleft license for software and other kinds of works.
  • Your developed XMLs get the benefits of new XMLPortletFactory developments and improvements. 
  • Generated portlets use Liferay's search container, tags, etc. so they have very "Liferay" behavior, melting very well with themes.


Saludos,  Jack A. Rider

Latest Posts

RE: Search doesn't work in multi application

Philip Teagle:
Stoicho Gizdov:
I know this is quite a bit old thread, but if anyone is interested, iIn addition to what Juan mentioned, there are better ways to do this:
I did it as follows:
Made the search code part of the .vm template, generating the portlet java file.
    I updated the Portlet_XXXXXXPortlet_java.vm with the code, necessary to do the proper filtering. It was actually quite easy. If you are interested in the actual code modification, let me know.
Other ways include modifying the schema and/or using conditional schema elements to enable/disable <filter> processing only if a <mdfilter>true</mdilter> (as in master-detail filter new tag) is present...
Again, those are just ideas...

Hi Stoicho,

I would be interested in how you resolved the search issue with a vm template change.  Were you able to implement your app using XMLPF?


I was able to implement the change by using the diff patch below. I cannot guarantee it will work 100% for you, but you can take a look and make the necessary changes manually as well. This functionality may be included in a later release of XMLPF with option to select whether you want to enable this search functionality or not at the master/detail portlet level.
 3> #set ($fields = $application.getFileDef().getFields().getFieldArray())
 4> #set ($count=0)
 5> #foreach($field in $fields)
 6>     #set($tipoCampo = ${field.getType().getDomNode().getChildNodes().item(1).getLocalName()})
 7>     #if(${tipoCampo}=="varchar")
 8>         #if (${field.getType().getVarchar().getFilter()} == "true")
 9>             #set ($count=$count+1)
10>         #end
11>     #end
12> #end
15<             tempResults = ${classDef_name}LocalServiceUtil.findAllIn${detailfile.getConnectionFieldName()}Group(${detailfile.getConnectionFieldName()}, groupId,comparator);
18> #if ($count > 0)
20>             if (${fileDef_name}Filter.equalsIgnoreCase("")) {
21> #end
22>                 tempResults = ${classDef_name}LocalServiceUtil.findAllIn${detailfile.getConnectionFieldName()}Group(${detailfile.getConnectionFieldName()}, groupId,comparator);
23>                 total = tempResults.size();
25> #foreach($field in $fields)
26> #if(${field.isSetValidation()})
27>                 if (orderByCol.equalsIgnoreCase("${field.getName()}")) {
28>                     BeanComparator ${field.getName()}_bc = new BeanComparator("${field.getName()}", ${classDef_name}Comparator.get${classDef_name}OrderByComparator(orderByCol,orderByType));
29>                     List newList = new ArrayList(tempResults);
30>                     Collections.sort(newList, ${field.getName()}_bc);
31>                     if (!orderByType.trim().equalsIgnoreCase("asc")) {
32>                         Collections.reverse(newList);
33>                     }
34>                     tempResults = Collections.unmodifiableList(newList);
35>                 }
36> #end
37> #end
38> #if ($count > 0)
39>             } else {
41>                 Indexer indexer = IndexerRegistryUtil.getIndexer(${classDef_name}.class);
43>                 SearchContext searchContext = SearchContextFactory.getInstance(PortalUtil.getHttpServletRequest(renderRequest));
45>                 searchContext.setEnd(containerEnd);
46>                 searchContext.setKeywords(${fileDef_name}Filter);
47>                 searchContext.setStart(containerStart);
48>                 searchContext.setAttribute("${detailfile.getConnectionFieldName()}", ${detailfile.getConnectionFieldName()});
50>                 Hits results = indexer.search(searchContext);
52>                 total = results.getLength();
54>                 if (total > 0) {
55>                     tempResults = new ArrayList<${classDef_name}>(total);
56>                 }
57>                 for (int i = 0; i < results.getDocs().length; i++) {
58>                     Document doc = results.doc(i);
60>                     ${classDef_name} resReg = null;
62>                     // Entry
63>                     long entryId = GetterUtil.getLong(doc.get(Field.ENTRY_CLASS_PK));
65>                     try {
66>                         resReg = ${classDef_name}LocalServiceUtil.get${classDef_name}(entryId);
68>                         resReg = resReg.toEscapedModel();
70>                         tempResults.add(resReg);
71>                     }
72>                     catch (Exception e) {
73>                         if (_log.isWarnEnabled()) {
74>                             _log.warn("${classDef_name} search index is stale and contains entry " + entryId);
75>                         }
77>                         continue;
78>                     }
79>                 }
80>             }
81> #end
84< #set ($fields = $application.getFileDef().getFields().getFieldArray())
85< #set ($count=0)
86< #foreach($field in $fields)
87< #set($tipoCampo = ${field.getType().getDomNode().getChildNodes().item(1).getLocalName()})
88< #if(${tipoCampo}=="varchar")
89< #if (${field.getType().getVarchar().getFilter()} == "true")
90< #set ($count=$count+1)
91< #end
92< #end
93< #end

Web Friends and Collaborators

TigerCub Technology is focused on providing reliable, intuitive, and cost effective portal applications as a software service.   

TigerCub Technology


Blog Miguel Pau   

SEO for Liferay