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.
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:
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'))";
}
}
And if you want to test your
application in the root context using JUnit, add the next entry in xava-junit.properties:
Of course, you can use root
context only for production and not for development, or vice versa.