/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.katari.report.domain;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.base.JRBaseParameter;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.Validate;
import com.globant.katari.hibernate.coreuser.domain.Role;
/**
* The <code>ReportDefinition</code> class represents a Report XML Template.
*
* @author sergio.sobek
*/
@Entity
@Table(name = "report_definitions")
public class ReportDefinition {
/**
* Maximum file size.
*/
private static final int MAX_TEMPLATE_SIZE = 1024000;
/**
* The report definition id.
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false)
private long id;
/**
* The report definition name.
*
* It is never null.
*/
@Column(name = "name", unique = true, nullable = false)
private String name;
/**
* The report definition description.
* It is never null.
*/
@Column(name = "description", nullable = false)
private String description;
/** The report XML template byte array.
*
* TODO Rename this to something more reasonable, like 'report template'.
*/
@Lob
// lazy by definition.
@Column(length = MAX_TEMPLATE_SIZE, name = "report_content")
private byte[] reportContent;
/** The projects associated with this client. */
@Transient
private List<ParameterDefinition> parameterDefinitions = null;
/** The roles that users must have to view the report.
*/
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "report_required_roles")
private Set<Role> roles = new HashSet<Role>();
/**
* Default Constructor.
*/
protected ReportDefinition() {
}
/**
* Constructor.
*
* This operation does not validate that the report template is a jrxml valid
* file. We leave this responsibility to the caller.
*
* @param aName the name of the report. It cannot be null.
* @param aDescription the description of the report. It cannot be null.
* @param aReportTemplate the report template as a byte array. It cannot be
* null.
*/
public ReportDefinition(final String aName, final String aDescription,
final byte[] aReportTemplate) {
Validate.notNull(aName, "The name cannot be null.");
Validate.notNull(aDescription, "The description cannot be null.");
Validate.notNull(aReportTemplate,
"The report template content cannot be null.");
name = aName;
description = aDescription;
reportContent = aReportTemplate.clone();
}
/**
* Modifies the report definition name.
*
* @param aName The name for the report definition. It cannot be null.
* @param aDescription The description for the report definition. It cannot be
* null.
*/
public void modify(final String aName, final String aDescription) {
Validate.notNull(aName,
"the new name of the report definition cannot be null.");
Validate.notNull(aDescription,
"the new description of the report definition cannot be null.");
name = aName;
description = aDescription;
}
/**
* Gets the id of the report definition.
*
* @return the id
*/
public long getId() {
return id;
}
/**
* Gets the parameters.
* @return the parameters. It never returns null.
*/
public List<ParameterDefinition> getParameterDefinitions() {
if (parameterDefinitions == null) {
parameterDefinitions = buildParameters();
}
return parameterDefinitions;
}
/**
* Gets for the report definition name.
*
* @return the report definition name.
*/
public String getName() {
return name;
}
/**
* Gets for the report definition description.
*
* @return the report definition description.
*/
public String getDescription() {
return description;
}
/**
* Gets of the report template XML byte array.
*
* @return the report template as a byte array. Never returns null.
*/
public byte[] getReportContent() {
return reportContent;
}
/**
* Modifies the report definition.
*
* This operation does not validate that the content is a jrxml valid file.
* We leave this responsibility to the caller.
*
* @param aContent The content to be associated with the report definition.
* It cannot be null.
*/
public void setReportContent(final byte[] aContent) {
Validate.notNull(aContent,
"the new conntent of the report definition cannot be null.");
reportContent = aContent.clone();
parameterDefinitions = null;
}
/**
* Parses the Jasper XML Template file retrieving a list of defined
* parameters.
*
* @return a list of parameters descriptors. If the report does not define
* any parameter, it returns an empty list.
*
* TODO Get rid of the sax parser and use JasperDesign instead.
*/
@SuppressWarnings("unchecked")
private List<ParameterDefinition> buildParameters() {
List<ParameterDefinition> result = new ArrayList<ParameterDefinition>();
String dropdownQuery;
boolean optional = false;
try {
JasperDesign design;
design = JRXmlLoader.load(new ByteArrayInputStream(reportContent));
List<JRBaseParameter> parameters = design.getParametersList();
// parses all the parameters
for (JRBaseParameter parameter : parameters) {
// the parameter must not be system defined and must be for prompting
if (!parameter.isSystemDefined() && parameter.isForPrompting()) {
// get the property dropdown: if it doesn't exists it is null
dropdownQuery = parameter.getPropertiesMap().getProperty("dropdown");
String optionalValue = parameter.getPropertiesMap().getProperty(
"optional");
// 'true','yes' or 'on' values makes the parameter optional. Every
// other thing, including null, is false.
optional = BooleanUtils.toBoolean(optionalValue);
result.add(new ParameterDefinition(parameter.getName(),
parameter.getValueClassName(), optional, dropdownQuery));
}
}
} catch (JRException ex) {
throw new RuntimeException("Error loading report definition", ex);
}
return result;
}
/**
* Adds the specified role.
*
* Ignores duplicates.
*
* @param theRole The role to add. It cannot be null.
*
* @return true if the role was added
*/
public boolean addRole(final Role theRole) {
Validate.notNull(theRole, "The role cannot be null");
return roles.add(theRole);
}
/**
* Removes the specified role.
*
* @param theRole The role to be deleted, it cannot be null.
*
* @return true if the list contained the specified role
*/
public boolean removeRole(final Role theRole) {
Validate.notNull(theRole, "The role cannot be null");
return roles.remove(theRole);
}
/**
* Returns the roles of the report.
*
* @return the role set, it is never null.
*/
public Set<Role> getRoles() {
return roles;
}
}