openxava / documentation / How to ...

Table of contents

How to ...
How to prevent from modifying certain fields in a view?
How to use a different view for creating and for updating?
How to deactive a property for updating but not for creating?
How to access to a property of the model that isn't shown in the view?
How to modify the appearance of @ReadOnly fields
How to store user preferences (new in v3.0.2)?
Example of basic authentication security for OX application in Tomcat
How to add your own servlets, filters, listeners or resources to your OpenXava application?
How to create a new element directly from a @ManyToMany collection? (new in v4m4)
How to change schema, locale and user using url parameters (new in v4m4)
How to add a second collection in a report
How to define a JavaScript-based action?
How to remove PDF + Excel export actions in GUI ?
How to modify the parameters of the default reports?
How to generate HTML reports?
How to generate several reports from a single action?
How to merge multiple reports in one PDF?
How to add your own portlets to your OpenXava application (new in v4.6)?
How to define your own content for the Welcome page and the First Steps page (new in v5.0)?
How to access to the View object from a custom JSP?
How to generate real Excel instead of CSV in all my modules (new in v5.5)?
How to forward to a page in a new window without reloading the current page?
How to have OpenXava and Addons projects in a different folder than your own project (new in v6.1.1)?
How to run your application in the root context (new in v6.3)?

How to prevent from modifying certain fields in a view?

In Update view, by default, all the fields (except the key) are modifiables.
But you can declare any property of the view read only, in this way:
<view name="SomeMemberReadOnly">
    <property-view property="name" read-only="true"/>
</view>
 
Or, if you are using OX3:
@ReadOnly(forViews="SomeMembersReadOnly")
private String name;
 

How to use a different view for creating and for updating?

Obiously you must define a view for creating and another for updating, thus:
<component ... >
...
    <view name="Create">
    ...
    </view>
 
    <view name="Update">
    ...
    </view>
 
</component>
 
Or, if you are using OX3:
@Views({
    @View(name="Create", members="  .... "),
    @View(name="Update", members=" ... ")
})
public class MyEntity { ...
 
Now you have to refine the new action for chosing the Create view and the searching action for chosing the Update view. First, define your own controller, in your controllers.xml, thus:
<controller name="MyTypical">
    <action name="new"
        class="com.mycompany.myapplication.actions.MyNewAction"
        image="images/new.gif" on-init="true"
        keystroke="F2">
        <use-object name="xava_view"/>  <!-- Not needed since v4m2 -->
    </action>
    <action name="search"
        by-default="if-possible" hidden="true"
        class="com.mycompany.myapplication.actions.MySearchAction"
        keystroke="F8">
        <use-object name="xava_view"/>  <!-- Not needed since v4m2 -->
    </action>
 </controller>
And now assign this controller to your module, and define the searching action for the module. Write your module in the application.xml in this way:
<module name="MyModule">
    <env-var name="XAVA_SEARCH_ACTION" value="MyTypical.search"/>
    <model name="MyComponent"/>
    <controller name="MyTypical"/>
</module>
 
And now only remains to refine the logic of your actions. For MySearchAction you write (NOTE: selected entity index values have to be captured (1) so that it might be restored (3) after the reset performed by setViewName(...) method (2)):
public class MySearchAction extends SearchByViewKeyAction {
    public void execute() throws Exception {
        Map mapIndexValues = getView().getKeyValuesWithValue();   //1
        getView().setViewName("Update");                          //2
        getView().setValues(mapIndexValues);                      //3
        super.execute();
    }
}
And for MyNewAction:
public class MyNewAction extends NewAction {
    public void execute() throws Exception {
        getView().setViewName("Create");
        super.execute();
    }
}
 

How to deactivate a property for updating but not for creating?

Since v6.2 you can deactivate a property only for creating with @ReadOnly(onCreate=false) as explained in StackOverflow. so the below instructions are for versions previous to 6.2.
You have to refine the new action and the searching action. First, define your own controller, in your controllers.xml, thus:
<controller name="MyTypical">
    <action name="new"
        class="com.mycompany.myapplication.actions.MyNewAction"
        image="images/new.gif" on-init="true"
        keystroke="F2">
        <use-object name="xava_view"/>  <!-- Not needed since v4m2 -->
    </action>
    <action name="search"
        by-default="if-possible" hidden="true"
        class="com.mycompany.myapplication.actions.MySearchAction"
        keystroke="F8">
        <use-object name="xava_view"/>  <!-- Not needed since v4m2 -->
    </action>
 </controller>
And now assign this controller to your module, and define the searching action for the module, write your module in the application.xml in this way:
<module name="MyModule">
    <env-var name="XAVA_SEARCH_ACTION" value="MyTypical.search"/>
    <model name="MyComponent"/>
    <controller name="MyTypical"/>
</module>
And now only remains to refine the logic of your actions. For MySearchAction you write:
public class MySearchAction extends SearchByViewKeyAction {
    public void execute() throws Exception {
        super.execute();
        getView().setEditable("myproperty", false);
    }
}
And for MyNewAction:
public class MyNewAction extends NewAction {
    public void execute() throws Exception {
        super.execute();
        getView().setEditable("myproperty", true);
    }
}
 

How to access to a property of the model that isn't shown in the view?

From the view you can obtain only the displayed data. But it's possible, using MapFacade class to acess directly to the model.
You can write in your action a code like this one:
public class MyAction extends ViewBaseAction {
 
    public void execute() throws Exception {
        Invoice invoice = (Invoice) MapFacade.findEntity(getModelName(), getView().getKeyValues());
        // Special discount is not shown in the view
        BigDecimal specialDiscount = invoice.getSpecialDiscount();
        ...
    }
    ...
 
In this way you can access to specialDiscount property although it is not displayed in the current view.

How to modify the appearance of @ReadOnly fields

By default, OpenXava will lightly shade fields that are dropdowns and those annotated with @ReadOnly. Marking a field @ReadOnly also removes the icon associated with editing. However, in my application, a requirement was that read-only fields be highlighted differently. This can be done by adding an entry into your custom.css file in the web/xava/style directory in your project as documented in the Customizing Views section.
The relevant entry is:
input[disabled] {
  background:red;
}
Of course, you can put any valid css that matches your needs.

How to store user preferences (new in v3.0.2)?

Storing user preferences of your application is your business, but for your convenience you can use OpenXava to store user preferences.
OpenXava uses the Java Preferences API for storing and loading user preferences, but adapted for working in a multiuser server environment. You can access to the Preferences object using the Users class of OpenXava. Just in this way:
// Obtain preferences for the current user
// and node (an arbitrary category of your choice)
Preferences preferences = Users.getCurrentPreferences().node("mynode");
 
// Read a property value
boolean rowsHidden = preferences.getBoolean(ROWS_HIDDEN, false);
 
...
 
// Modify and save a property
preferences.putBoolean(ROWS_HIDDEN, rowsHidden);
preferences.flush();
You must call explicitly to flush() in order to store the changed preferences.

Example of basic authentication security for OX application in Tomcat

Look at this forum message.

How to add your own servlets, filters, listeners or resources to your OpenXava application?

Since OpenXava 7.0 the servlets.xml, filters.xml and listeners.xml files we talk below are no longer supported. You can add your servlets, filter, listeners, etc. in the web.xml, that since v7.0 is empty and ready for your own things, in src/main/webapp/WEB-INF. Also you can use the standard @WebServlet, @WebFilter and @WebListener annotations.
Since OpenXava 6.0 you can use the standard Servlet annotations @WebServlet, @WebFilter and @WebListener to define your own servlets, filters and listeners.
If you're using an OpenXava version older than 7.0, for adding your own resources to your OX application do not modify the web.xml file, instead you can create a resources.xml with resource-ref (since v5.4) in the WEB-INF folder.
If you use a version previous to v6.0 you should user servlets.xml, filters.xml and listeners.xml. In this case, for adding your own servlets to your OX application do not modify the web.xml file, instead you can create a servlets.xml (with servlet and servlet-mapping elements), a filters.xml (with filter and filter-mapping elements) and a listeners.xml (with listener elements, since v4.0.1). Though this method is deprecated still works with latest OpenXava versions.
For example, if you want to add a servlet called TestServlet, just create a servlets.xml file in WEB-INF with the next content:
<!-- With v6.0 or better use @WebServlet instead -->
<servlet>
<servlet-name>testServlet</servlet-name> <servlet-class>org.openxava.test.servlets.TestServlet</servlet-class> </servlet>   <servlet-mapping> <servlet-name>testServlet</servlet-name> <url-pattern>/test</url-pattern> </servlet-mapping>  
This fragment will be automatically inserted in web.xml when you call to deployWar or updateOX ant task.

How to create a new element directly from a @ManyToMany collection? (new in v4m4)

By default in a @ManyToMany collection the user can add existing elements to the collection, however he cannot create new ones. Fortunately, you can add this functionality using the ManyToMany.new action (included in OpenXava) as list action for your collection. As following:
@ManyToMany
@ListAction("ManyToMany.new")
private Collection<Human> members;

How to change schema, locale and user using url parameters (new in v4m4)

You can change default schema, current locale or current user through web parameters by including the controller UrlParameters(1). For example in application.xml you add the controller:
<application name="MyApplication">
    <module name="MyModule">
        <model name="MyModel"/>
        <controller name="Typical"/>
        <controller name="UrlParameters" />          // 1
    </module>
</application>
The url for invoking the module now can contain the schema parameter.
http://localhost:8080/MyApplication/xava/module?application=MyApplication&module=MyModule&schema=companyA
or the locale parameter:
http://localhost:8080/MyApplication/xava/module?application=MyApplication&module=MyModule&locale=es
or the user parameter (it will be stored in session's attribute xava.user):
http://localhost:8080/MyApplication/xava/module?application=MyApplication&module=MyModule&user=theUser
They are not exclusive, you can use any combination of them.

How to add a second collection in a report

Modify your .jrxml, to add a subreport in one of the available bands (not the details ones, obviously). You can do that easily from the XML perspective of iReport.

<summary>
    <band height="77" splitType="Stretch">
        <subreport>
            <reportElement stretchType="RelativeToBandHeight" x="0" y="0" width="555" height="68"/>
            <dataSourceExpression><![CDATA[$P{subreport_ds}]]></dataSourceExpression>
            <subreportExpression class="net.sf.jasperreports.engine.JasperReport"><![CDATA[$P{subreport_report}]]></subreportExpression>
        </subreport>
    </band>
</summary>
Also add matching parameters at the top of the file, below your parameters.

<parameter name="subreport_report" class="net.sf.jasperreports.engine.JasperReport"/>
<parameter name="subreport_ds" class="net.sf.jasperreports.engine.JRDataSource"/>
You will have to design a new report in iReport describing the fields of the collection you want to add. Generally a columnHeader and a detail band are enough

In your report action, fill in the new parameters:

public class MyReportAction extends JasperReportBaseAction {
    ...
    public Map<String, Object> getParameters() throws Exception  {
        Messages errors = MapFacade.validate("Project", getView().getValues());
        if (errors.contains()) throw new ValidationException(errors);
        Map<String, Object> parameters = new HashMap<String, Object>();
        // fill up the project subreport
        parameters.put("subreport_report", JasperCompileManager.compileReport(JRUtils.class.getResourceAsStream("/Project_products.jrxml"))); // 1
        parameters.put("subreport_ds", new JRBeanCollectionDataSource(getProject().getProducts()));           // 2
        return parameters;
    }
    ...
1- Replace by the path to your subreport.
2- Any Collection is valid. The fields of the subreport refer to the properties of the collection members.

How to define a JavaScript-based action?

One use case could be, for example, to be able to click on a button (in a 'detail' page) to execute some custom JavaScript code.

To do so, you need OpenXava version N>=4, and you have to write a IForwardAction whose uri stars with "javascript:"
public class GoToGoogleAction implements IForwardAction {
 
  public String getForwardURI() {
    return "javascript:top.location=\"http://www.google.fr\"";
  }
 
  public boolean inNewWindow() {
    return false;
  }
  ...
}
 
Other IForwardAction methods could remain empty, or auto-generated if you like.

Since v5.9 you can implements IPostJavaScriptAction, that after the regular action execution executes your JavaScript code:
public class MyJavaScriptAction extends BaseAction implements IJavaScriptPostAction {
 
    public void execute() throws Exception {
        addMessage("Hello, I'm Java");
    }
 
    public String getPostJavaScript() {
        return "alert('Hello, I am JavaScript')";
    }
 
}
Unlike IForwardAction to javascript: in IPostJavaScriptAction the JavaScript is executed when the view is completely updated after regular Java execution.

How to remove PDF + Excel export actions in GUI ?

These actions are defined by the 'Print' controller. All controllers inherits these actions from the default controller, named 'Typical', that extends the 'Print' controller:
<controller name="Typical">
  <extends controller="Navigation"/>
  <extends controller="CRUD"/>
  <extends controller="Print"/>
</controller>
 
 
So, these actions are available by default to all controllers.

One way to remove them for all GUI is to redefine the 'Typical' controller in controllers.xml:
<controller name="Typical">
  <extends controller="Navigation"/>
  <extends controller="CRUD"/>
</controller>
 
 
But, still, these PDF + Excel export actions remain for collections within a business class. It's due to the 'DefaultListActionsForCollections' controller that extends the 'Print' controller too:
<controller name="DefaultListActionsForCollections">
  <extends controller="Print"/>
</controller>
 
So, in order to remove these PDF + Excel export actions always for embedded collections is to redefine the 'DefaultListActionsForCollections' controller:
<controller name="DefaultListActionsForCollections">
</controller>
 
And then, no PDF + Excel export action appear.

How to modify the parameters of the default reports?

We can change the parameters of the default report by code. In this case we change the organization name:
default_report.GIF
By default this organization name is collected from 'xava.organization' value in the i18n files, but we modify it to that this organization name is collected from a variable value.
Just create a new class that implements to IReportParametersProvider and add the code that you need to the 'getOrganization()' method:
package org.openxava.test.util
 
import org.openxava.util.*;
 
/**
 */
class MyReportParametersProvider implements IReportParametersProvider {
 
    String getOrganization() {
        return "report to " + Users.getCurrent()
    }
 
}
To finish add in your 'xava.properties' file a new line with the class to use:
reportParametersProviderClass=org.openxava.test.util.MyReportParametersProvider
 

How to generate HTML reports?

One option is to forward to a JSP that generates the HTML report, you can do it by means of IForwardAction. Another option is using the SimpleHTMLReportAction action (since v4.3) that allows you to work with simple HTML templates.

How to generate several reports from a single action?

Just extend your action from JasperMultipleReportBaseAction (new in v4.3). For an example look at InvoiceTwoReportsAction of OpenXavaTest.

How to merge multiple reports in one PDF?

Just extend your action from JasperConcatReportBaseAction (new in v5.0). Useful when you need to concatenate several reports with different page formats (landscape, portrait). There is an example at MovieReportAction of OpenXavaTest.

How to add your own portlets to your OpenXava application (new in v4.6, until v6.6.3)?

For adding your own portlets to your OX application do not modify the portlet.xml file, instead you can create a portlet-ext.xml (with portlet elements) and a liferay-display-ext.xml (with portlet elements) in the WEB-INF folder.
For example, if you want to add a portlet called VersionPortlet, just create a portlet-ext.xml file in WEB-INF with the next content:
<portlet id="Version">
    <description>OpenXavaTest - Version</description>
    <description xml:lang="ca">OpenXavaTest - Versió</description>
    <description xml:lang="es">OpenXavaTest - Versión</description>
    <description xml:lang="fr">OpenXavaTest - Version</description>
    <portlet-name>Version</portlet-name>
    <display-name>OpenXava - Version</display-name>
    <display-name xml:lang="ca">OpenXavaTest - Versió</display-name>
    <display-name xml:lang="es">OpenXavaTest - Versión</display-name>
    <display-name xml:lang="fr">OpenXavaTest - Version</display-name>
    <portlet-class>org.openxava.test.portlets.VersionPortlet</portlet-class>
    <expiration-cache>0</expiration-cache>
    <supports>
        <mime-type>text/html</mime-type>
        <portlet-mode>VIEW</portlet-mode>
    </supports>
    <supported-locale>ca</supported-locale>
    <supported-locale>es</supported-locale>
    <supported-locale>en</supported-locale>
    <supported-locale>fr</supported-locale>
    <resource-bundle>portlets/Version</resource-bundle>
</portlet>
If you are using Liferay you can optionally create the liferay-display-ext.xml file to add entries to liferay-display.xml file. So, for the above portlet you can write a liferay-display-ext.xml with the next content:
<portlet id="Version" />
This fragment will be automatically inserted in liferay-display.xml when you call to generatePortlets ant task.

Moreover, you have to write the resorce files, in this case you have to write Version_ca.properties, Version_es.properties, Version_en.properties and Version_fr.properties. Here there is a example for Version_en.properties:
javax.portlet.short-title=Version
javax.portlet.title=OpenXavaTest - Version
category.OpenXavaTest=OpenXavaTest

And, of course, you need to write the code for your portlet, in this case:
package org.openxava.test.portlets;
 
import java.io.*;
import javax.portlet.*;
import org.openxava.controller.*;
 
public class VersionPortlet extends GenericPortlet {
 
    public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
        response.setContentType("text/html");
        response.getWriter().write("<table border=\"0\">");
        writeVersion(response.getWriter(), "The version of OpenXava is", ModuleManager.getVersion());
        response.getWriter().write("</table>");
    }
 
    private void writeVersion(PrintWriter out, String unit, String version) {
        out.write("<tr>");
        out.write("<td style=\"padding: 2px 5px 2px 5px;\"><b>" + unit + "</b></td>");
        out.write("<td style=\"padding: 2px 5px 2px 5px;\">v" + version + "</td>");
        out.write("</tr>");
    }
 
}

How to define your own content for the Welcome page and the First Steps page (new in v5.0)?

To modify the Welcome page edit the file src/main/webapp/naviox/welcome.jsp of your project. To modify the First Steps page use the property initialModule in naviox.properties, as explained in Module navigation documentation. For v6 edit web/naviox/welcome.jsp and web/naviox/firstSteps.jsp in your project. If your project was created with v7.1 or v7.2 you have to copy welcome.jsp from GitHub repository to your project first, follow the instructions in customizing documentation to do so.

How to access to the View object from a custom JSP?

In our JSP we have to add the next lines:
<jsp:useBean id="context" class="org.openxava.controller.ModuleContext" scope="session"/>
<%
 
    String viewObject = request.getParameter("viewObject");
    viewObject = (viewObject == null || viewObject.equals(""))?"xava_view":viewObject;
    org.openxava.view.View view = (org.openxava.view.View) context.get(request, viewObject);
 
    System.out.println("modelo: " + view.getModelName()); // Here we use view

How to generate real Excel instead of CSV in all my modules (new in v5.5)?

Add this to your application.xml:
<default-module>
    <controller name="TypicalRealExcel"/>
</default-module>
Moreover, in your own controllers you have to extend from TypicalRealExcel instead from Typical.

How to forward to a page in a new window without reloading the current page?

Reloading the current page is the correct behavior because in your action you could modify the view, add messages, etc. Anyways, if you want forwaring without reloading it's possible using JavaScript, in this way:
package org.openxava.provaox.actions;
 
import org.openxava.actions.*;
 
public class ForwardWithoutReloadingAction extends BaseAction implements IForwardAction {
 
    public void execute() throws Exception {
        // Do something, if you want
    }
 
    public boolean inNewWindow() {
        return false; // Because we'll open the window ourselves using JavaScript
    }
 
    public String getForwardURI() {
        return "javascript:void(window.open('/MyApplication/myurl'))";
    }
 
}

How to have OpenXava and Addons projects in a different folder than your own project (new in v6.1.1)?

By default Addons and OpenXava projects have to be in the same directory (the workspace base directory) than your own project. However, since v6.1.1 you can specify a different directory for the OpenXava and Addons projects. Just add (or modify) the property openxava.base.dir in the build.xml of your project:
<property name="openxava.base.dir" value="/home/john/my-openxava"/>
In this way your project will use the OpenXava and Addons projects from /home/john/my-openxava directory.

How to run your application in the root context (new in v6.3)?

That is using it from browser without application name in the URL, like this: https://localhost:8080/
For production calling the war ROOT.war to deploy on Tomcat is enough, you don't need any change in your code.
For development you can modify the launcher class (com.yourcompany.yourapp.run.yourapp since v7.0 or _Run_YourApplication in v6.x) changing:
AppServer.run("YourApplication");
By:
AppServer.run("");
And if you want to test your application in the root context using JUnit, add the next entry in xava-junit.properties:
contextPath=/
Of course, you can use root context only for production and not for development, or vice versa.