← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 11478: Added new dashboard data model and persistence/service layer. Introduced classes Dashboard and Da...

 

------------------------------------------------------------
revno: 11478
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2013-07-22 23:08:05 +0200
message:
  Added new dashboard data model and persistence/service layer. Introduced classes Dashboard and DashboardItem. Allows for multiple dashboards per user.
added:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/Dashboard.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/DashboardItem.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/dashboard/hibernate/Dashboard.hbm.xml
  dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/dashboard/hibernate/DashboardItem.hbm.xml
  dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/dashboard/DashboardServiceTest.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/DashboardService.java
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/ExchangeClasses.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/dashboard/impl/DefaultDashboardService.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DashboardController.java
  dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/webapp/dhis-web-dashboard-integration/javascript/dashboard.js


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/Dashboard.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/Dashboard.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/Dashboard.java	2013-07-22 21:08:05 +0000
@@ -0,0 +1,66 @@
+package org.hisp.dhis.dashboard;
+
+/*
+ * Copyright (c) 2004-2012, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hisp.dhis.common.BaseIdentifiableObject;
+
+public class Dashboard
+    extends BaseIdentifiableObject
+{
+    private List<DashboardItem> items = new ArrayList<DashboardItem>();
+
+    // -------------------------------------------------------------------------
+    // Constructors
+    // -------------------------------------------------------------------------
+
+    public Dashboard()
+    {
+    }
+    
+    public Dashboard( String name )
+    {
+        this.name = name;
+    }
+
+    // -------------------------------------------------------------------------
+    // Getters and setters
+    // -------------------------------------------------------------------------
+
+    public List<DashboardItem> getItems()
+    {
+        return items;
+    }
+
+    public void setItems( List<DashboardItem> items )
+    {
+        this.items = items;
+    }
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/DashboardItem.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/DashboardItem.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/DashboardItem.java	2013-07-22 21:08:05 +0000
@@ -0,0 +1,188 @@
+package org.hisp.dhis.dashboard;
+
+/*
+ * Copyright (c) 2004-2012, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hisp.dhis.chart.Chart;
+import org.hisp.dhis.common.BaseIdentifiableObject;
+import org.hisp.dhis.common.DxfNamespaces;
+import org.hisp.dhis.document.Document;
+import org.hisp.dhis.mapping.Map;
+import org.hisp.dhis.report.Report;
+import org.hisp.dhis.reporttable.ReportTable;
+import org.hisp.dhis.user.User;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+
+public class DashboardItem
+    extends BaseIdentifiableObject
+{
+    private Chart chart;
+    
+    private Map map;
+    
+    private List<User> users = new ArrayList<User>();
+    
+    private List<ReportTable> reportTables = new ArrayList<ReportTable>();
+    
+    private List<Report> reports = new ArrayList<Report>();
+
+    private List<Document> resources = new ArrayList<Document>();
+
+    // -------------------------------------------------------------------------
+    // Constructors
+    // -------------------------------------------------------------------------
+
+    public DashboardItem()
+    {
+    }
+
+    // -------------------------------------------------------------------------
+    // Logic
+    // -------------------------------------------------------------------------
+
+    @JsonProperty
+    public String getType()
+    {
+        if ( chart != null )
+        {
+            return "chart";
+        }
+        else if ( map != null )
+        {
+            return "map";
+        }
+        else if ( !users.isEmpty() )
+        {
+            return "users";
+        }
+        else if ( !reportTables.isEmpty() )
+        {
+            return "reportTables";
+        }
+        else if ( !reports.isEmpty() )
+        {
+            return "reports";
+        }
+        else if ( !resources.isEmpty() )
+        {
+            return "resources";
+        }
+        
+        return null;
+    }
+    
+    // -------------------------------------------------------------------------
+    // Getters and setters
+    // -------------------------------------------------------------------------
+
+    @JsonProperty
+    @JsonSerialize( contentAs = BaseIdentifiableObject.class )
+    public Chart getChart()
+    {
+        return chart;
+    }
+
+    public void setChart( Chart chart )
+    {
+        this.chart = chart;
+    }
+    
+    @JsonProperty
+    @JsonSerialize( contentAs = BaseIdentifiableObject.class )
+    public Map getMap()
+    {
+        return map;
+    }
+
+    public void setMap( Map map )
+    {
+        this.map = map;
+    }
+
+    @JsonProperty( value = "users" )
+    @JsonSerialize( contentAs = BaseIdentifiableObject.class )
+    @JacksonXmlElementWrapper( localName = "users", namespace = DxfNamespaces.DXF_2_0)
+    @JacksonXmlProperty( localName = "user", namespace = DxfNamespaces.DXF_2_0)
+    public List<User> getUsers()
+    {
+        return users;
+    }
+
+    public void setUsers( List<User> users )
+    {
+        this.users = users;
+    }
+
+    @JsonProperty( value = "reportTables" )
+    @JsonSerialize( contentAs = BaseIdentifiableObject.class )
+    @JacksonXmlElementWrapper( localName = "reportTables", namespace = DxfNamespaces.DXF_2_0)
+    @JacksonXmlProperty( localName = "reportTable", namespace = DxfNamespaces.DXF_2_0)
+    public List<ReportTable> getReportTables()
+    {
+        return reportTables;
+    }
+
+    public void setReportTables( List<ReportTable> reportTables )
+    {
+        this.reportTables = reportTables;
+    }
+
+    @JsonProperty( value = "reports" )
+    @JsonSerialize( contentAs = BaseIdentifiableObject.class )
+    @JacksonXmlElementWrapper( localName = "reports", namespace = DxfNamespaces.DXF_2_0)
+    @JacksonXmlProperty( localName = "report", namespace = DxfNamespaces.DXF_2_0)
+    public List<Report> getReports()
+    {
+        return reports;
+    }
+
+    public void setReports( List<Report> reports )
+    {
+        this.reports = reports;
+    }
+
+    @JsonProperty( value = "resources" )
+    @JsonSerialize( contentAs = BaseIdentifiableObject.class )
+    @JacksonXmlElementWrapper( localName = "resources", namespace = DxfNamespaces.DXF_2_0)
+    @JacksonXmlProperty( localName = "resource", namespace = DxfNamespaces.DXF_2_0)
+    public List<Document> getResources()
+    {
+        return resources;
+    }
+
+    public void setResources( List<Document> resources )
+    {
+        this.resources = resources;
+    }
+}

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/DashboardService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/DashboardService.java	2013-07-22 17:46:51 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dashboard/DashboardService.java	2013-07-22 21:08:05 +0000
@@ -1,5 +1,9 @@
 package org.hisp.dhis.dashboard;
 
+import java.util.List;
+
+import org.hisp.dhis.user.User;
+
 /*
  * Copyright (c) 2004-2012, University of Oslo
  * All rights reserved.
@@ -36,4 +40,16 @@
     final String ID = DashboardService.class.getName();
 
     DashboardSearchResult search( String query );
+    
+    int saveDashboard( Dashboard dashboard );
+    
+    void updateDashboard( Dashboard dashboard );
+    
+    void deleteDashboard( Dashboard dashboard );
+    
+    Dashboard getDashboard( int id );
+    
+    Dashboard getDashboard( String uid );
+    
+    List<Dashboard> getByUser( User user );
 }

=== modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/ExchangeClasses.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/ExchangeClasses.java	2013-05-31 04:06:10 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/ExchangeClasses.java	2013-07-22 21:08:05 +0000
@@ -27,12 +27,20 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.hisp.dhis.attribute.Attribute;
 import org.hisp.dhis.chart.Chart;
 import org.hisp.dhis.common.BaseDimensionalObject;
 import org.hisp.dhis.common.IdentifiableObject;
 import org.hisp.dhis.concept.Concept;
 import org.hisp.dhis.constant.Constant;
+import org.hisp.dhis.dashboard.Dashboard;
+import org.hisp.dhis.dashboard.DashboardItem;
 import org.hisp.dhis.datadictionary.DataDictionary;
 import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataelement.DataElementCategory;
@@ -71,12 +79,6 @@
 import org.hisp.dhis.validation.ValidationRule;
 import org.hisp.dhis.validation.ValidationRuleGroup;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
@@ -138,6 +140,9 @@
         allExportClasses.put( ReportTable.class, "reportTables" );
         allExportClasses.put( Report.class, "reports" );
         allExportClasses.put( Chart.class, "charts" );
+        
+        allExportClasses.put( Dashboard.class, "dashboards" );
+        allExportClasses.put( DashboardItem.class, "dashboardItems" );
 
         allExportClasses.put( ValidationRule.class, "validationRules" );
         allExportClasses.put( ValidationRuleGroup.class, "validationRuleGroups" );

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/dashboard/impl/DefaultDashboardService.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/dashboard/impl/DefaultDashboardService.java	2013-07-22 17:46:51 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/dashboard/impl/DefaultDashboardService.java	2013-07-22 21:08:05 +0000
@@ -27,20 +27,16 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import java.util.Collection;
+import java.util.List;
 
 import org.hisp.dhis.chart.ChartService;
-import org.hisp.dhis.dashboard.DashboardContent;
-import org.hisp.dhis.dashboard.DashboardContentStore;
+import org.hisp.dhis.common.hibernate.HibernateIdentifiableObjectStore;
+import org.hisp.dhis.dashboard.Dashboard;
 import org.hisp.dhis.dashboard.DashboardSearchResult;
 import org.hisp.dhis.dashboard.DashboardService;
-import org.hisp.dhis.document.Document;
 import org.hisp.dhis.document.DocumentService;
-import org.hisp.dhis.mapping.Map;
 import org.hisp.dhis.mapping.MappingService;
-import org.hisp.dhis.report.Report;
 import org.hisp.dhis.report.ReportService;
-import org.hisp.dhis.reporttable.ReportTable;
 import org.hisp.dhis.reporttable.ReportTableService;
 import org.hisp.dhis.user.User;
 import org.hisp.dhis.user.UserService;
@@ -61,6 +57,13 @@
     // Dependencies
     // -------------------------------------------------------------------------
 
+    private HibernateIdentifiableObjectStore<Dashboard> dashboardStore;
+    
+    public void setDashboardStore( HibernateIdentifiableObjectStore<Dashboard> dashboardStore )
+    {
+        this.dashboardStore = dashboardStore;
+    }
+
     private UserService userService;
     
     public void setUserService( UserService userService )
@@ -107,6 +110,7 @@
     // DashboardService implementation
     // -------------------------------------------------------------------------
 
+    @Override
     public DashboardSearchResult search( String query )
     {
         DashboardSearchResult result = new DashboardSearchResult();
@@ -120,5 +124,40 @@
         
         return result;
     }
-    
+
+    @Override
+    public int saveDashboard( Dashboard dashboard )
+    {
+        return dashboardStore.save( dashboard );
+    }
+
+    @Override
+    public void updateDashboard( Dashboard dashboard )
+    {
+        dashboardStore.update( dashboard );
+    }
+
+    @Override
+    public void deleteDashboard( Dashboard dashboard )
+    {
+        dashboardStore.delete( dashboard );
+    }
+
+    @Override
+    public Dashboard getDashboard( int id )
+    {
+        return dashboardStore.get( id );
+    }
+
+    @Override
+    public Dashboard getDashboard( String uid )
+    {
+        return dashboardStore.getByUid( uid );
+    }
+
+    @Override
+    public List<Dashboard> getByUser( User user )
+    {
+        return dashboardStore.getByUser( user );
+    }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml	2013-07-22 17:46:51 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml	2013-07-22 21:08:05 +0000
@@ -125,6 +125,12 @@
   
   <!-- Dashboard -->
 
+  <bean id="org.hisp.dhis.dashboard.DashboardStore" class="org.hisp.dhis.common.hibernate.HibernateIdentifiableObjectStore">
+    <property name="clazz" value="org.hisp.dhis.dashboard.Dashboard" />
+    <property name="sessionFactory" ref="sessionFactory" />
+    <property name="cacheable" value="true" />
+  </bean>
+
   <bean id="org.hisp.dhis.dashboard.DashboardContentStore" class="org.hisp.dhis.dashboard.hibernate.HibernateDashboardContentStore">
     <property name="clazz" value="org.hisp.dhis.dashboard.DashboardContent" />
     <property name="sessionFactory" ref="sessionFactory" />
@@ -133,6 +139,7 @@
   </bean>
 
   <bean id="org.hisp.dhis.dashboard.DashboardService" class="org.hisp.dhis.dashboard.impl.DefaultDashboardService">
+    <property name="dashboardStore" ref="org.hisp.dhis.dashboard.DashboardStore" />
     <property name="userService" ref="org.hisp.dhis.user.UserService" />
     <property name="chartService" ref="org.hisp.dhis.chart.ChartService" />
     <property name="mappingService" ref="org.hisp.dhis.mapping.MappingService" />

=== added file 'dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/dashboard/hibernate/Dashboard.hbm.xml'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/dashboard/hibernate/Dashboard.hbm.xml	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/dashboard/hibernate/Dashboard.hbm.xml	2013-07-22 21:08:05 +0000
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+  "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd";
+  [<!ENTITY identifiableProperties SYSTEM "classpath://org/hisp/dhis/common/identifiableProperties.hbm">]
+  >
+
+<hibernate-mapping>
+  <class name="org.hisp.dhis.dashboard.Dashboard" table="dashboard">
+
+    <cache usage="read-write" />
+
+    <id name="id" column="dashboardid">
+      <generator class="native" />
+    </id>
+    &identifiableProperties;
+
+    <property name="name" column="name" not-null="true" unique="false" length="230" />
+    
+    <list name="items" table="dashboard_items" cascade="all-delete-orphan">
+      <key column="dashboardid" foreign-key="fk_dashboard_items_dashboardid" />
+      <list-index column="sort_order" base="0" />
+      <many-to-many column="dashboarditemid" class="org.hisp.dhis.dashboard.DashboardItem" foreign-key="fk_dashboard_items_dashboarditemid" />
+    </list>
+
+  </class>
+</hibernate-mapping>
\ No newline at end of file

=== added file 'dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/dashboard/hibernate/DashboardItem.hbm.xml'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/dashboard/hibernate/DashboardItem.hbm.xml	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/dashboard/hibernate/DashboardItem.hbm.xml	2013-07-22 21:08:05 +0000
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+  "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd";
+  [<!ENTITY identifiableProperties SYSTEM "classpath://org/hisp/dhis/common/identifiableProperties.hbm">]
+  >
+
+<hibernate-mapping>
+  <class name="org.hisp.dhis.dashboard.DashboardItem" table="dashboarditem">
+
+    <cache usage="read-write" />
+
+    <id name="id" column="dashboarditemid">
+      <generator class="native" />
+    </id>
+    &identifiableProperties;
+
+    <many-to-one name="chart" class="org.hisp.dhis.chart.Chart" column="chartid" foreign-key="fk_dashboarditem_chartid" />
+    
+    <many-to-one name="map" class="org.hisp.dhis.mapping.Map" column="mapid" foreign-key="fk_dashboarditem_mapid" />
+    
+    <list name="users" table="dashboarditem_users">
+      <key column="dashboarditemid" foreign-key="fk_dashboarditem_users_dashboardid" />
+      <list-index column="sort_order" base="0" />
+      <many-to-many column="userid" class="org.hisp.dhis.user.User" foreign-key="fk_dashboarditem_users_userinfoid" />
+    </list>
+    
+    <list name="reportTables" table="dashboarditem_reporttables">
+      <key column="dashboarditemid" foreign-key="fk_dashboarditem_reporttables_dashboardid" />
+      <list-index column="sort_order" base="0" />
+      <many-to-many column="reporttableid" class="org.hisp.dhis.reporttable.ReportTable" foreign-key="fk_dashboarditem_reporttables_reporttableid" />
+    </list>    
+    
+    <list name="reports" table="dashboarditem_reports">
+      <key column="dashboarditemid" foreign-key="fk_dashboarditem_reports_dashboardid" />
+      <list-index column="sort_order" base="0" />
+      <many-to-many column="reportid" class="org.hisp.dhis.report.Report" foreign-key="fk_dashboarditem_reports_reportid" />
+    </list>
+
+    <list name="resources" table="dashboarditem_resources">
+      <key column="dashboarditemid" foreign-key="fk_dashboarditem_resources_dashboardid" />
+      <list-index column="sort_order" base="0" />
+      <many-to-many column="resourceid" class="org.hisp.dhis.document.Document" foreign-key="fk_dashboarditem_resources_documentid" />
+    </list>
+
+  </class>
+</hibernate-mapping>
\ No newline at end of file

=== added file 'dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/dashboard/DashboardServiceTest.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/dashboard/DashboardServiceTest.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/dashboard/DashboardServiceTest.java	2013-07-22 21:08:05 +0000
@@ -0,0 +1,148 @@
+package org.hisp.dhis.dashboard;
+
+/*
+ * Copyright (c) 2004-2012, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.hisp.dhis.DhisSpringTest;
+import org.hisp.dhis.chart.Chart;
+import org.hisp.dhis.chart.ChartService;
+import org.hisp.dhis.document.Document;
+import org.hisp.dhis.document.DocumentService;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import static org.junit.Assert.*;
+
+public class DashboardServiceTest
+    extends DhisSpringTest
+{
+    @Autowired
+    private DashboardService dashboardService;
+    
+    @Autowired
+    private ChartService chartService;
+    
+    @Autowired
+    private DocumentService documentService;
+    
+    private Dashboard dA;
+    private Dashboard dB;
+    
+    private DashboardItem diA;
+    private DashboardItem diB;
+    private DashboardItem diC;
+    private DashboardItem diD;
+    
+    @Override
+    public void setUpTest()
+    {
+        Chart chartA = new Chart( "A" );
+        Chart chartB = new Chart( "B" );
+        
+        chartService.addChart( chartA );
+        chartService.addChart( chartB );
+                
+        Document docA = new Document( "A", "url", false, null );
+        Document docB = new Document( "B", "url", false, null );
+        Document docC = new Document( "C", "url", false, null );
+        Document docD = new Document( "D", "url", false, null );
+        
+        documentService.saveDocument( docA );
+        documentService.saveDocument( docB );
+        documentService.saveDocument( docC );
+        documentService.saveDocument( docD );
+        
+        diA = new DashboardItem();
+        diA.setChart( chartA );
+        
+        diB = new DashboardItem();
+        diB.setChart( chartB );
+        
+        diC = new DashboardItem();
+        diC.getResources().add( docA );
+        diC.getResources().add( docB );
+
+        diD = new DashboardItem();
+        diD.getResources().add( docC );
+        diD.getResources().add( docD );
+        
+        dA = new Dashboard( "A" );
+        dA.getItems().add( diA );
+        dA.getItems().add( diB );
+        dA.getItems().add( diC );
+        
+        dB = new Dashboard( "B" );
+        dB.getItems().add( diD );
+    }
+    
+    @Test
+    public void testAddGet()
+    {        
+        int dAId = dashboardService.saveDashboard( dA );
+        int dBId = dashboardService.saveDashboard( dB );
+        
+        assertEquals( dA, dashboardService.getDashboard( dAId ) );
+        assertEquals( dB, dashboardService.getDashboard( dBId ) );
+        
+        assertEquals( 3, dashboardService.getDashboard( dAId ).getItems().size() );
+        assertEquals( 1, dashboardService.getDashboard( dBId ).getItems().size() );
+    }
+
+    @Test
+    public void testUpdate()
+    {
+        int dAId = dashboardService.saveDashboard( dA );
+        
+        assertEquals( "A", dashboardService.getDashboard( dAId ).getName() );
+        
+        dA.setName( "B" );
+        
+        dashboardService.updateDashboard( dA );
+
+        assertEquals( "B", dashboardService.getDashboard( dAId ).getName() );
+    }
+
+    @Test
+    public void testDelete()
+    {        
+        int dAId = dashboardService.saveDashboard( dA );
+        int dBId = dashboardService.saveDashboard( dB );
+        
+        assertNotNull( dashboardService.getDashboard( dAId ) );
+        assertNotNull( dashboardService.getDashboard( dBId ) );
+        
+        dashboardService.deleteDashboard( dA );
+
+        assertNull( dashboardService.getDashboard( dAId ) );
+        assertNotNull( dashboardService.getDashboard( dBId ) );
+
+        dashboardService.deleteDashboard( dB );
+
+        assertNull( dashboardService.getDashboard( dAId ) );
+        assertNull( dashboardService.getDashboard( dBId ) );        
+    }
+}

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DashboardController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DashboardController.java	2013-07-22 15:17:19 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DashboardController.java	2013-07-22 21:08:05 +0000
@@ -2,8 +2,7 @@
 
 import javax.servlet.http.HttpServletResponse;
 
-import org.hisp.dhis.api.utils.ContextUtils;
-import org.hisp.dhis.api.utils.ContextUtils.CacheStrategy;
+import org.hisp.dhis.dashboard.Dashboard;
 import org.hisp.dhis.dashboard.DashboardSearchResult;
 import org.hisp.dhis.dashboard.DashboardService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -16,22 +15,18 @@
 @Controller
 @RequestMapping( value = DashboardController.RESOURCE_PATH )
 public class DashboardController
+    extends AbstractCrudController<Dashboard>
 {
     public static final String RESOURCE_PATH = "/dashboards";
         
     @Autowired
     private DashboardService dashboardService;
     
-    @Autowired
-    private ContextUtils contextUtils;
-    
-    @RequestMapping( value = "/search/{query}", method = RequestMethod.GET, produces = { "application/json" } )
+    @RequestMapping( value = "/q/{query}", method = RequestMethod.GET )
     public String search( @PathVariable String query, 
         Model model,
         HttpServletResponse response ) throws Exception
     {
-        contextUtils.configureResponse( response, ContextUtils.CONTENT_TYPE_JSON, CacheStrategy.NO_CACHE );
-        
         DashboardSearchResult result = dashboardService.search( query );
         
         model.addAttribute( "model", result );

=== modified file 'dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/webapp/dhis-web-dashboard-integration/javascript/dashboard.js'
--- dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/webapp/dhis-web-dashboard-integration/javascript/dashboard.js	2013-07-22 16:50:06 +0000
+++ dhis-2/dhis-web/dhis-web-dashboard-integration/src/main/webapp/dhis-web-dashboard-integration/javascript/dashboard.js	2013-07-22 21:08:05 +0000
@@ -131,7 +131,7 @@
 		return false;
 	}
 	
-	var hits = $.get( "../api/dashboards/search/" + query, function( data ) {
+	var hits = $.get( "../api/dashboards/q/" + query, function( data ) {
 		$( "#hitDiv" ).show().html( getSearchResultList( data ) );		
 	} );		
 }