/** @author Javier Paniza */ public abstract class ModelMapping implements java.io.Serializable { private static Log log = LogFactory.getLog(ModelMapping.class); private static boolean codeGenerationTime; private static boolean codeGenerationTimeObtained = false; private MetaComponent metaComponent; private String table; private Map propertyMappings = new HashMap(); private Map referenceMappings; private Collection modelProperties = new ArrayList(); // of String private Collection tableColumns = new ArrayList(); // of String private Collection referenceMappingsWithConverter; // of ReferenceMapping private boolean databaseMetadataLoaded = false; private boolean supportsSchemasInDataManipulation = true; private boolean supportsYearFunction = false; private boolean supportsMonthFunction = false; private boolean supportsTranslateFunction = false; private boolean referencePropertyWithFormula = false; public abstract String getModelName() throws XavaException; public abstract MetaModel getMetaModel() throws XavaException; /** Util specially to find out the type of properties that are not in model, only in mapping. */ public Class getType(String propertyName) throws XavaException { try { return getMetaModel().getMetaProperty(propertyName).getType(); } catch (ElementNotFoundException ex) { // Try to obtain it from primary key if (!(getMetaModel() instanceof MetaEntity)) return java.lang.Object.class; throw ex; } } public String getTable() { // Change this if by polymorphism ? if (isCodeGenerationTime()) return table; if (XavaPreferences.getInstance().isJPAPersistence() && getSchema() == null && !Is.emptyString(XPersistence.getDefaultSchema())) { return XPersistence.getDefaultSchema() + "." + table; } else if (XavaPreferences.getInstance().isHibernatePersistence() && getSchema() == null && !Is.emptyString(XHibernate.getDefaultSchema())) { return XHibernate.getDefaultSchema() + "." + table; } return table; } private static boolean isCodeGenerationTime() { if (!codeGenerationTimeObtained) { codeGenerationTimeObtained = true; try { // Class.forName("CodeGenerator"); ClassLoaderUtil.forName(ModelMapping.class, "CodeGenerator"); codeGenerationTime = true; } catch (Exception ex) { codeGenerationTime = false; } } return codeGenerationTime; } public void setTable(String tabla) { this.table = tabla; } public String getSchema() { int idx = table.indexOf('.'); if (idx < 0) return null; return table.substring(0, idx); } public String getUnqualifiedTable() { int idx = table.indexOf('.'); if (idx < 0) return table; return table.substring(idx + 1); } public String getTableToQualifyColumn() { return supportsSchemasInDataManipulation() ? getTable() : getUnqualifiedTable(); } public void addPropertyMapping(PropertyMapping propertyMapping) throws XavaException { propertyMappings.put(propertyMapping.getProperty(), propertyMapping); modelProperties.add(propertyMapping.getProperty()); // To keep order tableColumns.add(propertyMapping.getColumn()); if (propertyMapping.hasFormula() && !getMetaModel().isAnnotatedEJB3()) { propertyMapping.getMetaProperty().setReadOnly(true); } } public void addReferenceMapping(ReferenceMapping referenceMapping) throws XavaException { if (referenceMappings == null) referenceMappings = new HashMap(); referenceMappings.put(referenceMapping.getReference(), referenceMapping); referenceMapping.setContainer(this); } /** @return Not null */ public ReferenceMapping getReferenceMapping(String name) throws XavaException, ElementNotFoundException { ReferenceMapping r = referenceMappings == null ? null : (ReferenceMapping) referenceMappings.get(name); if (r == null) { throw new ElementNotFoundException("reference_mapping_not_found", name, getModelName()); } return r; } /** @return Not null */ public PropertyMapping getPropertyMapping(String name) throws XavaException, ElementNotFoundException { int i = name.indexOf('.'); if (i >= 0) { String rName = name.substring(0, i); String pName = name.substring(i + 1); if (isReferenceNameInReferenceMappings(rName)) { return getReferenceMapping(rName).getReferencedMapping().getPropertyMapping(pName); } else { // by embedded references: address.city -> address_city return getPropertyMapping(name.replace(".", "_")); } } PropertyMapping p = propertyMappings == null ? null : (PropertyMapping) propertyMappings.get(name); if (p == null) { throw new ElementNotFoundException("property_mapping_not_found", name, getModelName()); } return p; } private boolean isReferenceNameInReferenceMappings(String referenceName) { Collection<ReferenceMapping> col = getReferenceMappings(); for (ReferenceMapping rm : col) if (rm.getReference().equals(referenceName)) return true; return false; } /** * In the order that they was added. * * @return Collection of <tt>String</tt>. */ public Collection getModelProperties() { return modelProperties; } /** * In the order that they was added. * * @return Collection of <tt>String</tt>. */ public Collection getColumns() { return tableColumns; } public String getKeyColumnsAsString() throws XavaException { StringBuffer r = new StringBuffer(); Collection columns = new HashSet(); for (Iterator it = getMetaModel().getAllKeyPropertiesNames().iterator(); it.hasNext(); ) { String pr = (String) it.next(); String column = getColumn(pr); if (columns.contains(column)) continue; columns.add(column); r.append(column); r.append(' '); } return r.toString().trim(); } private boolean supportsSchemasInDataManipulation() { loadDatabaseMetadata(); return supportsSchemasInDataManipulation; } /** Wraps the column name with the SQL function for extracting the year from a date. */ public String yearSQLFunction(String column) { if (supportsYearFunction()) return "year(" + column + ")"; return "extract (year from " + column + ")"; } /** Wraps the column name with the SQL function for extracting the month from a date. */ public String monthSQLFunction(String column) { if (supportsMonthFunction()) return "month(" + column + ")"; return "extract (month from " + column + ")"; } /** * To ignore accents: just to search 'cami�n' or 'camion' * * <p>Good performance using 'translate' but is very slow when it use 'replace...' * * @since v4m6 */ public String translateSQLFunction(String column) { if (supportsTranslateFunction()) return "translate(" + column + ",'aeiouAEIOU','áéíóúÁÉÍÓÚ')"; return "replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(" + column + ", 'Ú', 'U'), 'ú', 'u'), 'Ó', 'O'), 'ó', 'o'), 'Í', 'I'), " + "'í', 'i'), 'É', 'E'), 'é', 'e'), 'Á', 'A'), 'á', 'a')"; } private boolean supportsYearFunction() { loadDatabaseMetadata(); return supportsYearFunction; } private boolean supportsMonthFunction() { loadDatabaseMetadata(); return supportsMonthFunction; } /** @since v4m6 */ private boolean supportsTranslateFunction() { loadDatabaseMetadata(); return supportsTranslateFunction; } private void loadDatabaseMetadata() { if (!databaseMetadataLoaded) { String componentName = "UNKNOWN"; Connection con = null; try { componentName = getMetaComponent().getName(); con = DataSourceConnectionProvider.getByComponent(componentName).getConnection(); DatabaseMetaData metaData = con.getMetaData(); supportsSchemasInDataManipulation = metaData.supportsSchemasInDataManipulation(); Collection timeDateFunctions = Strings.toCollection(metaData.getTimeDateFunctions().toUpperCase()); // // another solution instead of the use of 'if' would be to use a xml with // the information of the functions from each BBDD if ("DB2 UDB for AS/400".equals(metaData.getDatabaseProductName()) || "Oracle".equals(metaData.getDatabaseProductName()) || "PostgresSQL".equals(metaData.getDatabaseProductName())) { supportsTranslateFunction = true; } if ("Oracle".equals(metaData.getDatabaseProductName()) || "PostgreSQL".equals(metaData.getDatabaseProductName())) { supportsYearFunction = supportsMonthFunction = false; } else { supportsYearFunction = timeDateFunctions.contains("YEAR"); supportsMonthFunction = timeDateFunctions.contains("MONTH"); } databaseMetadataLoaded = true; } catch (Exception ex) { log.warn(XavaResources.getString("load_database_metadata_warning")); } finally { try { if (con != null) { con.close(); } } catch (SQLException e) { log.warn(XavaResources.getString("close_connection_warning")); } } } } public String getQualifiedColumn(String modelProperty) throws XavaException { PropertyMapping propertyMapping = (PropertyMapping) propertyMappings.get(modelProperty); if (propertyMapping != null && propertyMapping.hasFormula()) return getColumn(modelProperty); String tableColumn = getTableColumn(modelProperty, true); if (Is.emptyString(tableColumn)) return "'" + modelProperty + "'"; if (referencePropertyWithFormula) { referencePropertyWithFormula = false; return tableColumn; } // for calculated fields or created by multiple converter if (modelProperty.indexOf('.') >= 0) { if (tableColumn.indexOf('.') < 0) return tableColumn; String reference = modelProperty.substring(0, modelProperty.lastIndexOf('.')); if (tableColumn.startsWith(getTableToQualifyColumn() + ".")) { String member = modelProperty.substring(modelProperty.lastIndexOf('.') + 1); if (getMetaModel().getMetaReference(reference).getMetaModelReferenced().isKey(member)) return tableColumn; } // The next code uses the alias of the table instead of its name. In order to // support multiple references to the same model if (reference.indexOf('.') >= 0) { if (getMetaModel().getMetaProperty(modelProperty).isKey()) { reference = reference.substring(0, reference.lastIndexOf('.')); } reference = reference.replaceAll("\\.", "_"); } return "T_" + reference + tableColumn.substring(tableColumn.lastIndexOf('.')); } else { return getTableToQualifyColumn() + "." + tableColumn; } } /** Support the use of references with dots, this is: myreference.myproperty. */ public String getColumn(String modelProperty) throws ElementNotFoundException, XavaException { return getTableColumn(modelProperty, false); } private String getTableColumn(String modelProperty, boolean qualifyReferenceMappingColumn) throws XavaException { PropertyMapping propertyMapping = (PropertyMapping) propertyMappings.get(modelProperty); if (propertyMapping == null) { int idx = modelProperty.indexOf('.'); if (idx >= 0) { String referenceName = modelProperty.substring(0, idx); String propertyName = modelProperty.substring(idx + 1); if (getMetaModel().getMetaReference(referenceName).isAggregate() && !Strings.firstUpper(referenceName).equals(getMetaModel().getContainerModelName())) { propertyMapping = (PropertyMapping) propertyMappings.get(referenceName + "_" + propertyName); if (propertyMapping == null) { int idx2 = propertyName.indexOf('.'); if (idx2 >= 0) { String referenceName2 = propertyName.substring(0, idx2); String propertyName2 = propertyName.substring(idx2 + 1); return getTableColumn( referenceName + "_" + referenceName2 + "." + propertyName2, qualifyReferenceMappingColumn); } else { throw new ElementNotFoundException( "property_mapping_not_found", referenceName + "_" + propertyName, getModelName()); } } return propertyMapping.getColumn(); } ReferenceMapping referenceMapping = getReferenceMapping(referenceName); if (referenceMapping.hasColumnForReferencedModelProperty(propertyName)) { if (qualifyReferenceMappingColumn) { return getTableToQualifyColumn() + "." + referenceMapping.getColumnForReferencedModelProperty(propertyName); } else { return referenceMapping.getColumnForReferencedModelProperty(propertyName); } } else { ModelMapping referencedMapping = referenceMapping.getReferencedMapping(); String tableName = referencedMapping.getTableToQualifyColumn(); boolean secondLevel = propertyName.indexOf('.') >= 0; String columnName = referencedMapping.getTableColumn(propertyName, secondLevel); boolean hasFormula = referencedMapping.getPropertyMapping(propertyName).hasFormula(); if (qualifyReferenceMappingColumn && !secondLevel && !hasFormula) { return tableName + "." + columnName; } else if (hasFormula) { String formula = referencedMapping.getPropertyMapping(propertyName).getFormula(); referencePropertyWithFormula = true; return qualifyFormulaWithReferenceName( formula, referencedMapping.getModelName(), modelProperty); } else { return columnName; } } } throw new ElementNotFoundException( "property_mapping_not_found", modelProperty, getModelName()); } if (propertyMapping.hasFormula()) return propertyMapping.getFormula(); return propertyMapping.getColumn(); } /** * @exception ElementNotFoundException If property does not exist. * @exception XavaException Any problem * @return nulo If property exists but it does not have converter. */ public IConverter getConverter(String modelProperty) throws ElementNotFoundException, XavaException { return getPropertyMapping(modelProperty).getConverter(); } /** * @exception ElementNotFoundException If property does not exist. * @exception XavaException Any problem * @return nulo If property exists but it does not have converter. */ public IMultipleConverter getMultipleConverter(String modelProperty) throws ElementNotFoundException, XavaException { return getPropertyMapping(modelProperty).getMultipleConverter(); } /** If the property exists and has converter. */ public boolean hasConverter(String propertyName) { try { return getPropertyMapping(propertyName).hasConverter(); } catch (XavaException ex) { return false; } } public MetaComponent getMetaComponent() { return metaComponent; } public void setMetaComponent(MetaComponent componente) throws XavaException { this.metaComponent = componente; setupDefaultConverters(); } /** * Change the properties inside ${ } by the database qualified(schema + table) columns. Also if * the property inside ${ } is a model name it changes by the table name * * <p>For example, it would change: * * <pre> * select ${number}, ${name} from ${Tercero} * </pre> * * by * * <pre> * select G4GENBD.GENTGER.TGRCOD, G4GENBD.GENTGER.TGRDEN from G4GENBD.GENTGER * </pre> */ public String changePropertiesByColumns(String source) throws XavaException { return changePropertiesByColumns(source, true); } /** * Change the properties inside ${ } by the database columns without table and schema as prefix. * Also if the property inside ${ } is a model name it changes by the table name. * * <p>For example, it would change: * * <pre> * select ${number}, ${name} from ${Tercero} * </pre> * * by * * <pre> * select TGRCOD, TGRDEN * from G4GENBD.GENTGER * </pre> */ public String changePropertiesByNotQualifiedColumns(String source) throws XavaException { return changePropertiesByColumns(source, false); } private String changePropertiesByColumns(String source, boolean qualified) throws XavaException { StringBuffer r = new StringBuffer(source); int i = r.toString().indexOf("${"); int f = 0; while (i >= 0) { f = r.toString().indexOf("}", i + 2); if (f < 0) break; String property = r.substring(i + 2, f); String column = "0"; // thus it remained if it is calculated if (!getMetaModel().isCalculated(property)) { column = Strings.isModelName(property) ? getTable(property) : qualified ? getQualifiedColumn(property) : getColumn(property); } r.replace(i, f + 1, column); i = r.toString().indexOf("${"); } return r.toString(); } /** @since 4.1 */ private String getTable(String name) { return MetaComponent.get(name).getEntityMapping().getTable(); } public String changePropertiesByCMPAttributes(String source) throws XavaException { StringBuffer r = new StringBuffer(source); int i = r.toString().indexOf("${"); int f = 0; while (i >= 0) { f = r.toString().indexOf("}", i + 2); if (f < 0) break; String property = r.substring(i + 2, f); String cmpAttribute = null; if (property.indexOf('.') >= 0) { cmpAttribute = "o._" + Strings.firstUpper(Strings.change(property, ".", "_")); } else { MetaProperty metaProperty = getMetaModel().getMetaProperty(property); if (metaProperty.getMapping().hasConverter()) { cmpAttribute = "o._" + Strings.firstUpper(property); } else { cmpAttribute = "o." + property; } } r.replace(i, f + 1, cmpAttribute); i = r.toString().indexOf("${"); } return r.toString(); } public boolean hasPropertyMapping(String memberName) { return propertyMappings.containsKey(memberName); } private void setupDefaultConverters() throws XavaException { Iterator it = propertyMappings.values().iterator(); while (it.hasNext()) { PropertyMapping propertyMapping = (PropertyMapping) it.next(); propertyMapping.setDefaultConverter(); } } public boolean hasReferenceMapping(MetaReference metaReference) { if (referenceMappings == null) return false; return referenceMappings.containsKey(metaReference.getName()); } public boolean isReferenceOverlappingWithSomeProperty( String reference, String propertiesOfReference) throws XavaException { String column = getReferenceMapping(reference).getColumnForReferencedModelProperty(propertiesOfReference); return containsColumn(getColumns(), column); } public boolean isReferenceOverlappingWithSomeProperty(String reference) throws XavaException { Iterator it = getReferenceMapping(reference).getDetails().iterator(); while (it.hasNext()) { ReferenceMappingDetail d = (ReferenceMappingDetail) it.next(); if (containsColumn(getColumns(), d.getColumn())) { String property = getMappingForColumn(d.getColumn()).getProperty(); if (!property.startsWith(reference + "_")) { return true; } } } return false; } public boolean isReferencePropertyOverlappingWithSomeProperty(String qualifiedProperty) throws XavaException { int idx = qualifiedProperty.indexOf('.'); if (idx < 0) return false; String ref = qualifiedProperty.substring(0, idx); String pr = qualifiedProperty.substring(idx + 1); return isReferenceOverlappingWithSomeProperty(ref, pr); } /** @throws XavaException If it does not have a overlapped property, or any other problem. */ public String getOverlappingPropertyForReference(String reference, String propertyOfReference) throws XavaException { String column = getReferenceMapping(reference).getColumnForReferencedModelProperty(propertyOfReference); if (propertyMappings == null) { throw new XavaException("reference_property_not_overlapped", propertyOfReference, reference); } Iterator it = propertyMappings.values().iterator(); while (it.hasNext()) { PropertyMapping mapping = (PropertyMapping) it.next(); if (column.equalsIgnoreCase(mapping.getColumn())) return mapping.getProperty(); } throw new XavaException("reference_property_not_overlapped", propertyOfReference, reference); } /** @return Of <tt>String</tt> and not null. */ public Collection getOverlappingPropertiesOfReference(String reference) throws XavaException { Collection overlappingPropertiesOfReference = new ArrayList(); Iterator it = getReferenceMapping(reference).getDetails().iterator(); while (it.hasNext()) { ReferenceMappingDetail d = (ReferenceMappingDetail) it.next(); if (containsColumn(getColumns(), d.getColumn())) { String property = getMappingForColumn(d.getColumn()).getProperty(); if (!property.startsWith(reference + "_")) { overlappingPropertiesOfReference.add(d.getReferencedModelProperty()); } } } return overlappingPropertiesOfReference; } private boolean containsColumn(Collection columns, String column) { if (columns.contains(column)) return true; for (Iterator it = columns.iterator(); it.hasNext(); ) { if (((String) it.next()).equalsIgnoreCase(column)) return true; } return false; } private PropertyMapping getMappingForColumn(String column) throws XavaException { if (propertyMappings == null) { throw new ElementNotFoundException("mapping_not_found_no_property_mappings", column); } Iterator it = propertyMappings.values().iterator(); while (it.hasNext()) { PropertyMapping propertyMapping = (PropertyMapping) it.next(); if (propertyMapping.getColumn().equalsIgnoreCase(column)) { return propertyMapping; } } throw new ElementNotFoundException("mapping_for_column_not_found", column); } String getCMPAttributeForColumn(String column) throws XavaException { PropertyMapping mapping = getMappingForColumn(column); if (!mapping.hasConverter()) return Strings.change(mapping.getProperty(), ".", "_"); return "_" + Strings.change(Strings.firstUpper(mapping.getProperty()), ".", "_"); } private Collection getPropertyMappings() { return propertyMappings.values(); } public Collection getPropertyMappingsNotInModel() throws XavaException { Collection names = new ArrayList(getModelProperties()); names.removeAll(getMetaModel().getPropertiesNames()); if (names.isEmpty()) return Collections.EMPTY_LIST; Collection result = new ArrayList(); for (Iterator it = names.iterator(); it.hasNext(); ) { String name = (String) it.next(); if (name.indexOf('_') < 0) { result.add(getPropertyMapping(name)); } } return result; } private Collection getReferenceMappings() { return referenceMappings == null ? Collections.EMPTY_LIST : referenceMappings.values(); } public Collection getCmpFields() throws XavaException { Collection r = new ArrayList(); Collection mappedColumns = new HashSet(); for (Iterator it = getPropertyMappings().iterator(); it.hasNext(); ) { PropertyMapping pMapping = (PropertyMapping) it.next(); r.addAll(pMapping.getCmpFields()); mappedColumns.add(pMapping.getColumn()); } for (Iterator it = getReferenceMappings().iterator(); it.hasNext(); ) { ReferenceMapping rMapping = (ReferenceMapping) it.next(); for (Iterator itFields = rMapping.getCmpFields().iterator(); itFields.hasNext(); ) { CmpField field = (CmpField) itFields.next(); if (!mappedColumns.contains(field.getColumn())) { r.add(field); mappedColumns.add(field.getColumn()); } } } return r; } public boolean hasReferenceConverters() { return !getReferenceMappingsWithConverter().isEmpty(); } public Collection getReferenceMappingsWithConverter() { if (referenceMappingsWithConverter == null) { referenceMappingsWithConverter = new ArrayList(); Iterator it = getReferenceMappings().iterator(); while (it.hasNext()) { ReferenceMapping referenceMapping = (ReferenceMapping) it.next(); Collection mrd = referenceMapping.getDetails(); Iterator itd = mrd.iterator(); while (itd.hasNext()) { ReferenceMappingDetail referenceMappingDetail = (ReferenceMappingDetail) itd.next(); if (referenceMappingDetail.hasConverter()) { referenceMappingsWithConverter.add(referenceMapping); } } } } return referenceMappingsWithConverter; } /** * Find the columns name in the formula and replace its by qualify columns name: 'name' -> * 't_reference.name' */ private String qualifyFormulaWithReferenceName( String formula, String referenceName, String modelProperty) { EntityMapping em = MetaComponent.get(referenceName).getEntityMapping(); Iterator<String> it = em.getColumns().iterator(); while (it.hasNext()) { String column = it.next(); if (formula.contains(column)) { formula = formula.replace( column, getQualifyColumnName(modelProperty, referenceName + "." + column)); } } return formula; } private String getQualifyColumnName(String modelProperty, String tableColumn) { if (modelProperty.indexOf('.') >= 0) { if (tableColumn.indexOf('.') < 0) return tableColumn; String reference = modelProperty.substring(0, modelProperty.lastIndexOf('.')); if (tableColumn.startsWith(getTableToQualifyColumn() + ".")) { String member = modelProperty.substring(modelProperty.lastIndexOf('.') + 1); if (getMetaModel().getMetaReference(reference).getMetaModelReferenced().isKey(member)) return tableColumn; } // The next code uses the alias of the table instead of its name. In order to // support multiple references to the same model if (reference.indexOf('.') >= 0) { if (getMetaModel().getMetaProperty(modelProperty).isKey()) { reference = reference.substring(0, reference.lastIndexOf('.')); } reference = reference.substring(reference.lastIndexOf('.') + 1); } return "T_" + reference + tableColumn.substring(tableColumn.lastIndexOf('.')); } else { return getTableToQualifyColumn() + "." + tableColumn; } } }
/** * To generate automatically reports from list mode. * * <p>Uses JasperReports. * * @author Javier Paniza */ public class GenerateReportServlet extends HttpServlet { private static Log log = LogFactory.getLog(GenerateReportServlet.class); public static class TableModelDecorator implements TableModel { private TableModel original; private List metaProperties; private boolean withValidValues = false; private Locale locale; private boolean labelAsHeader = false; private HttpServletRequest request; private boolean format = false; // format or no the values. If format = true, all values to the report are String private Integer columnCountLimit; public TableModelDecorator( HttpServletRequest request, TableModel original, List metaProperties, Locale locale, boolean labelAsHeader, boolean format, Integer columnCountLimit) throws Exception { this.request = request; this.original = original; this.metaProperties = metaProperties; this.locale = locale; this.withValidValues = calculateWithValidValues(); this.labelAsHeader = labelAsHeader; this.format = format; this.columnCountLimit = columnCountLimit; } private boolean calculateWithValidValues() { Iterator it = metaProperties.iterator(); while (it.hasNext()) { MetaProperty m = (MetaProperty) it.next(); if (m.hasValidValues()) return true; } return false; } private MetaProperty getMetaProperty(int i) { return (MetaProperty) metaProperties.get(i); } public int getRowCount() { return original.getRowCount(); } public int getColumnCount() { return columnCountLimit == null ? original.getColumnCount() : columnCountLimit; } public String getColumnName(int c) { return labelAsHeader ? getMetaProperty(c).getLabel(locale) : Strings.change(getMetaProperty(c).getQualifiedName(), ".", "_"); } public Class getColumnClass(int c) { return original.getColumnClass(c); } public boolean isCellEditable(int row, int column) { return original.isCellEditable(row, column); } public Object getValueAt(int row, int column) { if (isFormat()) return getValueWithWebEditorsFormat(row, column); else return getValueWithoutWebEditorsFormat(row, column); } private Object getValueWithoutWebEditorsFormat(int row, int column) { Object r = original.getValueAt(row, column); if (r instanceof Boolean) { if (((Boolean) r).booleanValue()) return XavaResources.getString(locale, "yes"); return XavaResources.getString(locale, "no"); } if (withValidValues) { MetaProperty p = getMetaProperty(column); if (p.hasValidValues()) { return p.getValidValueLabel(locale, original.getValueAt(row, column)); } } if (r instanceof java.util.Date) { MetaProperty p = getMetaProperty(column); // In order to use the type declared by the developer // and not the one returned by JDBC or the JPA engine if (java.sql.Time.class.isAssignableFrom(p.getType())) { return DateFormat.getTimeInstance(DateFormat.SHORT, locale).format(r); } if (java.sql.Timestamp.class.isAssignableFrom(p.getType())) { DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); return dateFormat.format(r); } return DateFormat.getDateInstance(DateFormat.SHORT, locale).format(r); } if (r instanceof BigDecimal) { return formatBigDecimal(r, locale); } return r; } private Object getValueWithWebEditorsFormat(int row, int column) { Object r = original.getValueAt(row, column); MetaProperty metaProperty = getMetaProperty(column); String result = WebEditors.format(this.request, metaProperty, r, null, "", true); if (isHtml(result)) { // this avoids that the report shows html content result = WebEditors.format(this.request, metaProperty, r, null, "", false); } return result; } public void setValueAt(Object value, int row, int column) { original.setValueAt(value, row, column); } public void addTableModelListener(TableModelListener l) { original.addTableModelListener(l); } public void removeTableModelListener(TableModelListener l) { original.removeTableModelListener(l); } private boolean isHtml(String value) { return value.matches("<.*>"); } public boolean isFormat() { return format; } public void setFormat(boolean format) { this.format = format; } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Locales.setCurrent(request); if (Users.getCurrent() == null) { // for a bug in websphere portal 5.1 with Domino LDAP Users.setCurrent((String) request.getSession().getAttribute("xava.user")); } request.getParameter("application"); // for a bug in websphere 5.1 request.getParameter("module"); // for a bug in websphere 5.1 Tab tab = (Tab) request.getSession().getAttribute("xava_reportTab"); int[] selectedRowsNumber = (int[]) request.getSession().getAttribute("xava_selectedRowsReportTab"); Map[] selectedKeys = (Map[]) request.getSession().getAttribute("xava_selectedKeysReportTab"); int[] selectedRows = getSelectedRows(selectedRowsNumber, selectedKeys, tab); request.getSession().removeAttribute("xava_selectedRowsReportTab"); Integer columnCountLimit = (Integer) request.getSession().getAttribute("xava_columnCountLimitReportTab"); request.getSession().removeAttribute("xava_columnCountLimitReportTab"); setDefaultSchema(request); String user = (String) request.getSession().getAttribute("xava_user"); request.getSession().removeAttribute("xava_user"); Users.setCurrent(user); String uri = request.getRequestURI(); if (uri.endsWith(".pdf")) { InputStream is; JRDataSource ds; Map parameters = new HashMap(); synchronized (tab) { tab.setRequest(request); parameters.put("Title", tab.getTitle()); parameters.put("Organization", getOrganization()); parameters.put("Date", getCurrentDate()); for (String totalProperty : tab.getTotalPropertiesNames()) { parameters.put(totalProperty + "__TOTAL__", getTotal(request, tab, totalProperty)); } TableModel tableModel = getTableModel(request, tab, selectedRows, false, true, null); tableModel.getValueAt(0, 0); if (tableModel.getRowCount() == 0) { generateNoRowsPage(response); return; } is = getReport(request, response, tab, tableModel, columnCountLimit); ds = new JRTableModelDataSource(tableModel); } JasperPrint jprint = JasperFillManager.fillReport(is, parameters, ds); response.setContentType("application/pdf"); response.setHeader( "Content-Disposition", "inline; filename=\"" + getFileName(tab) + ".pdf\""); JasperExportManager.exportReportToPdfStream(jprint, response.getOutputStream()); } else if (uri.endsWith(".csv")) { String csvEncoding = XavaPreferences.getInstance().getCSVEncoding(); if (!Is.emptyString(csvEncoding)) { response.setCharacterEncoding(csvEncoding); } response.setContentType("text/x-csv"); response.setHeader( "Content-Disposition", "inline; filename=\"" + getFileName(tab) + ".csv\""); synchronized (tab) { tab.setRequest(request); response .getWriter() .print( TableModels.toCSV( getTableModel(request, tab, selectedRows, true, false, columnCountLimit))); } } else { throw new ServletException( XavaResources.getString("report_type_not_supported", "", ".pdf .csv")); } } catch (Exception ex) { log.error(ex.getMessage(), ex); throw new ServletException(XavaResources.getString("report_error")); } finally { request.getSession().removeAttribute("xava_reportTab"); } } private void generateNoRowsPage(HttpServletResponse response) throws Exception { response.setContentType("text/html"); response.getWriter().println("<html><head><title>"); response.getWriter().println(XavaResources.getString("no_rows_report_message_title")); response .getWriter() .println( "</title></head><body style='font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;'>"); response.getWriter().println("<h1 style='font-size:22px;'>"); response.getWriter().println(XavaResources.getString("no_rows_report_message_title")); response.getWriter().println("</h1>"); response.getWriter().println("<p style='font-size:16px;'>"); response.getWriter().println(XavaResources.getString("no_rows_report_message_detail")); response.getWriter().println("</p></body></html>"); } private String getCurrentDate() { return java.text.DateFormat.getDateInstance(DateFormat.MEDIUM, Locales.getCurrent()) .format(new java.util.Date()); } private String getFileName(Tab tab) { String now = new SimpleDateFormat("yyyyMMdd_HHmm").format(new Date()); return tab.getTitle() + " " + now; } private Object getTotal(HttpServletRequest request, Tab tab, String totalProperty) { Object total = tab.getTotal(totalProperty); return WebEditors.format( request, tab.getMetaProperty(totalProperty), total, new Messages(), null, true); } private void setDefaultSchema(HttpServletRequest request) { String hibernateDefaultSchemaTab = (String) request.getSession().getAttribute("xava_hibernateDefaultSchemaTab"); if (hibernateDefaultSchemaTab != null) { request.getSession().removeAttribute("xava_hibernateDefaultSchemaTab"); XHibernate.setDefaultSchema(hibernateDefaultSchemaTab); } String jpaDefaultSchemaTab = (String) request.getSession().getAttribute("xava_jpaDefaultSchemaTab"); if (jpaDefaultSchemaTab != null) { request.getSession().removeAttribute("xava_jpaDefaultSchemaTab"); XPersistence.setDefaultSchema(jpaDefaultSchemaTab); } } protected String getOrganization() throws MissingResourceException, XavaException { return ReportParametersProviderFactory.getInstance().getOrganization(); } private InputStream getReport( HttpServletRequest request, HttpServletResponse response, Tab tab, TableModel tableModel, Integer columnCountLimit) throws ServletException, IOException { StringBuffer suri = new StringBuffer(); suri.append("/xava/jasperReport"); suri.append("?language="); suri.append(Locales.getCurrent().getLanguage()); suri.append("&widths="); suri.append(Arrays.toString(getWidths(tableModel))); if (columnCountLimit != null) { suri.append("&columnCountLimit="); suri.append(columnCountLimit); } response.setCharacterEncoding(XSystem.getEncoding()); return Servlets.getURIAsStream(request, response, suri.toString()); } private int[] getWidths(TableModel tableModel) { int[] widths = new int[tableModel.getColumnCount()]; for (int r = 0; r < Math.min(tableModel.getRowCount(), 500); r++) { // 500 is not for performance, but for using only a sample of data with huge table for (int c = 0; c < tableModel.getColumnCount(); c++) { Object o = tableModel.getValueAt(r, c); if (o instanceof String) { String s = ((String) o).trim(); if (s.length() > widths[c]) widths[c] = s.length(); } } } return widths; } private TableModel getTableModel( HttpServletRequest request, Tab tab, int[] selectedRows, boolean labelAsHeader, boolean format, Integer columnCountLimit) throws Exception { TableModel data = null; if (selectedRows != null && selectedRows.length > 0) { data = new SelectedRowsXTableModel(tab.getTableModel(), selectedRows); } else { data = tab.getAllDataTableModel(); } return new TableModelDecorator( request, data, tab.getMetaProperties(), Locales.getCurrent(), labelAsHeader, format, columnCountLimit); } private static Object formatBigDecimal(Object number, Locale locale) { NumberFormat nf = NumberFormat.getNumberInstance(locale); nf.setMinimumFractionDigits(2); return nf.format(number); } private int[] getSelectedRows(int[] selectedRowsNumber, Map[] selectedRowsKeys, Tab tab) { if (selectedRowsKeys == null || selectedRowsKeys.length == 0) return new int[0]; // selectedRowsNumber is the most performant so we use it when possible else if (selectedRowsNumber.length == selectedRowsKeys.length) return selectedRowsNumber; else { // find the rows from the selectedKeys // This has a poor performance, but it covers the case when the selected // rows are not loaded for the tab, something that can occurs if the user // select rows and afterwards reorder the list. try { int[] s = new int[selectedRowsKeys.length]; List selectedKeys = Arrays.asList(selectedRowsKeys); int end = tab.getTableModel().getTotalSize(); int x = 0; for (int i = 0; i < end; i++) { Map key = (Map) tab.getTableModel().getObjectAt(i); if (selectedKeys.contains(key)) { s[x] = i; x++; } } return s; } catch (Exception ex) { log.warn(XavaResources.getString("fails_selected"), ex); throw new XavaException("fails_selected"); } } } }