All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.inspired.exporter.Exporter Maven / Gradle / Ivy

/*******************************************************************************
* Inspired Model Exporter is a framework to export data from pojo class.
* Copyright (C) 2016 Inspired Soft
* 
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see .    
*******************************************************************************/

package it.inspired.exporter;

import it.inspired.exporter.annotation.ExpoProperty;
import it.inspired.exporter.comparator.ExpoPropertyComparator;
import it.inspired.exporter.comparator.PropertyDescriptionComparator;
import it.inspired.exporter.utils.BeanUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.proxy.HibernateProxy;

/**
 * The abstract class that are extended to implements the 
 * two types of exporter provided: Excel and TXT.
 * 
 * @author Massimo Romano
 *
 */
public abstract class Exporter 
{
	private static final Logger log = Logger.getLogger(Exporter.class);

	// Object exported in a row
	private List exportedInRow = new ArrayList();
	
	protected List
headers = new ArrayList
(); protected int currentRow = 0; protected boolean enabledHeader = true; //------------------------------------------------------------------------------------------------- // Abstract Methods //------------------------------------------------------------------------------------------------- /** * Used to write the header columns */ protected abstract void writeHeader(); protected abstract void writeValue( int row, int coll, Object value ); public abstract void finalyze(); public abstract void write( OutputStream outputStream ) throws IOException; //------------------------------------------------------------------------------------------------- // Protected Methods //-------------------------------------------------------------------------------------- /** * Overriding this method is possible to exclude some properties from the export process. * @return A list of properties to exclude. */ protected List getExcludedProperties() { return new ArrayList(); } //-------------------------------------------------------------------------------------- /** * This method is used basically for internationalization to convert a key into a specific text * @param key A string key to convert * @return The message returned */ protected String getText( String key ) { throw new UnsupportedOperationException("getText(String key) must be implemented to use key converter"); } //-------------------------------------------------------------------------------------- /** * Return the capitalized name of the class or the name specified using the labelKey * @param header * @return */ protected String getHeaderName( Header header ) { String name = BeanUtils.capitalizeMethodName( header.getType().getSimpleName() ); String annoname = AnnotationHelper.getLabelKey( header.getType() ); if ( annoname != null ) { name = getText( annoname ); } return name; } protected String getPropertyHeaderName( PropertyDescriptor property ) { String name = BeanUtils.capitalizeMethodName( property.getName() ); String annoname = AnnotationHelper.getLabelKey( property ); if ( annoname != null ) { name = getText( annoname ); } return name; } //-------------------------------------------------------------------------------------- /** * Used to declare the header text of the exported file * @param col Column position of the header text * @param info Bean Information containing the property * @param property Property describing the column information */ protected void addHeader( Integer col, BeanInfo info, PropertyDescriptor property, ExpoProperty annotation ) { Header header = null; // Searching for the header associated to the bean information for ( Header head : headers ) { if ( head.isFor( info.getBeanDescriptor().getBeanClass() ) ) { header = head; break; } } if ( header == null ) { header = new Header( info.getBeanDescriptor().getBeanClass() ); headers.add( header ); } // Searching for the header property, if exist return for ( PropertyHeader ph : header.getProperties() ) { if ( ph.getProperty().equals( property ) ) { return; } } // Add the header if ( annotation == null ) { header.addProperty( property ); } else { header.addProperty(property, annotation); } } //-------------------------------------------------------------------------------------- // Private methods. //-------------------------------------------------------------------------------------- /** * Used to deproxy an hibernate object * @param proxy The object to deproxy * @return The deproxed object */ private static Object deproxy(Object proxy) { /* * Check if it is an HibernateProxy using String equals. * This should avoid to import Hibernate if it is not used. */ if ( proxy.getClass().getName().equalsIgnoreCase( "org.hibernate.proxy.HibernateProxy" ) ) { return ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer() .getImplementation(); } else { return proxy; } } //-------------------------------------------------------------------------------------- /** * Check if a property is included in the list of the excluded properties. * @param property The property to check. * @return True if exportable. */ private boolean isExportable( PropertyDescriptor property ) { return !getExcludedProperties().contains( property.getName() ); } //-------------------------------------------------------------------------------------- /** * Start the export of the object to the given row starting from column zero. * @param row The row number where to export the object. * @param obj The object to export. * @return The number of the column where the export ends. * * @throws IntrospectionException * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ private int export( int row, Object obj ) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { exportedInRow.clear(); int col = export( row, 0, obj ); log.debug( "Used columns: " + col ); return col; } //-------------------------------------------------------------------------------------- /** * Export the given object starting from the row and column specified. * @param row The row number to start. * @param coll The column number to start. * @param obj The object to export. * @return The number of the column where the export ends. * * @throws IntrospectionException * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ private int export( int row, int coll, Object obj ) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { List expQueue = new ArrayList(); obj = deproxy( obj ); // Check if it is exportable if ( obj == null || AnnotationHelper.isUnexportable( obj ) || AnnotationHelper.isExportIgnored ( obj ) || !AnnotationHelper.hasExpoElement( obj ) ) { return coll; } BeanInfo info = null; if ( AnnotationHelper.isExportSuperclass( obj ) ) { // Only the properties of the superclass are exported if they exist if ( obj.getClass().getSuperclass() == null ) { return coll; } info = Introspector.getBeanInfo( obj.getClass().getSuperclass() ); } else // Export Class { info = Introspector.getBeanInfo( obj.getClass() ); } log.debug( "Exporting object " + obj.getClass().getName() ); exportedInRow.add( obj ); // Get the list of properties to export for the given object if specified List oprops = AnnotationHelper.getProperty( obj ); // Gets all the properties from the objects and sort them PropertyDescriptor[] pds = info.getPropertyDescriptors(); Arrays.sort( pds, new PropertyDescriptionComparator() ); // If the object has an identifier, it is placed at the beginning if( BeanUtils.hasProperty( obj.getClass(), "id" ) ) { PropertyDescriptor pid = BeanUtils.getPropertyDescriptor( obj.getClass(), "id" ); if ( !AnnotationHelper.isUnexportable( pid.getReadMethod() ) ) { addHeader( coll, info, pid, null ); writeValue( row, coll, pid.getReadMethod().invoke(obj) ); coll++; } } // For each property the export rules are evaluated for (PropertyDescriptor property : pds) { // Id is ignored and any other property not included in the list of properties specified // in the ExpoProperty annotation if defined if ( property.getName().equals("id") || ( oprops != null && !oprops.contains( property.getName() ) ) ) { continue; } // Gets the method to get the property Method propertyGetter = property.getReadMethod(); // Check if the getter is marked as unexportable if ( AnnotationHelper.isUnexportable( propertyGetter ) ) { log.debug( "Property " + property.getName() + " has Unxportable annotation" ); continue; } // Check if the property is declased unexportable (eg. version) if ( !isExportable( property ) ) { log.debug( "Exluded property " + property.getName() + " of type " + property.getPropertyType().getSimpleName() ); continue; } if ( BeanUtils.isPrimitive( property ) ) { log.debug( "Exporting property " + property.getName() + " of type " + property.getPropertyType().getSimpleName() ); addHeader( coll, info, property, null ); // Get the prefix used to convert the value to a message String prefix = AnnotationHelper.getPrefixKey( obj, property.getName() ); if ( prefix == null ) { prefix = AnnotationHelper.getPrefixKey( propertyGetter, property.getName() ); } // Get the value and convert it if there is a prefix Object ovalue = propertyGetter.invoke(obj); if ( prefix == null || ovalue == null ) { writeValue( row, coll, ovalue ); } else { writeValue( row, coll, getText( prefix + ovalue ) ); } coll++; } else { // Oggetto non primitivo, verifico se e' indicata la proprieta' da esportare List eprops = AnnotationHelper.getExportProperty( propertyGetter ); if ( eprops == null ) { // Se la propieta' non e' indicata si esporta tutto l'oggetto come entita' a se Object value = propertyGetter.invoke(obj); expQueue.add( value ); } else { Collections.sort( eprops, new ExpoPropertyComparator() ); // Viene restituita la sola proprieta' indicata Object value = propertyGetter.invoke(obj); for ( ExpoProperty eprop : eprops ) { Object pvalue = BeanUtils.getProperty( value, eprop.value() ); if ( pvalue == null || BeanUtils.isPrimitive( pvalue.getClass() ) ) { log.debug( "Exporting property " + eprop + " of type " + info.getBeanDescriptor().getBeanClass().getSimpleName() ); addHeader( coll, info, BeanUtils.getPropertyDescriptor( property.getPropertyType(), eprop.value() ), eprop ); String prefix = AnnotationHelper.getPrefixKey( propertyGetter, eprop.value() ); if ( prefix == null ) { writeValue( row, coll, pvalue ); } else { writeValue( row, coll, getText( prefix + pvalue ) ); } coll++; } else { expQueue.add( pvalue ); } } } } } if ( !expQueue.isEmpty() ) { for ( Object value : expQueue ) { if ( !exportedInRow.contains( value ) ) { coll = export( row, coll, value ); } } } return coll; } //------------------------------------------------------------------------------------------------- // Public Methods //------------------------------------------------------------------------------------------------- /** * Should always be called */ public void init() { currentRow = 0; } //------------------------------------------------------------------------------------------------- /** * Start the export process to the given list of object. * @param list The list of object to export. * * @throws IllegalArgumentException * @throws IntrospectionException * @throws IllegalAccessException * @throws InvocationTargetException */ @SuppressWarnings("rawtypes") public void export( List list ) throws IllegalArgumentException, IntrospectionException, IllegalAccessException, InvocationTargetException { for ( Object item : list ) { export( currentRow++, item ); } } /** * Check if the header has to be added to the exported file. * @return True if the header is enabled. */ public boolean isEnabledHeader() { return enabledHeader; } /** * Set the enable header option. * @param enabledHeader The option to set. */ public void setEnabledHeader(boolean enabledHeader) { this.enabledHeader = enabledHeader; } }