/** * <copyright> </copyright> * * $Id$ */ package org.talend.dataquality.indicators.impl; import java.sql.Types; import java.util.Date; import java.util.List; import java.util.TreeMap; import org.apache.log4j.Logger; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.talend.algorithms.AlgoUtils; import org.talend.dataquality.indicators.IndicatorValueType; import org.talend.dataquality.indicators.IndicatorsPackage; import org.talend.dataquality.indicators.MedianIndicator; import org.talend.utils.sql.Java2SqlType; import org.talend.utils.time.TimeTracer; /** * <!-- begin-user-doc --> An implementation of the model object '<em><b>Median Indicator</b></em>'. <!-- end-user-doc * --> * <p> * The following features are implemented: * <ul> * <li>{@link org.talend.dataquality.indicators.impl.MedianIndicatorImpl#getMedian <em>Median</em>}</li> * <li>{@link org.talend.dataquality.indicators.impl.MedianIndicatorImpl#getFrequenceTable <em>Frequence Table</em>}</li> * <li>{@link org.talend.dataquality.indicators.impl.MedianIndicatorImpl#getDateMedian <em>Date Median</em>}</li> * </ul> * </p> * * @generated */ public class MedianIndicatorImpl extends IndicatorImpl implements MedianIndicator { /** * The default value of the '{@link #getMedian() <em>Median</em>}' attribute. * <!-- begin-user-doc --> <!-- * end-user-doc --> * @see #getMedian() * @generated * @ordered */ protected static final Double MEDIAN_EDEFAULT = null; /** * The cached value of the '{@link #getMedian() <em>Median</em>}' attribute. * <!-- begin-user-doc --> <!-- * end-user-doc --> * @see #getMedian() * @generated * @ordered */ protected Double median = MEDIAN_EDEFAULT; /** * This is true if the Median attribute has been set. * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated * @ordered */ protected boolean medianESet; /** * The default value of the '{@link #getFrequenceTable() <em>Frequence Table</em>}' attribute. * <!-- begin-user-doc * --> <!-- end-user-doc --> * @see #getFrequenceTable() * @generated * @ordered */ protected static final TreeMap<Object, Long> FREQUENCE_TABLE_EDEFAULT = null; /** * The cached value of the '{@link #getFrequenceTable() <em>Frequence Table</em>}' attribute. * <!-- begin-user-doc * --> <!-- end-user-doc --> * @see #getFrequenceTable() * @generated * @ordered */ protected TreeMap<Object, Long> frequenceTable = FREQUENCE_TABLE_EDEFAULT; /** * The default value of the '{@link #getDateMedian() <em>Date Median</em>}' attribute. * <!-- begin-user-doc --> <!-- * end-user-doc --> * @see #getDateMedian() * @generated * @ordered */ protected static final Date DATE_MEDIAN_EDEFAULT = null; /** * The cached value of the '{@link #getDateMedian() <em>Date Median</em>}' attribute. * <!-- begin-user-doc --> <!-- * end-user-doc --> * @see #getDateMedian() * @generated * @ordered */ protected Date dateMedian = DATE_MEDIAN_EDEFAULT; /** * The sorted frequency table. Contains data as keys and count as values. * * @generated NOT */ // private TreeMap<Object, Long> freqTable = new TreeMap<Object, Long>(); /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ protected MedianIndicatorImpl() { super(); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override protected EClass eStaticClass() { return IndicatorsPackage.Literals.MEDIAN_INDICATOR; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public Double getMedian() { return median; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public void setMedian(Double newMedian) { Double oldMedian = median; median = newMedian; boolean oldMedianESet = medianESet; medianESet = true; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, IndicatorsPackage.MEDIAN_INDICATOR__MEDIAN, oldMedian, median, !oldMedianESet)); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public void unsetMedian() { Double oldMedian = median; boolean oldMedianESet = medianESet; median = MEDIAN_EDEFAULT; medianESet = false; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.UNSET, IndicatorsPackage.MEDIAN_INDICATOR__MEDIAN, oldMedian, MEDIAN_EDEFAULT, oldMedianESet)); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public boolean isSetMedian() { return medianESet; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public TreeMap<Object, Long> getFrequenceTableGen() { return frequenceTable; } /* * (non-Javadoc) * * @see org.talend.dataquality.indicators.MedianIndicator#getFrequenceTable() @generated NOT */ public TreeMap<Object, Long> getFrequenceTable() { if (frequenceTable == FREQUENCE_TABLE_EDEFAULT) { frequenceTable = new TreeMap<Object, Long>(); } return getFrequenceTableGen(); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public void setFrequenceTable(TreeMap<Object, Long> newFrequenceTable) { TreeMap<Object, Long> oldFrequenceTable = frequenceTable; frequenceTable = newFrequenceTable; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, IndicatorsPackage.MEDIAN_INDICATOR__FREQUENCE_TABLE, oldFrequenceTable, frequenceTable)); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public Date getDateMedian() { return dateMedian; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public void setDateMedian(Date newDateMedian) { Date oldDateMedian = dateMedian; dateMedian = newDateMedian; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, IndicatorsPackage.MEDIAN_INDICATOR__DATE_MEDIAN, oldDateMedian, dateMedian)); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated NOT */ public boolean computeMedian() { // scorreia keep private method "computeNumericMedian" as we may have a computeDateMedian later return computeNumericMedian(); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public Object eGet(int featureID, boolean resolve, boolean coreType) { switch (featureID) { case IndicatorsPackage.MEDIAN_INDICATOR__MEDIAN: return getMedian(); case IndicatorsPackage.MEDIAN_INDICATOR__FREQUENCE_TABLE: return getFrequenceTable(); case IndicatorsPackage.MEDIAN_INDICATOR__DATE_MEDIAN: return getDateMedian(); } return super.eGet(featureID, resolve, coreType); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @SuppressWarnings("unchecked") @Override public void eSet(int featureID, Object newValue) { switch (featureID) { case IndicatorsPackage.MEDIAN_INDICATOR__MEDIAN: setMedian((Double)newValue); return; case IndicatorsPackage.MEDIAN_INDICATOR__FREQUENCE_TABLE: setFrequenceTable((TreeMap<Object, Long>)newValue); return; case IndicatorsPackage.MEDIAN_INDICATOR__DATE_MEDIAN: setDateMedian((Date)newValue); return; } super.eSet(featureID, newValue); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public void eUnset(int featureID) { switch (featureID) { case IndicatorsPackage.MEDIAN_INDICATOR__MEDIAN: unsetMedian(); return; case IndicatorsPackage.MEDIAN_INDICATOR__FREQUENCE_TABLE: setFrequenceTable(FREQUENCE_TABLE_EDEFAULT); return; case IndicatorsPackage.MEDIAN_INDICATOR__DATE_MEDIAN: setDateMedian(DATE_MEDIAN_EDEFAULT); return; } super.eUnset(featureID); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public boolean eIsSet(int featureID) { switch (featureID) { case IndicatorsPackage.MEDIAN_INDICATOR__MEDIAN: return isSetMedian(); case IndicatorsPackage.MEDIAN_INDICATOR__FREQUENCE_TABLE: return FREQUENCE_TABLE_EDEFAULT == null ? frequenceTable != null : !FREQUENCE_TABLE_EDEFAULT.equals(frequenceTable); case IndicatorsPackage.MEDIAN_INDICATOR__DATE_MEDIAN: return DATE_MEDIAN_EDEFAULT == null ? dateMedian != null : !DATE_MEDIAN_EDEFAULT.equals(dateMedian); } return super.eIsSet(featureID); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated NOT toString() */ @Override public String toString() { StringBuffer result = new StringBuffer(super.toString()); result.append(" (median: "); if (medianESet) result.append(median); else result.append("<unset>"); return result.toString(); } private static final boolean trace = true; private static Logger log = Logger.getLogger(MedianIndicatorImpl.class); /** * ADDED scorreia Method "computeNumericMedian" computes the median for numerical objects (objects must be Number). * * @return true if ok. */ private boolean computeNumericMedian() { if (getCount() == null || getCount() == 0) { return false; } TimeTracer tt; if (trace) tt = new TimeTracer("Median computation with frequency table.", null); else tt = null; if (trace) { tt.start("searching median"); } long totalCount = super.getCount().longValue() - super.getNullCount().longValue(); double localMedian = AlgoUtils.getMedian(totalCount, this.getFrequenceTable()); if (trace) { tt.end("median found"); } this.setMedian(localMedian); return true; } /** * by default, it is set to true because when loading the indicator from file, the median is already computed. This * flag is set to false when new data are passed to the handle(data) method. This flag is not useful when median is * computed via SQL query. */ private boolean medianComputed = true; // fix bug 4936 set to true /* * (non-Javadoc) ADDED scorreia overriden method handle() * * @see org.talend.dataquality.indicators.impl.IndicatorImpl#handle(java.lang.Object) @generated NOT */ @Override public boolean handle(Object data) { boolean ok = super.handle(data); // TODO scorreia handle null values (handle case when null is replaced by a default value. if (data == null) { return ok; } return ok && AlgoUtils.incrementValueCounts(data, this.getFrequenceTable()); } /* * (non-Javadoc) * * @see org.talend.dataquality.indicators.impl.IndicatorImpl#storeSqlResults(java.util.List) * * ADDED scorreia 2008-05-02 storeSqlResults(List<Object[]> objects) */ @Override public boolean storeSqlResults(List<Object[]> objects) { if (!checkResults(objects, 1)) { return false; } // get the correct type of result from the analyzed element int javaType = this.getColumnType(); if (objects.size() == 1) { // case when 1 row is returned String med = String.valueOf(objects.get(0)[0]); if (med == null) { log.error("Median is null!!"); return false; } this.setMedian(MedianIndicatorImpl.getRealValue(javaType, med)); return true; } else if (objects.size() == 2) { // case when 2 rows are returned Double r1 = MedianIndicatorImpl.getRealValue(javaType, String.valueOf(objects.get(0)[0])); Double r2 = MedianIndicatorImpl.getRealValue(javaType, String.valueOf(objects.get(1)[0])); if (r1 == null || r2 == null) { log.error("Cannot compute the median: At least one of the rows is null: " + r1 + " | " + r2); return false; } this.setMedian((r1 + r2) / 2); // this.medianComputed = true; // fix bug 4936 return true; } return false; } /** * Method "getRealValue" converts object into double. * * @param javaType * @param object * @return */ static Double getRealValue(int javaType, String object) { // FIXME scorreia this is not the best way to work. Other indicator simply store dates. if (Java2SqlType.isDateInSQL(javaType)) { Date date = null; switch (javaType) { case Types.TIMESTAMP: date = java.sql.Timestamp.valueOf(object); break; case Types.DATE: date = java.sql.Date.valueOf(object); break; case Types.TIME: date = java.sql.Time.valueOf(object); break; default: break; } return date != null ? Double.valueOf(date.getTime()) : Double.NaN; } // else a number try { return Double.valueOf(object); } catch (NumberFormatException e) { return Double.NaN; } } /* * (non-Javadoc) * * @see org.talend.dataquality.indicators.impl.IndicatorImpl#getRealValue() */ @Override public Double getRealValue() { return median; } /* * (non-Javadoc) * * @see org.talend.dataquality.indicators.impl.ValueIndicatorImpl#getValueType() */ @Override public IndicatorValueType getValueType() { return IndicatorValueType.REAL_VALUE; } @Override public boolean reset() { this.median = MEDIAN_EDEFAULT; if (frequenceTable != null) { this.frequenceTable.clear(); } this.computed = COMPUTED_EDEFAULT; return super.reset(); } @Override public boolean finalizeComputation() { if (!isComputed()) { computeMedian(); } return super.finalizeComputation(); } public void setMedianComputed(boolean medianComputed) { this.medianComputed = medianComputed; } public boolean isMedianComputed() { return medianComputed; } } // MedianIndicatorImpl