=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/acl/Access.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/acl/Access.java 2014-03-27 04:44:41 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/acl/Access.java 2014-06-06 07:40:49 +0000 @@ -126,4 +126,17 @@ { this.delete = delete; } + + @Override + public String toString() + { + return "Access{" + + "manage=" + manage + + ", externalize=" + externalize + + ", write=" + write + + ", read=" + read + + ", update=" + update + + ", delete=" + delete + + '}'; + } } === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseAnalyticalObject.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseAnalyticalObject.java 2014-04-21 11:05:22 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseAnalyticalObject.java 2014-06-06 07:40:49 +0000 @@ -28,31 +28,14 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import static org.hisp.dhis.common.DimensionalObject.CATEGORYOPTIONCOMBO_DIM_ID; -import static org.hisp.dhis.common.DimensionalObject.DATAELEMENT_DIM_ID; -import static org.hisp.dhis.common.DimensionalObject.DATAELEMENT_OPERAND_ID; -import static org.hisp.dhis.common.DimensionalObject.DATASET_DIM_ID; -import static org.hisp.dhis.common.DimensionalObject.DATA_X_DIM_ID; -import static org.hisp.dhis.common.DimensionalObject.DIMENSION_SEP; -import static org.hisp.dhis.common.DimensionalObject.INDICATOR_DIM_ID; -import static org.hisp.dhis.common.DimensionalObject.ORGUNIT_DIM_ID; -import static org.hisp.dhis.common.DimensionalObject.PERIOD_DIM_ID; -import static org.hisp.dhis.common.DimensionalObject.STATIC_DIMS; -import static org.hisp.dhis.organisationunit.OrganisationUnit.KEY_LEVEL; -import static org.hisp.dhis.organisationunit.OrganisationUnit.KEY_ORGUNIT_GROUP; -import static org.hisp.dhis.organisationunit.OrganisationUnit.KEY_USER_ORGUNIT; -import static org.hisp.dhis.organisationunit.OrganisationUnit.KEY_USER_ORGUNIT_CHILDREN; -import static org.hisp.dhis.organisationunit.OrganisationUnit.KEY_USER_ORGUNIT_GRANDCHILDREN; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonView; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import org.apache.commons.lang.StringUtils; import org.hisp.dhis.common.adapter.JacksonPeriodDeserializer; import org.hisp.dhis.common.adapter.JacksonPeriodSerializer; @@ -80,35 +63,40 @@ import org.hisp.dhis.trackedentity.TrackedEntityDataElementDimension; import org.hisp.dhis.user.User; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonView; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.hisp.dhis.common.DimensionalObject.*; +import static org.hisp.dhis.organisationunit.OrganisationUnit.*; /** * This class contains associations to dimensional meta-data. Should typically * be sub-classed by analytical objects like tables, maps and charts. - * + *

* Implementation note: Objects currently managing this class are AnalyticsService, - * DefaultDimensionService and the getDimensionalObject and getDimensionalObjectList + * DefaultDimensionService and the getDimensionalObject and getDimensionalObjectList * methods of this class. - * + * * @author Lars Helge Overland */ +@JacksonXmlRootElement( localName = "analyticalObject", namespace = DxfNamespaces.DXF_2_0 ) public abstract class BaseAnalyticalObject extends BaseIdentifiableObject { public static final String NUMBER_FORMATTING_COMMA = "comma"; public static final String NUMBER_FORMATTING_SPACE = "space"; public static final String NUMBER_FORMATTING_NONE = "none"; - + public static final int ASC = -1; public static final int DESC = 1; public static final int NONE = 0; - + // ------------------------------------------------------------------------- // Persisted properties // ------------------------------------------------------------------------- @@ -121,7 +109,7 @@ @Scanned protected List dataElementOperands = new ArrayList(); - + @Scanned protected List dataSets = new ArrayList(); @@ -130,18 +118,18 @@ @Scanned protected List periods = new ArrayList(); - + protected RelativePeriods relatives; @Scanned protected List categoryDimensions = new ArrayList(); - + @Scanned protected List dataElementGroups = new ArrayList(); @Scanned protected List organisationUnitGroups = new ArrayList(); - + @Scanned protected List categoryOptionGroups = new ArrayList(); @@ -150,11 +138,11 @@ @Scanned protected List dataElementDimensions = new ArrayList(); - + protected boolean userOrganisationUnit; protected boolean userOrganisationUnitChildren; - + protected boolean userOrganisationUnitGrandChildren; @Scanned @@ -162,13 +150,13 @@ @Scanned protected List itemOrganisationUnitGroups = new ArrayList(); - + protected boolean rewindRelativePeriods; - + protected String digitGroupSeparator; - + protected int sortOrder; - + protected int topLimit; // ------------------------------------------------------------------------- @@ -176,11 +164,11 @@ // ------------------------------------------------------------------------- protected transient List columns = new ArrayList(); - + protected transient List rows = new ArrayList(); - + protected transient List filters = new ArrayList(); - + protected transient Map parentGraphMap = new HashMap(); // ------------------------------------------------------------------------- @@ -188,42 +176,42 @@ // ------------------------------------------------------------------------- protected transient List transientOrganisationUnits = new ArrayList(); - + protected transient List transientCategoryOptionCombos = new ArrayList(); - + protected transient Date relativePeriodDate; protected transient OrganisationUnit relativeOrganisationUnit; - + // ------------------------------------------------------------------------- // Logic // ------------------------------------------------------------------------- - public abstract void init( User user, Date date, OrganisationUnit organisationUnit, + public abstract void init( User user, Date date, OrganisationUnit organisationUnit, List organisationUnitsAtLevel, List organisationUnitsInGroups, I18nFormat format ); - + public abstract void populateAnalyticalProperties(); - + public boolean hasUserOrgUnit() { return userOrganisationUnit || userOrganisationUnitChildren || userOrganisationUnitGrandChildren; } - + public boolean hasRelativePeriods() { return relatives != null && !relatives.isEmpty(); } - + public boolean hasOrganisationUnitLevels() { return organisationUnitLevels != null && !organisationUnitLevels.isEmpty(); } - + public boolean hasItemOrganisationUnitGroups() { return itemOrganisationUnitGroups != null && !itemOrganisationUnitGroups.isEmpty(); } - + protected void addTransientOrganisationUnits( Collection organisationUnits ) { if ( organisationUnits != null ) @@ -231,7 +219,7 @@ this.transientOrganisationUnits.addAll( organisationUnits ); } } - + protected void addTransientOrganisationUnit( OrganisationUnit organisationUnit ) { if ( organisationUnit != null ) @@ -239,46 +227,46 @@ this.transientOrganisationUnits.add( organisationUnit ); } } - + /** * Assembles a DimensionalObject based on the persisted properties of this - * AnalyticalObject. Collapses indicators, data elements, data element + * AnalyticalObject. Collapses indicators, data elements, data element * operands and data sets into the dx dimension. - * + *

* Collapses fixed and relative periods into the pe dimension. Collapses * fixed and user organisation units into the ou dimension. - * - * @param dimension the dimension identifier. - * @param date the date used for generating relative periods. - * @param user the current user. + * + * @param dimension the dimension identifier. + * @param date the date used for generating relative periods. + * @param user the current user. * @param dynamicNames whether to use dynamic or static names. - * @param format the I18nFormat. + * @param format the I18nFormat. * @return a DimensionalObject. */ - protected DimensionalObject getDimensionalObject( String dimension, Date date, User user, boolean dynamicNames, + protected DimensionalObject getDimensionalObject( String dimension, Date date, User user, boolean dynamicNames, List organisationUnitsAtLevel, List organisationUnitsInGroups, I18nFormat format ) - { + { List items = new ArrayList(); - + DimensionType type = null; List categoryDims = getCategoryDims(); - + if ( DATA_X_DIM_ID.equals( dimension ) ) { items.addAll( indicators ); items.addAll( dataElements ); items.addAll( dataElementOperands ); items.addAll( dataSets ); - + type = DimensionType.DATA_X; } else if ( PERIOD_DIM_ID.equals( dimension ) ) { setPeriodNames( periods, dynamicNames, format ); - + items.addAll( periods ); - + if ( hasRelativePeriods() ) { if ( rewindRelativePeriods ) @@ -290,65 +278,65 @@ items.addAll( relatives.getRelativePeriods( date, format, dynamicNames ) ); } } - + type = DimensionType.PERIOD; } else if ( ORGUNIT_DIM_ID.equals( dimension ) ) { items.addAll( organisationUnits ); items.addAll( transientOrganisationUnits ); - + if ( userOrganisationUnit && user != null && user.hasDataViewOrganisationUnitWithFallback() ) { items.add( user.getDataViewOrganisationUnitWithFallback() ); } - + if ( userOrganisationUnitChildren && user != null && user.hasDataViewOrganisationUnitWithFallback() ) { items.addAll( user.getDataViewOrganisationUnitWithFallback().getSortedChildren() ); } - + if ( userOrganisationUnitGrandChildren && user != null && user.hasDataViewOrganisationUnitWithFallback() ) { items.addAll( user.getDataViewOrganisationUnitWithFallback().getSortedGrandChildren() ); } - + if ( organisationUnitLevels != null && !organisationUnitLevels.isEmpty() && organisationUnitsAtLevel != null ) { items.addAll( organisationUnitsAtLevel ); // Must be set externally } - + if ( itemOrganisationUnitGroups != null && !itemOrganisationUnitGroups.isEmpty() && organisationUnitsInGroups != null ) { items.addAll( organisationUnitsInGroups ); // Must be set externally } - + type = DimensionType.ORGANISATIONUNIT; } else if ( CATEGORYOPTIONCOMBO_DIM_ID.equals( dimension ) ) { items.addAll( transientCategoryOptionCombos ); - + type = DimensionType.CATEGORY_OPTION_COMBO; } else if ( categoryDims.contains( dimension ) ) { DataElementCategoryDimension categoryDimension = categoryDimensions.get( categoryDims.indexOf( dimension ) ); - + items.addAll( categoryDimension.getItems() ); - + type = DimensionType.CATEGORY; } else if ( STATIC_DIMS.contains( dimension ) ) - { + { type = DimensionType.STATIC; } else { // Data element group set - + ListMap deGroupMap = new ListMap(); - + for ( DataElementGroup group : dataElementGroups ) { if ( group.getGroupSet() != null ) @@ -356,18 +344,18 @@ deGroupMap.putValue( group.getGroupSet().getDimension(), group ); } } - + if ( deGroupMap.containsKey( dimension ) ) { items.addAll( deGroupMap.get( dimension ) ); - + type = DimensionType.DATAELEMENT_GROUPSET; } // Organisation unit group set - + ListMap ouGroupMap = new ListMap(); - + for ( OrganisationUnitGroup group : organisationUnitGroups ) { if ( group.getGroupSet() != null ) @@ -375,18 +363,18 @@ ouGroupMap.putValue( group.getGroupSet().getUid(), group ); } } - + if ( ouGroupMap.containsKey( dimension ) ) { items.addAll( ouGroupMap.get( dimension ) ); - + type = DimensionType.ORGANISATIONUNIT_GROUPSET; } // Category option group set - + ListMap coGroupMap = new ListMap(); - + for ( CategoryOptionGroup group : categoryOptionGroups ) { if ( group.getGroupSet() != null ) @@ -394,99 +382,99 @@ coGroupMap.putValue( group.getGroupSet().getUid(), group ); } } - + if ( coGroupMap.containsKey( dimension ) ) { items.addAll( coGroupMap.get( dimension ) ); - + type = DimensionType.CATEGORYOPTION_GROUPSET; } - + // Tracked entity attribute - + Map attributes = new HashMap(); - + for ( TrackedEntityAttributeDimension attribute : attributeDimensions ) { attributes.put( attribute.getUid(), attribute ); } - + if ( attributes.containsKey( dimension ) ) { TrackedEntityAttributeDimension tead = attributes.get( dimension ); - + return new BaseDimensionalObject( dimension, DimensionType.TRACKED_ENTITY_ATTRIBUTE, null, tead.getDisplayName(), tead.getFilter() ); } - + // Tracked entity data element - + Map dataElements = new HashMap(); - + for ( TrackedEntityDataElementDimension dataElement : dataElementDimensions ) { dataElements.put( dataElement.getUid(), dataElement ); } - + if ( dataElements.containsKey( dimension ) ) { TrackedEntityDataElementDimension tedd = dataElements.get( dimension ); - + return new BaseDimensionalObject( dimension, DimensionType.TRACKED_ENTITY_DATAELEMENT, null, tedd.getDisplayName(), tedd.getFilter() ); } } - + IdentifiableObjectUtils.removeDuplicates( items ); - + return new BaseDimensionalObject( dimension, type, items ); } - + /** * Assembles a list of DimensionalObjects based on the concrete objects in - * this BaseAnalyticalObject. Explodes the dx dimension into the in|de|dc|ds + * this BaseAnalyticalObject. Explodes the dx dimension into the in|de|dc|ds * concrete objects and returns them as separate DimensionalObjects. - * + *

* Merges fixed and relative periods into the pe dimension, where the - * RelativePeriods object is represented by enums (e.g. LAST_MONTH). Merges - * fixed and user organisation units into the ou dimension, where user + * RelativePeriods object is represented by enums (e.g. LAST_MONTH). Merges + * fixed and user organisation units into the ou dimension, where user * organisation units properties are represented by enums (e.g. USER_ORG_UNIT). - * + *

* This method is useful when serializing the AnalyticalObject. - * + * * @param dimension the dimension identifier. * @return a list of DimensionalObjects. */ protected List getDimensionalObjectList( String dimension ) { List objects = new ArrayList(); - + List categoryDims = getCategoryDims(); - + if ( DATA_X_DIM_ID.equals( dimension ) ) { if ( !indicators.isEmpty() ) { objects.add( new BaseDimensionalObject( INDICATOR_DIM_ID, DimensionType.INDICATOR, indicators ) ); } - + if ( !dataElements.isEmpty() ) { objects.add( new BaseDimensionalObject( DATAELEMENT_DIM_ID, DimensionType.DATAELEMENT, dataElements ) ); } - + if ( !dataElementOperands.isEmpty() ) { objects.add( new BaseDimensionalObject( DATAELEMENT_OPERAND_ID, DimensionType.DATAELEMENT_OPERAND, dataElementOperands ) ); } - + if ( !dataSets.isEmpty() ) { objects.add( new BaseDimensionalObject( DATASET_DIM_ID, DimensionType.DATASET, dataSets ) ); } } - else if ( PERIOD_DIM_ID.equals( dimension ) && ( !periods.isEmpty() || hasRelativePeriods() ) ) + else if ( PERIOD_DIM_ID.equals( dimension ) && (!periods.isEmpty() || hasRelativePeriods()) ) { List periodList = new ArrayList( periods ); - + if ( hasRelativePeriods() ) { List list = relatives.getRelativePeriodEnums(); @@ -496,52 +484,52 @@ periodList.add( new ConfigurablePeriod( periodEnum.toString() ) ); } } - + Collections.sort( periodList, new AscendingPeriodComparator() ); - + objects.add( new BaseDimensionalObject( dimension, DimensionType.PERIOD, periodList ) ); - } - else if ( ORGUNIT_DIM_ID.equals( dimension ) && ( !organisationUnits.isEmpty() || !transientOrganisationUnits.isEmpty() || hasUserOrgUnit() ) ) + } + else if ( ORGUNIT_DIM_ID.equals( dimension ) && (!organisationUnits.isEmpty() || !transientOrganisationUnits.isEmpty() || hasUserOrgUnit()) ) { List ouList = new ArrayList(); ouList.addAll( organisationUnits ); ouList.addAll( transientOrganisationUnits ); - + if ( userOrganisationUnit ) { ouList.add( new BaseNameableObject( KEY_USER_ORGUNIT, KEY_USER_ORGUNIT, KEY_USER_ORGUNIT ) ); } - + if ( userOrganisationUnitChildren ) { ouList.add( new BaseNameableObject( KEY_USER_ORGUNIT_CHILDREN, KEY_USER_ORGUNIT_CHILDREN, KEY_USER_ORGUNIT_CHILDREN ) ); } - + if ( userOrganisationUnitGrandChildren ) { ouList.add( new BaseNameableObject( KEY_USER_ORGUNIT_GRANDCHILDREN, KEY_USER_ORGUNIT_GRANDCHILDREN, KEY_USER_ORGUNIT_GRANDCHILDREN ) ); } - + if ( organisationUnitLevels != null && !organisationUnitLevels.isEmpty() ) { for ( Integer level : organisationUnitLevels ) { String id = KEY_LEVEL + level; - + ouList.add( new BaseNameableObject( id, id, id ) ); } } - + if ( itemOrganisationUnitGroups != null && !itemOrganisationUnitGroups.isEmpty() ) { for ( OrganisationUnitGroup group : itemOrganisationUnitGroups ) { String id = KEY_ORGUNIT_GROUP + group.getUid(); - + ouList.add( new BaseNameableObject( id, id, id ) ); } } - + objects.add( new BaseDimensionalObject( dimension, DimensionType.ORGANISATIONUNIT, ouList ) ); } else if ( CATEGORYOPTIONCOMBO_DIM_ID.equals( dimension ) ) @@ -551,7 +539,7 @@ else if ( categoryDims.contains( dimension ) ) { DataElementCategoryDimension categoryDimension = categoryDimensions.get( categoryDims.indexOf( dimension ) ); - + objects.add( new BaseDimensionalObject( dimension, DimensionType.CATEGORY, categoryDimension.getItems() ) ); } else if ( STATIC_DIMS.contains( dimension ) ) @@ -561,9 +549,9 @@ else { // Data element group set - + ListMap deGroupMap = new ListMap(); - + for ( DataElementGroup group : dataElementGroups ) { if ( group.getGroupSet() != null ) @@ -571,16 +559,16 @@ deGroupMap.putValue( group.getGroupSet().getDimension(), group ); } } - + if ( deGroupMap.containsKey( dimension ) ) { objects.add( new BaseDimensionalObject( dimension, DimensionType.DATAELEMENT_GROUPSET, deGroupMap.get( dimension ) ) ); } - + // Organisation unit group set - + ListMap ouGroupMap = new ListMap(); - + for ( OrganisationUnitGroup group : organisationUnitGroups ) { if ( group.getGroupSet() != null ) @@ -588,16 +576,16 @@ ouGroupMap.putValue( group.getGroupSet().getUid(), group ); } } - + if ( ouGroupMap.containsKey( dimension ) ) { objects.add( new BaseDimensionalObject( dimension, DimensionType.ORGANISATIONUNIT_GROUPSET, ouGroupMap.get( dimension ) ) ); } - + // Category option group set - + ListMap coGroupMap = new ListMap(); - + for ( CategoryOptionGroup group : categoryOptionGroups ) { if ( group.getGroupSet() != null ) @@ -605,57 +593,57 @@ coGroupMap.putValue( group.getGroupSet().getUid(), group ); } } - + if ( coGroupMap.containsKey( dimension ) ) { objects.add( new BaseDimensionalObject( dimension, DimensionType.CATEGORYOPTION_GROUPSET, coGroupMap.get( dimension ) ) ); } // Tracked entity attribute - + Map attributes = new HashMap(); - + for ( TrackedEntityAttributeDimension attribute : attributeDimensions ) { attributes.put( attribute.getUid(), attribute ); } - + if ( attributes.containsKey( dimension ) ) { TrackedEntityAttributeDimension tead = attributes.get( dimension ); - + objects.add( new BaseDimensionalObject( dimension, DimensionType.TRACKED_ENTITY_ATTRIBUTE, null, tead.getDisplayName(), tead.getFilter() ) ); } - + // Tracked entity data element Map dataElements = new HashMap(); - + for ( TrackedEntityDataElementDimension dataElement : dataElementDimensions ) { dataElements.put( dataElement.getUid(), dataElement ); } - + if ( dataElements.containsKey( dimension ) ) { TrackedEntityDataElementDimension tedd = dataElements.get( dimension ); - + objects.add( new BaseDimensionalObject( dimension, DimensionType.TRACKED_ENTITY_DATAELEMENT, null, tedd.getDisplayName(), tedd.getFilter() ) ); } } - + return objects; } - + private List getCategoryDims() { List categoryDims = new ArrayList(); - + for ( DataElementCategoryDimension dim : categoryDimensions ) { categoryDims.add( dim.getDimension().getDimension() ); } - + return categoryDims; } @@ -666,34 +654,34 @@ RelativePeriods.setName( period, null, dynamicNames, format ); } } - + /** - * Splits the keys of the given map on the dimension identifier separator, + * Splits the keys of the given map on the dimension identifier separator, * sorts the identifiers, writes them out as a key and puts the key back into * the map. */ public static void sortKeys( Map valueMap ) { Map map = new HashMap(); - + for ( String key : valueMap.keySet() ) { if ( key != null ) { String[] ids = key.split( DIMENSION_SEP ); - + Collections.sort( Arrays.asList( ids ) ); - + String sortedKey = StringUtils.join( ids, DIMENSION_SEP ); - + map.put( sortedKey, valueMap.get( key ) ); } } - + valueMap.clear(); valueMap.putAll( map ); } - + /** * Generates an identifier based on the given lists of NameableObjects. Uses * the UIDs for each NameableObject, sorts them and writes them out as a key. @@ -701,11 +689,11 @@ public static String getIdentifier( List column, List row ) { List ids = new ArrayList(); - + List dimensions = new ArrayList(); dimensions.addAll( column != null ? column : new ArrayList() ); dimensions.addAll( row != null ? row : new ArrayList() ); - + for ( NameableObject item : dimensions ) { if ( item.getClass().isAssignableFrom( DataElementOperand.class ) ) @@ -718,12 +706,12 @@ ids.add( item.getUid() ); } } - + Collections.sort( ids ); - + return StringUtils.join( ids, DIMENSION_SEP ); } - + /** * Returns meta-data mapping for this analytical object. Includes a identifier * to name mapping for dynamic dimensions. @@ -731,25 +719,25 @@ public Map getMetaData() { Map meta = new HashMap(); - + for ( DataElementGroup group : dataElementGroups ) { meta.put( group.getGroupSet().getUid(), group.getGroupSet().getName() ); } - + for ( OrganisationUnitGroup group : organisationUnitGroups ) { meta.put( group.getGroupSet().getUid(), group.getGroupSet().getName() ); } - + for ( DataElementCategoryDimension category : categoryDimensions ) { meta.put( category.getDimension().getUid(), category.getDimension().getName() ); } - + return meta; } - + /** * Clear or set to false all persistent dimensional (not option) properties for this object. */ @@ -772,18 +760,18 @@ organisationUnitLevels.clear(); itemOrganisationUnitGroups.clear(); } - + @Override public void mergeWith( IdentifiableObject other ) { super.mergeWith( other ); - + if ( other.getClass().isInstance( this ) ) { BaseAnalyticalObject object = (BaseAnalyticalObject) other; - + this.clear(); - + indicators.addAll( object.getIndicators() ); dataElements.addAll( object.getDataElements() ); dataElementOperands.addAll( object.getDataElementOperands() ); @@ -814,10 +802,10 @@ // ------------------------------------------------------------------------- @JsonProperty - @JsonSerialize( contentAs = BaseNameableObject.class ) - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlElementWrapper( localName = "indicators", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "indicator", namespace = DxfNamespaces.DXF_2_0) + @JsonSerialize(contentAs = BaseNameableObject.class) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlElementWrapper(localName = "indicators", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "indicator", namespace = DxfNamespaces.DXF_2_0) public List getIndicators() { return indicators; @@ -829,10 +817,10 @@ } @JsonProperty - @JsonSerialize( contentAs = BaseNameableObject.class ) - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlElementWrapper( localName = "dataElements", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "dataElement", namespace = DxfNamespaces.DXF_2_0) + @JsonSerialize(contentAs = BaseNameableObject.class) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlElementWrapper(localName = "dataElements", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "dataElement", namespace = DxfNamespaces.DXF_2_0) public List getDataElements() { return dataElements; @@ -844,10 +832,10 @@ } @JsonProperty - @JsonSerialize( contentAs = BaseIdentifiableObject.class ) - @JsonView( DetailedView.class ) - @JacksonXmlElementWrapper( localName = "dataElementOperands", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "dataElementOperand", namespace = DxfNamespaces.DXF_2_0) + @JsonSerialize(contentAs = BaseIdentifiableObject.class) + @JsonView(DetailedView.class) + @JacksonXmlElementWrapper(localName = "dataElementOperands", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "dataElementOperand", namespace = DxfNamespaces.DXF_2_0) public List getDataElementOperands() { return dataElementOperands; @@ -859,10 +847,10 @@ } @JsonProperty - @JsonSerialize( contentAs = BaseNameableObject.class ) - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlElementWrapper( localName = "dataSets", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "dataSet", namespace = DxfNamespaces.DXF_2_0) + @JsonSerialize(contentAs = BaseNameableObject.class) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlElementWrapper(localName = "dataSets", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "dataSet", namespace = DxfNamespaces.DXF_2_0) public List getDataSets() { return dataSets; @@ -874,10 +862,10 @@ } @JsonProperty - @JsonSerialize( contentAs = BaseNameableObject.class ) - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlElementWrapper( localName = "organisationUnits", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "organisationUnit", namespace = DxfNamespaces.DXF_2_0) + @JsonSerialize(contentAs = BaseNameableObject.class) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlElementWrapper(localName = "organisationUnits", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "organisationUnit", namespace = DxfNamespaces.DXF_2_0) public List getOrganisationUnits() { return organisationUnits; @@ -889,11 +877,11 @@ } @JsonProperty - @JsonSerialize( contentUsing = JacksonPeriodSerializer.class ) - @JsonDeserialize( contentUsing = JacksonPeriodDeserializer.class ) - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlElementWrapper( localName = "periods", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "period", namespace = DxfNamespaces.DXF_2_0) + @JsonSerialize(contentUsing = JacksonPeriodSerializer.class) + @JsonDeserialize(contentUsing = JacksonPeriodDeserializer.class) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlElementWrapper(localName = "periods", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "period", namespace = DxfNamespaces.DXF_2_0) public List getPeriods() { return periods; @@ -904,9 +892,9 @@ this.periods = periods; } - @JsonProperty( value = "relativePeriods" ) - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0) + @JsonProperty(value = "relativePeriods") + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public RelativePeriods getRelatives() { return relatives; @@ -928,9 +916,9 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlElementWrapper( localName = "dataElementGroups", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "dataElementGroup", namespace = DxfNamespaces.DXF_2_0) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlElementWrapper(localName = "dataElementGroups", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "dataElementGroup", namespace = DxfNamespaces.DXF_2_0) public List getDataElementGroups() { return dataElementGroups; @@ -942,9 +930,9 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlElementWrapper( localName = "organisationUnitGroups", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "organisationUnitGroup", namespace = DxfNamespaces.DXF_2_0) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlElementWrapper(localName = "organisationUnitGroups", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "organisationUnitGroup", namespace = DxfNamespaces.DXF_2_0) public List getOrganisationUnitGroups() { return organisationUnitGroups; @@ -987,8 +975,8 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isUserOrganisationUnit() { return userOrganisationUnit; @@ -1000,8 +988,8 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isUserOrganisationUnitChildren() { return userOrganisationUnitChildren; @@ -1013,8 +1001,8 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isUserOrganisationUnitGrandChildren() { return userOrganisationUnitGrandChildren; @@ -1026,9 +1014,9 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlElementWrapper( localName = "organisationUnitLevels", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "organisationUnitLevel", namespace = DxfNamespaces.DXF_2_0) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlElementWrapper(localName = "organisationUnitLevels", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "organisationUnitLevel", namespace = DxfNamespaces.DXF_2_0) public List getOrganisationUnitLevels() { return organisationUnitLevels; @@ -1040,9 +1028,9 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class} ) - @JacksonXmlElementWrapper( localName = "itemOrganisationUnitGroups", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "itemOrganisationUnitGroup", namespace = DxfNamespaces.DXF_2_0) + @JsonView({ DetailedView.class, ExportView.class }) + @JacksonXmlElementWrapper(localName = "itemOrganisationUnitGroups", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "itemOrganisationUnitGroup", namespace = DxfNamespaces.DXF_2_0) public List getItemOrganisationUnitGroups() { return itemOrganisationUnitGroups; @@ -1054,8 +1042,8 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class, DimensionalView.class} ) - @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0) + @JsonView({ DetailedView.class, ExportView.class, DimensionalView.class }) + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isRewindRelativePeriods() { return rewindRelativePeriods; @@ -1067,8 +1055,8 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class, DimensionalView.class} ) - @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 ) + @JsonView({ DetailedView.class, ExportView.class, DimensionalView.class }) + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getDigitGroupSeparator() { return digitGroupSeparator; @@ -1080,8 +1068,8 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class, DimensionalView.class} ) - @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 ) + @JsonView({ DetailedView.class, ExportView.class, DimensionalView.class }) + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public int getSortOrder() { return sortOrder; @@ -1093,8 +1081,8 @@ } @JsonProperty - @JsonView( {DetailedView.class, ExportView.class, DimensionalView.class} ) - @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 ) + @JsonView({ DetailedView.class, ExportView.class, DimensionalView.class }) + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public int getTopLimit() { return topLimit; @@ -1132,11 +1120,11 @@ // ------------------------------------------------------------------------- @JsonProperty - @JsonDeserialize( contentAs = BaseDimensionalObject.class ) - @JsonSerialize( contentAs = BaseDimensionalObject.class ) - @JsonView( {DimensionalView.class} ) - @JacksonXmlElementWrapper( localName = "columns", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "column", namespace = DxfNamespaces.DXF_2_0) + @JsonDeserialize(contentAs = BaseDimensionalObject.class) + @JsonSerialize(contentAs = BaseDimensionalObject.class) + @JsonView({ DimensionalView.class }) + @JacksonXmlElementWrapper(localName = "columns", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "column", namespace = DxfNamespaces.DXF_2_0) public List getColumns() { return columns; @@ -1148,11 +1136,11 @@ } @JsonProperty - @JsonDeserialize( contentAs = BaseDimensionalObject.class ) - @JsonSerialize( contentAs = BaseDimensionalObject.class ) - @JsonView( {DimensionalView.class} ) - @JacksonXmlElementWrapper( localName = "rows", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "row", namespace = DxfNamespaces.DXF_2_0) + @JsonDeserialize(contentAs = BaseDimensionalObject.class) + @JsonSerialize(contentAs = BaseDimensionalObject.class) + @JsonView({ DimensionalView.class }) + @JacksonXmlElementWrapper(localName = "rows", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "row", namespace = DxfNamespaces.DXF_2_0) public List getRows() { return rows; @@ -1164,11 +1152,11 @@ } @JsonProperty - @JsonDeserialize( contentAs = BaseDimensionalObject.class ) - @JsonSerialize( contentAs = BaseDimensionalObject.class ) - @JsonView( {DimensionalView.class} ) - @JacksonXmlElementWrapper( localName = "filters", namespace = DxfNamespaces.DXF_2_0) - @JacksonXmlProperty( localName = "filter", namespace = DxfNamespaces.DXF_2_0) + @JsonDeserialize(contentAs = BaseDimensionalObject.class) + @JsonSerialize(contentAs = BaseDimensionalObject.class) + @JsonView({ DimensionalView.class }) + @JacksonXmlElementWrapper(localName = "filters", namespace = DxfNamespaces.DXF_2_0) + @JacksonXmlProperty(localName = "filter", namespace = DxfNamespaces.DXF_2_0) public List getFilters() { return filters; @@ -1180,7 +1168,7 @@ } @JsonProperty - @JsonView( {DimensionalView.class} ) + @JsonView({ DimensionalView.class }) public Map getParentGraphMap() { return parentGraphMap; === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElement.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElement.java 2014-04-25 14:00:28 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElement.java 2014-06-06 07:40:49 +0000 @@ -323,7 +323,7 @@ public PeriodType getPeriodType() { DataSet dataSet = getDataSet(); - + return dataSet != null ? dataSet.getPeriodType() : null; } @@ -453,7 +453,7 @@ { return optionSet != null; } - + // ------------------------------------------------------------------------- // Getters and setters // ------------------------------------------------------------------------- === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java 2014-06-05 09:09:03 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java 2014-06-06 07:40:49 +0000 @@ -28,10 +28,13 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE */ -import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.hisp.dhis.node.exception.InvalidTypeException; +import org.hisp.dhis.node.types.SimpleNode; +import org.springframework.core.OrderComparator; +import org.springframework.core.Ordered; +import java.util.Collections; import java.util.List; /** @@ -142,7 +145,33 @@ @Override public List getChildren() { - return ImmutableList.copyOf( children ); + List clone = Lists.newArrayList( children ); + Collections.sort( clone, OrderComparator.INSTANCE ); + return clone; + } + + @Override + public int getOrder() + { + if ( isSimple() ) + { + if ( ((SimpleNode) this).isAttribute() ) + { + return 10; + } + + return 20; + } + else if ( isComplex() ) + { + return 30; + } + else if ( isCollection() ) + { + return 40; + } + + return Ordered.LOWEST_PRECEDENCE; } @Override === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Node.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Node.java 2014-06-05 09:09:03 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Node.java 2014-06-06 07:40:49 +0000 @@ -28,12 +28,14 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE */ +import org.springframework.core.Ordered; + import java.util.List; /** * @author Morten Olav Hansen */ -public interface Node +public interface Node extends Ordered { /** * Name of this node. === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java 2014-06-04 16:22:56 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java 2014-06-06 07:40:49 +0000 @@ -35,6 +35,8 @@ import org.hisp.dhis.node.types.ComplexNode; import org.hisp.dhis.node.types.RootNode; import org.hisp.dhis.node.types.SimpleNode; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @@ -49,6 +51,7 @@ * @author Morten Olav Hansen */ @Component +@Scope( ConfigurableBeanFactory.SCOPE_PROTOTYPE ) public class StAXNodeSerializer implements NodeSerializer { public static final String CONTENT_TYPE = "application/xml"; @@ -68,7 +71,9 @@ try { + xmlFactory.setProperty( "javax.xml.stream.isRepairingNamespaces", true ); writer = xmlFactory.createXMLStreamWriter( outputStream ); + writer.setDefaultNamespace( rootNode.getDefaultNamespace() ); writeRootNode( rootNode, writer ); writer.flush(); } @@ -182,7 +187,7 @@ { if ( !StringUtils.isEmpty( node.getNamespace() ) ) { - writer.writeStartElement( "", node.getName(), node.getNamespace() ); + writer.writeStartElement( node.getNamespace(), node.getName() ); } else { === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/RootNode.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/RootNode.java 2014-05-31 23:48:24 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/RootNode.java 2014-06-06 07:40:49 +0000 @@ -28,13 +28,35 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE */ +import org.hisp.dhis.node.Node; + /** * @author Morten Olav Hansen */ public class RootNode extends ComplexNode { + private String defaultNamespace; + public RootNode( String name ) { super( name ); } + + public RootNode( Node node ) + { + super( node.getName() ); + setNamespace( node.getNamespace() ); + setComment( node.getComment() ); + addChildren( node.getChildren() ); + } + + public String getDefaultNamespace() + { + return defaultNamespace; + } + + public void setDefaultNamespace( String defaultNamespace ) + { + this.defaultNamespace = defaultNamespace; + } } === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/SimpleNode.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/SimpleNode.java 2014-06-04 18:33:34 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/SimpleNode.java 2014-06-06 07:40:49 +0000 @@ -28,11 +28,14 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE */ +import com.google.common.collect.Lists; import org.hisp.dhis.node.AbstractNode; import org.hisp.dhis.node.Node; import org.hisp.dhis.node.NodeType; import org.hisp.dhis.node.exception.InvalidTypeException; +import java.util.List; + /** * @author Morten Olav Hansen */ @@ -49,6 +52,12 @@ this.attribute = false; } + public SimpleNode( String name, Object value, boolean attribute ) + { + this( name, value ); + this.attribute = attribute; + } + public Object getValue() { return value; === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/DefaultNodeService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/DefaultNodeService.java 2014-06-05 11:56:44 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/DefaultNodeService.java 2014-06-06 07:40:49 +0000 @@ -48,7 +48,7 @@ @Autowired( required = false ) private List nodeSerializers = Lists.newArrayList(); - @Autowired(required = false) + @Autowired( required = false ) private List nodeDeserializers = Lists.newArrayList(); private Map nodeSerializerMap = Maps.newHashMap(); === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java 2014-06-03 08:19:42 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java 2014-06-06 07:40:49 +0000 @@ -64,18 +64,13 @@ if ( schema.getProperties().isEmpty() ) { - schema.setPropertyMap( propertyIntrospectorService.getPropertiesMap( schema.getKlass() ) ); + schema.setPropertyMap( Maps.newHashMap( propertyIntrospectorService.getPropertiesMap( schema.getKlass() ) ) ); } classSchemaMap.put( schema.getKlass(), schema ); singularSchemaMap.put( schema.getSingular(), schema ); - if ( schema.getPropertyMap().containsKey( "__self__" ) ) - { - Property property = schema.getPropertyMap().get( "__self__" ); - schema.setName( property.getName() ); - schema.setNamespaceURI( property.getNamespaceURI() ); - } + updateSelf( schema ); } } @@ -115,7 +110,9 @@ klass = ReflectionUtils.getRealClass( klass ); schema = new Schema( klass, klass.getName(), klass.getName() ); - schema.setPropertyMap( propertyIntrospectorService.getPropertiesMap( schema.getKlass() ) ); + schema.setPropertyMap( Maps.newHashMap( propertyIntrospectorService.getPropertiesMap( schema.getKlass() ) ) ); + + updateSelf( schema ); return schema; } @@ -153,4 +150,16 @@ return schemas; } + + private void updateSelf( Schema schema ) + { + if ( schema.getPropertyMap().containsKey( "__self__" ) ) + { + Property property = schema.getPropertyMap().get( "__self__" ); + schema.setName( property.getName() ); + schema.setNamespaceURI( property.getNamespaceURI() ); + + schema.getPropertyMap().remove( "__self__" ); + } + } } === modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java 2014-06-05 11:11:33 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java 2014-06-06 07:40:49 +0000 @@ -31,6 +31,7 @@ import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.dxf2.filter.ops.Op; import org.hisp.dhis.node.types.CollectionNode; @@ -58,7 +59,7 @@ private SchemaService schemaService; @Override - public List filterObjects( List objects, List filters ) + public List objectFilter( List objects, List filters ) { if ( objects == null || objects.isEmpty() ) { @@ -81,45 +82,34 @@ } @Override - public CollectionNode filterProperties( Class klass, List objects, - List includes, List excludes ) + public CollectionNode fieldFilter( Class klass, List objects, + List fieldList ) { - String include = includes == null ? "" : Joiner.on( "," ).join( includes ); - String exclude = excludes == null ? "" : Joiner.on( "," ).join( excludes ); + String fields = fieldList == null ? "" : Joiner.on( "," ).join( fieldList ); Schema rootSchema = schemaService.getDynamicSchema( klass ); - CollectionNode collectionNode = new CollectionNode( rootSchema.getPlural() ); // replace with 'xml' collection name - - if ( objects.isEmpty() ) - { - return collectionNode; - } Map fieldMap = Maps.newHashMap(); Schema schema = schemaService.getDynamicSchema( objects.get( 0 ).getClass() ); - if ( include == null && exclude == null ) + if ( fields == null ) { for ( Property property : schema.getProperties() ) { fieldMap.put( property.getName(), Maps.newHashMap() ); } } - else if ( include != null ) - { - fieldMap = parserService.parsePropertyFilter( include ); - } else { - Map excludeMap = parserService.parsePropertyFilter( exclude ); - - for ( Property property : schema.getProperties() ) - { - if ( !excludeMap.containsKey( property.getName() ) ) - { - fieldMap.put( property.getName(), Maps.newHashMap() ); - } - } + fieldMap = parserService.parsePropertyFilter( fields ); + } + + CollectionNode collectionNode = new CollectionNode( rootSchema.getPlural() ); // replace with 'xml' collection name + collectionNode.setNamespace( rootSchema.getNamespaceURI() ); + + if ( objects.isEmpty() ) + { + return collectionNode; } for ( Object object : objects ) @@ -139,7 +129,10 @@ } Schema schema = schemaService.getDynamicSchema( object.getClass() ); - ComplexNode complexNode = new ComplexNode( schema.getSingular() ); + ComplexNode complexNode = new ComplexNode( schema.getName() ); + complexNode.setNamespace( schema.getNamespaceURI() ); + + updateFields( fieldMap, object ); for ( String fieldKey : fieldMap.keySet() ) { @@ -150,6 +143,7 @@ Property property = schema.getPropertyMap().get( fieldKey ); Object returnValue = ReflectionUtils.invokeMethod( object, property.getGetterMethod() ); + Schema propertySchema = schemaService.getDynamicSchema( property.getKlass() ); if ( returnValue == null ) { @@ -162,15 +156,26 @@ { if ( !property.isIdentifiableObject() ) { - complexNode.addChild( new SimpleNode( fieldKey, returnValue ) ); + if ( propertySchema.getProperties().isEmpty() ) + { + SimpleNode simpleNode = new SimpleNode( fieldKey, returnValue ); + simpleNode.setAttribute( property.isAttribute() ); + simpleNode.setNamespace( property.getNamespaceURI() ); + + complexNode.addChild( simpleNode ); + } + else + { + complexNode.addChild( buildObjectOutput( getFullFieldMap( propertySchema ), returnValue ) ); + } } else if ( !property.isCollection() ) { - complexNode.addChild( getIdentifiableObjectProperties( returnValue, IDENTIFIABLE_PROPERTIES ) ); + complexNode.addChild( getProperties( returnValue, FilterService.FIELD_PRESETS.get( "identifiable" ) ) ); } else { - complexNode.addChild( getIdentifiableObjectCollectionProperties( returnValue, IDENTIFIABLE_PROPERTIES, fieldKey ) ); + complexNode.addChild( getCollectionProperties( returnValue, FilterService.FIELD_PRESETS.get( "identifiable" ), property ) ); } } else @@ -178,6 +183,7 @@ if ( property.isCollection() ) { CollectionNode collectionNode = complexNode.addChild( new CollectionNode( property.getCollectionName() ) ); + collectionNode.setNamespace( property.getNamespaceURI() ); for ( Object collectionObject : (Collection) returnValue ) { @@ -204,8 +210,74 @@ return complexNode; } + private void updateFields( Map fieldMap, Object object ) + { + // we need two run this (at least) two times, since some of the presets might contain other presets + _updateFields( fieldMap, object ); + _updateFields( fieldMap, object ); + } + + private void _updateFields( Map fieldMap, Object object ) + { + Schema schema = schemaService.getDynamicSchema( object.getClass() ); + + List cleanupFields = Lists.newArrayList(); + + for ( String fieldKey : Sets.newHashSet( fieldMap.keySet() ) ) + { + if ( fieldKey.equals( "*" ) ) + { + for ( String mapKey : schema.getPropertyMap().keySet() ) + { + if ( !fieldMap.containsKey( mapKey ) ) + { + fieldMap.put( mapKey, Maps.newHashMap() ); + } + } + + cleanupFields.add( fieldKey ); + } + else if ( fieldKey.startsWith( ":" ) ) + { + List fields = FilterService.FIELD_PRESETS.get( fieldKey.substring( 1 ) ); + + for ( String field : fields ) + { + if ( !fieldMap.containsKey( field ) ) + { + fieldMap.put( field, Maps.newHashMap() ); + } + } + + cleanupFields.add( fieldKey ); + } + else if ( fieldKey.startsWith( "!" ) ) + { + cleanupFields.add( fieldKey ); + } + } + + for ( String ignore : cleanupFields ) + { + fieldMap.remove( ignore ); + fieldMap.remove( ignore.substring( 1 ) ); + } + } + + private Map getFullFieldMap( Schema schema ) + { + Map map = Maps.newHashMap(); + + for ( String mapKey : schema.getPropertyMap().keySet() ) + { + map.put( mapKey, Maps.newHashMap() ); + } + + return map; + } + @SuppressWarnings( "unchecked" ) - private CollectionNode getIdentifiableObjectCollectionProperties( Object object, List fields, String collectionName ) + private CollectionNode getCollectionProperties( Object object, List fields, Property property ) { if ( object == null ) { @@ -217,42 +289,30 @@ return null; } - CollectionNode collectionNode = new CollectionNode( collectionName ); - Collection identifiableObjects; - - try - { - identifiableObjects = (Collection) object; - } - catch ( ClassCastException ex ) - { - ex.printStackTrace(); - return collectionNode; - } - - for ( IdentifiableObject identifiableObject : identifiableObjects ) - { - collectionNode.addChild( getIdentifiableObjectProperties( identifiableObject, fields ) ); + CollectionNode collectionNode = new CollectionNode( property.getCollectionName() ); + collectionNode.setNamespace( property.getNamespaceURI() ); + + Collection collection = (Collection) object; + + for ( Object collectionObject : collection ) + { + collectionNode.addChild( getProperties( collectionObject, fields ) ); } return collectionNode; } - private ComplexNode getIdentifiableObjectProperties( Object object, List fields ) + private ComplexNode getProperties( Object object, List fields ) { if ( object == null ) { return null; } - if ( !IdentifiableObject.class.isInstance( object ) ) - { - return null; - } - Schema schema = schemaService.getDynamicSchema( object.getClass() ); ComplexNode complexNode = new ComplexNode( schema.getSingular() ); + complexNode.setNamespace( schema.getNamespaceURI() ); for ( String field : fields ) { @@ -267,7 +327,11 @@ if ( o != null ) { - complexNode.addChild( new SimpleNode( field, o ) ); + SimpleNode simpleNode = new SimpleNode( field, o ); + simpleNode.setAttribute( property.isAttribute() ); + simpleNode.setNamespace( property.getNamespaceURI() ); + + complexNode.addChild( simpleNode ); } } === modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultParserService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultParserService.java 2014-04-14 06:43:16 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultParserService.java 2014-06-06 07:40:49 +0000 @@ -103,7 +103,7 @@ continue; } - if ( StringUtils.isAlpha( c ) ) + if ( StringUtils.isAlpha( c ) || c.equals( "*" ) || c.equals( ":" ) || c.equals( "!" ) ) { builder.append( c ); } @@ -124,9 +124,14 @@ return prefixes; } - @SuppressWarnings( "unchecked" ) + @SuppressWarnings("unchecked") private void putInMap( Map map, String path ) { + if ( StringUtils.isEmpty( path ) ) + { + return; + } + for ( String p : path.split( "\\." ) ) { if ( map.get( p ) == null ) === modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/FilterService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/FilterService.java 2014-06-05 11:11:33 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/FilterService.java 2014-06-06 07:40:49 +0000 @@ -28,6 +28,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.node.types.CollectionNode; @@ -39,8 +40,11 @@ */ public interface FilterService { - static final List IDENTIFIABLE_PROPERTIES = - Lists.newArrayList( "id", "name", "code", "created", "lastUpdated" ); + static final ImmutableMap> FIELD_PRESETS = ImmutableMap.>builder() + .put( "all", Lists.newArrayList( "*" ) ) + .put( "identifiable", Lists.newArrayList( "id", "name", "code", "created", "lastUpdated" ) ) + .put( "nameable", Lists.newArrayList( "id", "name", "shortName", "description", "code", "created", "lastUpdated" ) ) + .build(); /** * Filter a list of objects based on un-parsed filter string. @@ -49,16 +53,15 @@ * @param filters Filter string * @return Filtered object list */ - List filterObjects( List objects, List filters ); + List objectFilter( List objects, List filters ); /** * Perform inclusion/exclusion on a list of objects. * - * @param objects List to filter - * @param include Inclusion filter - * @param exclude Exclusion filter + * @param objects List to filter + * @param fieldList Field filter * @return List of objects with only wanted properties */ - CollectionNode filterProperties( Class klass, List objects, - List include, List exclude ); + CollectionNode fieldFilter( Class klass, List objects, + List fieldList ); } === modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/Options.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/Options.java 2014-03-25 10:24:56 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/Options.java 2014-06-06 07:40:49 +0000 @@ -60,7 +60,7 @@ return null; } - String patterns[] = new String[] { + String patterns[] = new String[]{ "yyyy-MM-dd", "yyyy-MM", "yyyyMMdd", @@ -88,7 +88,8 @@ try { return new SimpleDateFormat( pattern ).parse( str ); - } catch ( ParseException ignored ) + } + catch ( ParseException ignored ) { } } @@ -131,7 +132,7 @@ try { return Integer.parseInt( str ); - } + } catch ( NumberFormatException ignored ) { } @@ -183,6 +184,17 @@ return !isEnabled( type ); } + public boolean booleanTrue( String key ) + { + return booleanTrue( key, false ); + } + + public boolean booleanTrue( String key, boolean defaultValue ) + { + String value = options.get( key ); + return stringAsBoolean( value, defaultValue ); + } + public Date getDate( String key ) { return stringAsDate( options.get( key ) ); @@ -224,15 +236,15 @@ //-------------------------------------------------------------------------- // Adding options //-------------------------------------------------------------------------- - - public void addOption(String option, String value) + + public void addOption( String option, String value ) { - options.put( option, value); + options.put( option, value ); } - - public void addOptions(Map newOptions) + + public void addOptions( Map newOptions ) { options.putAll( options ); } - + } === modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java' --- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java 2014-06-02 22:47:30 +0000 +++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java 2014-06-06 07:40:49 +0000 @@ -402,6 +402,11 @@ @SuppressWarnings("unchecked") public static T invokeMethod( Object target, Method method, Object... args ) { + if ( target == null || method == null ) + { + return null; + } + if ( Modifier.isProtected( method.getModifiers() ) || Modifier.isPrivate( method.getModifiers() ) ) { return null; @@ -421,7 +426,7 @@ } } - @SuppressWarnings("unchecked") + @SuppressWarnings( "unchecked" ) public static T getFieldObject( Field field, T target ) { return (T) invokeGetterMethod( field.getName(), target ); === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java 2014-06-05 11:11:33 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java 2014-06-06 07:40:49 +0000 @@ -32,6 +32,7 @@ import org.hisp.dhis.acl.Access; import org.hisp.dhis.acl.AclService; import org.hisp.dhis.common.BaseIdentifiableObject; +import org.hisp.dhis.common.DxfNamespaces; import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.common.IdentifiableObjectManager; import org.hisp.dhis.common.Pager; @@ -45,11 +46,12 @@ import org.hisp.dhis.hibernate.exception.DeleteAccessDeniedException; import org.hisp.dhis.hibernate.exception.UpdateAccessDeniedException; import org.hisp.dhis.importexport.ImportStrategy; +import org.hisp.dhis.node.types.CollectionNode; import org.hisp.dhis.node.types.ComplexNode; import org.hisp.dhis.node.types.RootNode; import org.hisp.dhis.node.types.SimpleNode; +import org.hisp.dhis.schema.Schema; import org.hisp.dhis.schema.SchemaService; -import org.hisp.dhis.system.util.ReflectionUtils; import org.hisp.dhis.user.CurrentUserService; import org.hisp.dhis.webapi.controller.exception.NotFoundException; import org.hisp.dhis.webapi.utils.ContextService; @@ -59,7 +61,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.ui.Model; -import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -69,10 +70,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; import java.io.InputStream; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -81,8 +82,6 @@ */ public abstract class AbstractCrudController { - private static final List DEFAULT_LIST_INCLUDES = Lists.newArrayList( FilterService.IDENTIFIABLE_PROPERTIES ); - //-------------------------------------------------------------------------- // Dependencies //-------------------------------------------------------------------------- @@ -119,41 +118,18 @@ //-------------------------------------------------------------------------- @RequestMapping( method = RequestMethod.GET ) - public String getObjectList( + public @ResponseBody RootNode getObjectList( @RequestParam Map parameters, Model model, HttpServletResponse response, HttpServletRequest request ) { - WebOptions options = new WebOptions( parameters ); - WebMetaData metaData = new WebMetaData(); - List entityList = getEntityList( metaData, options ); - String viewClass = options.getViewClass( "basic" ); - - postProcessEntities( entityList ); - postProcessEntities( entityList, options, parameters ); - - ReflectionUtils.invokeSetterMethod( schemaService.getSchema( getEntityClass() ).getPlural(), metaData, entityList ); - - handleLinksAndAccess( options, metaData, entityList ); - - model.addAttribute( "model", metaData ); - model.addAttribute( "viewClass", viewClass ); - - return StringUtils.uncapitalize( getEntitySimpleName() ) + "List"; - } - - @RequestMapping( method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE } ) - public @ResponseBody RootNode getObjectListJson( - @RequestParam Map parameters, Model model, HttpServletResponse response, HttpServletRequest request ) throws IOException - { - List includes = Lists.newArrayList( contextService.getParameterValues( "include" ) ); - List excludes = Lists.newArrayList( contextService.getParameterValues( "exclude" ) ); + List fields = Lists.newArrayList( contextService.getParameterValues( "fields" ) ); List filters = Lists.newArrayList( contextService.getParameterValues( "filter" ) ); WebOptions options = new WebOptions( parameters ); WebMetaData metaData = new WebMetaData(); - if ( includes.isEmpty() && excludes.isEmpty() ) + if ( fields.isEmpty() ) { - includes = DEFAULT_LIST_INCLUDES; + fields = FilterService.FIELD_PRESETS.get( "identifiable" ); } boolean hasPaging = options.hasPaging(); @@ -176,7 +152,7 @@ // enable object filter if ( !filters.isEmpty() ) { - entityList = filterService.filterObjects( entityList, filters ); + entityList = filterService.objectFilter( entityList, filters ); if ( hasPaging ) { @@ -188,7 +164,7 @@ postProcessEntities( entityList ); postProcessEntities( entityList, options, parameters ); - if ( includes != null && includes.contains( "access" ) ) + if ( fields != null && fields.contains( "access" ) ) { options.getOptions().put( "viewClass", "sharing" ); } @@ -196,6 +172,8 @@ handleLinksAndAccess( options, metaData, entityList ); RootNode rootNode = new RootNode( "metadata" ); + rootNode.setDefaultNamespace( DxfNamespaces.DXF_2_0 ); + rootNode.setNamespace( DxfNamespaces.DXF_2_0 ); if ( pager != null ) { @@ -207,16 +185,23 @@ pagerNode.addChild( new SimpleNode( "prevPage", pager.getPrevPage() ) ); } - rootNode.addChild( filterService.filterProperties( getEntityClass(), entityList, includes, excludes ) ); + rootNode.addChild( filterService.fieldFilter( getEntityClass(), entityList, fields ) ); return rootNode; } @RequestMapping( value = "/{uid}", method = RequestMethod.GET ) - public String getObject( @PathVariable( "uid" ) String uid, @RequestParam Map parameters, + public @ResponseBody RootNode getObject( @PathVariable( "uid" ) String uid, @RequestParam Map parameters, Model model, HttpServletRequest request, HttpServletResponse response ) throws Exception { + List fields = Lists.newArrayList( contextService.getParameterValues( "fields" ) ); + + if ( fields.isEmpty() ) + { + fields.add( "*" ); + } + WebOptions options = new WebOptions( parameters ); T entity = getEntity( uid ); @@ -238,10 +223,27 @@ postProcessEntity( entity ); postProcessEntity( entity, options, parameters ); - model.addAttribute( "model", entity ); - model.addAttribute( "viewClass", options.getViewClass( "detailed" ) ); - - return StringUtils.uncapitalize( getEntitySimpleName() ); + List objects = new ArrayList<>(); + objects.add( entity ); + + CollectionNode collectionNode = filterService.fieldFilter( getEntityClass(), objects, fields ); + + if ( options.booleanTrue( "useWrapper" ) ) + { + RootNode rootNode = new RootNode( "metadata" ); + rootNode.setDefaultNamespace( DxfNamespaces.DXF_2_0 ); + rootNode.setNamespace( DxfNamespaces.DXF_2_0 ); + rootNode.addChild( collectionNode ); + + return rootNode; + } + else + { + RootNode rootNode = new RootNode( collectionNode.getChildren().get( 0 ) ); + rootNode.setDefaultNamespace( DxfNamespaces.DXF_2_0 ); + + return rootNode; + } } //-------------------------------------------------------------------------- @@ -421,6 +423,11 @@ return manager.getNoAcl( getEntityClass(), uid ); //TODO consider ACL } + protected Schema getSchema() + { + return schemaService.getDynamicSchema( getEntityClass() ); + } + protected void addAccessProperties( T object ) { Access access = new Access(); === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/organisationunit/OrganisationUnitController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/organisationunit/OrganisationUnitController.java 2014-05-27 13:18:27 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/organisationunit/OrganisationUnitController.java 2014-06-06 07:40:49 +0000 @@ -30,6 +30,7 @@ import org.hisp.dhis.common.Pager; import org.hisp.dhis.dxf2.metadata.MetaData; +import org.hisp.dhis.node.types.RootNode; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.organisationunit.OrganisationUnitService; import org.hisp.dhis.organisationunit.comparator.OrganisationUnitByLevelComparator; @@ -172,9 +173,11 @@ return entityList; } + + /* TODO can this be replaced by inclusion/filter? @Override @RequestMapping( value = "/{uid}", method = RequestMethod.GET ) - public String getObject( @PathVariable( "uid" ) String uid, @RequestParam Map parameters, + public RootNode getObject( @PathVariable( "uid" ) String uid, @RequestParam Map parameters, Model model, HttpServletRequest request, HttpServletResponse response ) throws Exception { WebOptions options = new WebOptions( parameters ); @@ -261,5 +264,5 @@ return StringUtils.uncapitalize( getEntitySimpleName() ); } - + */ } === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java 2014-05-28 16:38:44 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java 2014-06-06 07:40:49 +0000 @@ -35,6 +35,7 @@ import org.hisp.dhis.hibernate.exception.CreateAccessDeniedException; import org.hisp.dhis.hibernate.exception.UpdateAccessDeniedException; import org.hisp.dhis.importexport.ImportStrategy; +import org.hisp.dhis.node.types.RootNode; import org.hisp.dhis.schema.descriptors.UserSchemaDescriptor; import org.hisp.dhis.security.PasswordManager; import org.hisp.dhis.security.RestoreOptions; @@ -95,14 +96,14 @@ @Override @PreAuthorize( "hasRole('ALL') or hasRole('F_USER_VIEW')" ) - public String getObjectList( @RequestParam Map parameters, Model model, HttpServletResponse response, HttpServletRequest request ) + public RootNode getObjectList( @RequestParam Map parameters, Model model, HttpServletResponse response, HttpServletRequest request ) { return super.getObjectList( parameters, model, response, request ); } @Override @PreAuthorize( "hasRole('ALL') or hasRole('F_USER_VIEW')" ) - public String getObject( @PathVariable( "uid" ) String uid, @RequestParam Map parameters, Model model, + public RootNode getObject( @PathVariable( "uid" ) String uid, @RequestParam Map parameters, Model model, HttpServletRequest request, HttpServletResponse response ) throws Exception { return super.getObject( uid, parameters, model, request, response );