Merge lp:dhis2 into lp:~tw-msf/dhis2/dhis2

Proposed by Mahendra Kariya
Status: Merged
Merged at revision: 14679
Proposed branch: lp:dhis2
Merge into: lp:~tw-msf/dhis2/dhis2
Diff against target: 118964 lines (has conflicts)
Text conflict in dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DefaultDataValueSetService.java
Conflict: can't delete dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api because it is not empty.  Not deleting.
Conflict because dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api is not versioned, but has versioned children.  Versioned directory.
Conflict: can't delete dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller because it is not empty.  Not deleting.
Conflict because dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller is not versioned, but has versioned children.  Versioned directory.
Contents conflict in dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/CompleteDataSetRegistrationController.java
Contents conflict in dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/SystemSettingController.java
Contents conflict in dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/UserSettingController.java
To merge this branch: bzr merge lp:dhis2
Reviewer Review Type Date Requested Status
Lars Helge Øverland Pending
Review via email: mp+219164@code.launchpad.net

Description of the change

- Changed Translation to have uid of the translated object rather than the database id.
- Added an API for Translations. (Get all / Post )
- Making pwd validation optional for update user api
- Adding get user preference web api

To post a comment you must log in.
lp:dhis2 updated
15226. By Morten Olav Hansen

use PERIOD_TYPE_MAP instead of creating new instances in PeriodType.getPeriodTypeFromIsoString

15227. By Lars Helge Øverland

Event capture, small margin between table and paging

15228. By Abyot Asalefew Gizaw <email address hidden>

UI for search by program

15229. By Lars Helge Øverland

Made dependency explicit

15230. By Lars Helge Øverland

Removed really weird dependency

15231. By Abyot Asalefew Gizaw <email address hidden>

minor

15232. By Thu Tran

Support aggregate query builder formulas for the number days between visit-date of event and a date-attribute value.

15233. By Lars Helge Øverland

Made explict dependency on javassist. Version must be kept in sync with the one used by hibernate.

15234. By Abyot Asalefew Gizaw <email address hidden>

UI for tracked entity instance registration

15235. By Lars Helge Øverland

Codestyle

15236. By Abyot Asalefew Gizaw <email address hidden>

minor

15237. By Lars Helge Øverland

Encapsulated super user logic

15238. By Morten Olav Hansen

added simple tests for DateUnit, inject CalendarService into PeriodTypes (but not in use yet)

15239. By Morten Olav Hansen

minor bugfixes, and more tests for DateUnit

15240. By Morten Olav Hansen

minor fix

15241. By Lars Helge Øverland

Event capture. Fixed issue with pager sometimes being undefined. Made service more robust by checking whether pager is defined and falling back to default values.

15242. By Lars Helge Øverland

CSS fix

15243. By Lars Helge Øverland

Not null constraint on category option group short name

15244. By Jan Henrik Øverland

ER, count type, with options: events | unique TE instances.

15245. By Jan Henrik Øverland

ER, NaN bug fixed.

15246. By Morten Olav Hansen

remove programInstances from Program json/xml export, this should be considered data, and not exported as meta-data

15247. By Lars Helge Øverland

COG, test fix

15248. By Lars Helge Øverland

Added class to base identifiable tostring

15249. By Morten Olav Hansen

removed restriction on filters, allow for filtering of non-idobjects with exported properties

15250. By Lars Helge Øverland

IdentifiableObjectStore, added property which can be overridden by impls for whether backing object has persisted id properties - some impls do not. Makes it possible to search for an object solely based on uid.

15251. By Abyot Asalefew Gizaw <email address hidden>

UI for relationship

15252. By Lars Helge Øverland

CSS font weight bold fix

15253. By Lars Helge Øverland

CSS fix

15254. By Thu Tran

Use HibernateGenericStore in HibernateProgramStageDataElementStore.

15255. By Morten Olav Hansen

moved calendar settings from general to its own section

15256. By Morten Olav Hansen

in apps-servlet, just do a 404 if file is not found, current 'html5 compatible' solution didn't really work

15257. By Lars Helge Øverland

Reverted r 15254

15258. By Morten Olav Hansen

Added PeriodType.getCalendar, will return system calendar if calendarService is available, if not, default to iso 8601 impl. Added new method to Calendar, toIntervals, allows for generating multiple intervals.

15259. By Lars Helge Øverland

Removed unused method

15260. By Lars Helge Øverland

CSV import, added support for option sets

15261. By Jan Henrik Øverland

PT DV GIS, i18n.

15262. By Morten Olav Hansen

minor javadoc fix

15263. By Lars Helge Øverland

Dashboard tables cleanup

15264. By Lars Helge Øverland

Minor

15265. By Abyot Asalefew Gizaw <email address hidden>

upgrade of select2 and tracked entity search - WIP

15266. By Abyot Asalefew Gizaw <email address hidden>

tracked entity list refactored

15267. By Lars Helge Øverland

Tracker, fixed bug, display in list no program was assuming column value to be false

15268. By Lars Helge Øverland

Attribute no program, minor fix

15269. By Lars Helge Øverland

Attribute no program, minor fix

15270. By Thu Tran

Rewrite methods in tracker to use criteria instead of hql.

15271. By Thu Tran

Fix bug - Exception thrown when downloading program-history report in TEI dashboard

15272. By Thu Tran

Remove the orgunit-groups in Program object.

15273. By Abyot Asalefew Gizaw <email address hidden>

searching tracked entity - wip

15274. By Ngo Thanh Long

[mobile] clean up, remove unused classes

15275. By Bharath

RBF: Minor fixes on MaxScore

15276. By Abyot Asalefew Gizaw <email address hidden>

searching tracked entity - wip

15277. By Jim Grace

User administration restrictions

15278. By Lars Helge Øverland

Merge from ThoughtWorks/MSF team branch. Makes Translation.java an IdentifiableObject. Exposes translations in Web API.

15279. By Lars Helge Øverland

Minor

15280. By Abyot Asalefew Gizaw <email address hidden>

searching tei - wip

15281. By Lars Helge Øverland

Applied patch from TW. Implements post of system settings map.

15282. By Thu Tran

Fixed bug - Error when saving aggregate data values from Manual Aggregate.

15283. By Thu Tran

Exception thrown when clicking on the details icon of Aggregate query result.

15284. By Le Hong Em

[mobile] update send message server side for mobile J2ME agg

15285. By Thu Tran

Rename in HibernateTrackedEntityFormStore from getCommonForm to getFormsWithoutProgram.

15286. By Thu Tran

Move all classes from package org.hisp.dhis.trackedentity.scheduling to project dhis-service-eventreporting.

15287. By Lars Helge Øverland

Fixed various compilatione errors

15288. By Abyot Asalefew Gizaw <email address hidden>

tei grid, show/hide columns and additional column for orgunit

15289. By Lars Helge Øverland

Tracker, cleanup

15290. By Lars Helge Øverland

Codestyle fix

15291. By Lars Helge Øverland

Removed unused method

15292. By Abyot Asalefew Gizaw <email address hidden>

synchronized TEI search and registration UI

15293. By Thu Tran

Remove unused methods in tracker module.

15294. By Thu Tran

Remove unused methods in eventreporting module.

15295. By Thu Tran

Minor fix.

15296. By Thu Tran

Migrate the value from combo to optionSet in database, java and UI.

15297. By Jim Grace

Support attribute categories in validation

15298. By Paul Mark Castillo

Implemented Interpretations for Mobile Lite
https://blueprints.launchpad.net/dhis-mobile/+spec/mla-interpretations

15299. By Abyot Asalefew Gizaw <email address hidden>

tei registration and enrollment

15300. By Lars Helge Øverland

Web light module, cleaned up code style

15301. By Lars Helge Øverland

User role schema descriptor fix

15302. By Jim Grace

Remove unused UserCredentialsCanUpdateFilter.java

15303. By Abyot Asalefew Gizaw <email address hidden>

communication between tei dashboard controller

15304. By Thu Tran

Add statement to update aggregate query builder formulas from 2.13 to 2.15

15305. By Lars Helge Øverland

Deletion of category combination, including check for attributeoptioncombo in datavalues

15306. By Lars Helge Øverland

Category deletion, allowing deletion of categories which are linked to option combos. No good reason to deny that.

15307. By Lars Helge Øverland

Added new web api method at api/dimensions/constraints for potential dimensional constraints

15308. By Lars Helge Øverland

Excluded xerces

15309. By Abyot Asalefew Gizaw <email address hidden>

tei registration and enrollment - wip

15310. By Abyot Asalefew Gizaw <email address hidden>

minor

15311. By Abyot Asalefew Gizaw <email address hidden>

a little timeout to ensure broadcasts are not missed between controllers

15312. By Lars Helge Øverland

Email settings, made the email from address configurable

15313. By Lars Helge Øverland

Override annotations

15314. By Lars Helge Øverland

Mobile, correct interface modifiers

15315. By Lars Helge Øverland

Mobile, correct interface modifiers

15316. By Lars Helge Øverland

Unused method

15317. By Abyot Asalefew Gizaw <email address hidden>

more interaction in tei dashboard widgets such as editing, enrolling, event creation... - WIP

15318. By Lars Helge Øverland

SmsMessageSender, simplified logic

15319. By Lars Helge Øverland

Unused code

15320. By Lars Helge Øverland

Tracker, removed unused methods

15321. By Lars Helge Øverland

Tracker, removed unused code

15322. By Lars Helge Øverland

TrackedEntityInstance, moved method from store to service layer

15323. By Lars Helge Øverland

Typo

15324. By Lars Helge Øverland

Unused imports

15325. By Ngo Thanh Long

[mobile] migrate to TEI new method in line 286, update enrollProgram() to support for register and import Data Value on-the-fly

15326. By Lars Helge Øverland

Tracker, removed method from TrackedEntityStore/Service

15327. By Lars Helge Øverland

Tracker, removed method from TrackedEntityStore/Service for checking representative. We should reconsider the representative implementation or re-implemet in main TEI query.

15328. By Lars Helge Øverland

Minor

15329. By Ngo Thanh Long

remove class scope patient property in ActivityReportingServiceImpl

15330. By sherylyn.marie

https://blueprints.launchpad.net/dhis-mobile/+spec/enhance-tracker-client
#3 VISIT SCHEDULE

15331. By Ngo Thanh Long

remove TrackedEntityMobileSetting and all related services, actions

15332. By Abyot Asalefew Gizaw <email address hidden>

minor

15333. By jason.p.pickering

(Translations) Intermim commit of French

15334. By jason.p.pickering

(Translations) Interim sync of Arabic translations.

15335. By Le Hong Em

[mobile] update message conversations for J2ME Agg

15336. By Abyot Asalefew Gizaw <email address hidden>

stylesheet - spacing between buttons

15337. By Abyot Asalefew Gizaw <email address hidden>

removed searching and filtering from entity grid - these features can now be directly applied during searching

15338. By Abyot Asalefew Gizaw <email address hidden>

list all etinties by default if orgunit is selected

15339. By Abyot Asalefew Gizaw <email address hidden>

cleanup

15340. By Abyot Asalefew Gizaw <email address hidden>

by default display only those attributes marked displayInListNoProgram

15341. By Lars Helge Øverland

Merge branch localized-calendar from Morten. Implements new and more sophisticated calendar solution.

15342. By Thu Tran

Fixed bug - Don't display option-set attribute as combobox in default TEI registration form.

15343. By Thu Tran

Minor fix.

15344. By Thu Tran

Fixed bug - Error when displaying values of TYes-Only attributes in registration form.

15345. By jason.p.pickering

Adding another script for cleaning of translation files.

15346. By jason.p.pickering

Minor fix to translation cleaning script.

15347. By jason.p.pickering

(Translations) French translation cleanup.

15348. By Thu Tran

Fixed bug - Hide orgunit-uid column of TEI list in Tracked entity instance management

15349. By Le Hong Em

[mobile] reply message

15350. By Thu Tran

Fixed bug - Error when to enroll a TEI into a program in TEI Dashboard.

15351. By Ngo Thanh Long

clean up & bug fix for offline tracked entity data entry

15352. By Lars Helge Øverland

CSS fix

15353. By jason.p.pickering

(Translations) Cleaned up Spanish translations.

15354. By Lars Helge Øverland

Event capture, reduced size of headers

15355. By Lars Helge Øverland

Event report, moved show columns on top of register event button to allow for smaller screens

15356. By Lars Helge Øverland

Minor

15357. By Lars Helge Øverland

Autocomplete off in user invite for email and username

15358. By Morten Olav Hansen

made json default rendering for html/text header, removed xslt view rendering

15359. By Morten Olav Hansen

removing xslt files used for rendering html view

15360. By Lars Helge Øverland

Fixed bug with autocomplete in data entry as a result of jquery-ui upgrade

15361. By Morten Olav Hansen

changed main package for dhis-web-api from org.hisp.dhis.api => org.hisp.dhis.webapi, makes it more obvious where classes belong, also makes component scanner be more specific (it does not include files from dhis-api module which had same package)

15362. By Lars Helge Øverland

Autocomplete style

15363. By Morten Olav Hansen

upgrade to spring 3.2.9, and spring security 3.2.4

15364. By Abyot Asalefew Gizaw <email address hidden>

minor ui adjustments in event capture

15365. By Jan Henrik Øverland

PT, column/row totals as separate options.

15366. By Abyot Asalefew Gizaw <email address hidden>

replaced blue tables in tracker capture with grey ones

15367. By Morten Olav Hansen

made explicit dependency on xml-apis 1.4.01

15368. By Thu Tran

Fixed bug - Error when to enroll a TEI into a program in TEI

15369. By Lars Helge Øverland

Cleanup

15370. By Morten Olav Hansen

change to using /api/system/info to get context information in event-reports

15371. By Morten Olav Hansen

remove /api/system/context endpoint (use /system/info instead), add calendar/dateFormat info to SystemInfo (exposed in /api/system/info)

15372. By Morten Olav Hansen

remove unused constants in ProgramStage

15373. By Morten Olav Hansen

expose trackedEntityInstanceReminders on ProgramStage

15374. By Morten Olav Hansen

expose dataElement on progrmaStageDataElement as idObject

15375. By Jan Henrik Øverland

PT DV GIS plugins updated (commons) + EV, gui fixes, work in progress.

15376. By Morten Olav Hansen

minor undefined check in form.js

15377. By Jan Henrik Øverland

ER, period bug fixed.

15378. By Jan Henrik Øverland

DV, axis min/max instead of max/min.

15379. By Bharath

RBF work in progress: QualityBasedPayment

15380. By Morten Olav Hansen

various fixes to tracker classes

15381. By Lars Helge Øverland

Removed TabularEventColumn

15382. By Morten Olav Hansen

remove unused constants in ProgramValidation

15383. By Morten Olav Hansen

javadoc updates to tracker classes

15384. By Morten Olav Hansen

minor import opts + code format

15385. By Morten Olav Hansen

minor fix, unnecessary unboxing

15386. By Morten Olav Hansen

minor fixes to calendar classes

15387. By Morten Olav Hansen

minor javadoc fixes in period package

15388. By Lars Helge Øverland

Unused import

15389. By Lars Helge Øverland

Mapped hibernate identifiable properties for ValidationCriteria

15390. By Lars Helge Øverland

Minor

15391. By Lars Helge Øverland

TrackedEntityInstanceController, changed from patient to tei for authorities

15392. By Mark Polak

Fixes menu in event-capture additionally adds menu scroll buttons

15393. By Thu Tran

Remove the Single event without registration in DataEntry menu.

15394. By Thu Tran

Hide the Add filter button in Advanced search of Lost to follow up; add the datapicker for due-date search field in Lost to follow up.

15395. By Thu Tran

Apply web-api for search relationship of TEI in Find/Add instance.

15396. By Thu Tran

Minor fix for TEI relationship list.

15397. By Thu Tran

Fixed bug - Repeatable program stage not stored.

15398. By Abyot Asalefew Gizaw <email address hidden>

drop down menus for program selection and advanced search - wip

15399. By Morten Olav Hansen

support resources without paging in progressive selected loader

15400. By Morten Olav Hansen

Minor fix

15401. By Morten Olav Hansen

use HttpServletResponse.sendRedirect instead of relying of RedirectView which we don't use in the view-chain anymore, fixes issues with redirecting from /api and /api/ => /api/resources

15402. By Abyot Asalefew Gizaw <email address hidden>

code style, advanced search drop-down menu stays open onclicks, except for the intended buttons

15403. By Paul Mark Castillo

[NEW] Added sharing interpretations
https://blueprints.launchpad.net/dhis-mobile/+spec/mla-interpretations

15404. By Lars Helge Øverland

Approval, added missing states to approval report UI.

15405. By Lars Helge Øverland

ModuleManager, removed service/maintenance methods

15406. By Morten Olav Hansen

minor fixes to CategoryOptionComboSchemaDescriptor, CategoryOptionCombos are not shareable

15407. By Paul Mark Castillo

[IMPROVED] Cleaned up code for Interpretations for Mobile Lite
https://blueprints.launchpad.net/dhis-mobile/+spec/mla-interpretations

15408. By Thu Tran

Fixed bug - Don't display values of Date attribute in the Enrollment program form.

15409. By Morten Olav Hansen

enabled export of certain tracker objects

15410. By Morten Olav Hansen

hashCode/equals fixes to ProgramStageDataElement and ProgramTrackedEntityAttribute

15411. By Morten Olav Hansen

uncommented removal of tracker classes for import (but not working yet, since importer beans have not been added)

15412. By Morten Olav Hansen

minor importer fixes for tracker

15413. By Morten Olav Hansen

use AbstractCrudController which uses importer for CRUD operations on TrackedEntity objects

15414. By Morten Olav Hansen

fixes to tracker classes, adding merging

15415. By Morten Olav Hansen

minor fixes

15416. By Morten Olav Hansen

Added ValidtionCritera importer and property to MetaData

15417. By Morten Olav Hansen

support for ProgramStageSections in importer

15418. By Morten Olav Hansen

Support ProgramValidation for tracker importer

15419. By Morten Olav Hansen

add programValidtionSchemaDescriptor

15420. By Morten Olav Hansen

in expression extracter in IdObjectImporter, make sure that type is Expression (could clash with ProgramExpression etc)

15421. By Jim Grace

Add to webapi: POST /users/invite

15422. By Morten Olav Hansen

minor fix for sharing dialog, create dialog before autocomplete widget

15423. By Jim Grace

Add category dimension constraints, also validation implements dimension constraints.

15424. By Morten Olav Hansen

minor redirect fix in IndexController

15425. By Morten Olav Hansen

minor fixes to tracker import

15426. By Morten Olav Hansen

minor fix in detailed meta-data export, change from AttributeTypes => Attributes

15427. By Morten Olav Hansen

Minor fix

15428. By Morten Olav Hansen

fixes height issue with detailed export, uses new heightStyle property on accordion

15429. By Morten Olav Hansen

minor

15430. By Morten Olav Hansen

minor fix

15431. By Morten Olav Hansen

Add import for EventReport

15432. By Abyot Asalefew Gizaw <email address hidden>

refactored tracker capture into multiple components, updated code for changes in web-api

15433. By Morten Olav Hansen

expose endpoint in schemaDescriptors, wip

15434. By Morten Olav Hansen

finished exposing endpoints in schema-descriptors

15435. By Morten Olav Hansen

Simplified resource view in web-api, removed /api/resources, resource view is served directly on /api/ now. Uses SchemaDescriptors to generate resources based on apiEndpoint property.

15436. By Thu Tran

Translation.

15437. By Abyot Asalefew Gizaw <email address hidden>

tracker capture, more work on refactoring

15438. By Lars Helge Øverland

Fixed compilation/test error in tracker

15439. By Jan Henrik Øverland

GIS, isadmin callback bug fixed + PT, ou hierarchy wip + ER, ou hierarcy bug fixed + EV, gui wip.

15440. By James Chang

PDF data import fix - checkbox uncheck value change to null rather than 'false'.

15441. By Abyot Asalefew Gizaw <email address hidden>

event capture updated for changes in web-api

15442. By Jan Henrik Øverland

PT DV GIS, plugin, context -> info.

15443. By Jan Henrik Øverland

PT DV GIS, embed code updated.

15444. By Morten Olav Hansen

minor fixes to cacheManifest (caseentry), related to jquery-ui update

15445. By Morten Olav Hansen

exposed metadata property on Schema, will be used to find classes that are used for metadata import/export. Updated SchemaDescripors with metadata info.

15446. By Morten Olav Hansen

New class for /api/schemas output, used instead of metadata class. Reworked dxf2 export list in import-export module, now gets the list of types diretly from /api/schemas, so the list will be dynamic and grow/shrink according to SchemaDescriptors.

15447. By sherylyn.marie

https://blueprints.launchpad.net/dhis-mobile/+spec/enhance-tracker-client
Enhance the feature and offline capacity of tracker client
#2 DATAENTRY FOR OFFLINE PATIENT
- Save thru Visit Schedule
- View thru History List

15448. By Morten Olav Hansen

start work to have export service depend on SchemaService, and not ExchangeClasses, minor fix to TEISchemaDescriptor

15449. By Morten Olav Hansen

implement Ordered interface on Schema, using default value for now. Sort SchemaService.getMetadataSchemas() based on this, important to get proper order on metadata import (but will also be used for export)

15450. By Morten Olav Hansen

wip, implement ordering of schemas

15451. By Morten Olav Hansen

wip, use SchemaService to get supported metadata types in importer/exporter

15452. By Abyot Asalefew Gizaw <email address hidden>

tei enrollment and profile edit from dashboard

15453. By Abyot Asalefew Gizaw <email address hidden>

synchronization between program selections and dashboard contents

15454. By Ngo Thanh Long

temporaryiy fix the build fail problem, the missin file should be commit asap

15455. By Abyot Asalefew Gizaw <email address hidden>

display only those attributes matching selected program in tei profile widget

15456. By Abyot Asalefew Gizaw <email address hidden>

minor

15457. By sherylyn.marie

Added PatientList.java

15458. By sherylyn.marie

added PatientList.java and enabled commented out codes

15459. By Jim Grace

When KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, don't allow user group membership changes causing the changer to gain or loose control over another user.

15460. By Morten Olav Hansen

minor fixes

15461. By Morten Olav Hansen

various fixes to importer, should not be used for tracker objects yet

15462. By Morten Olav Hansen

minor fix

15463. By Morten Olav Hansen

more fixes to importer

15464. By Mark Polak

Make up and down scroll buttons for dropdown menu smaller

15465. By Lars Helge Øverland

Fixed bug with GIS/DV download as png, removing unsafe characters from svg text elements

15466. By Abyot Asalefew Gizaw <email address hidden>

event capture - trimmed data feteched from server using include/exclude feature of the web api

15467. By Thu Tran

Fixed bug - The buttons in TEI Advanced search box are disabled when another orgunit is selected.

15468. By Thu Tran

Fixed bug - Some attribute values are deleted after TEI enrolls into a program.

15469. By Thu Tran

Fixed bug - Hide the Remove program button indashboard if the program selected has any active events.

15470. By Thu Tran

Add deletionHandler for deleting program instance.

15471. By Lars Helge Øverland

App object, remove the permissions config property since it does not match the specification and causes trouble when installing apps

15472. By Lars Helge Øverland

Missing licenses

15473. By Thu Tran

Update help content for tracker module.

15474. By Morten Olav Hansen

minor fixes to programStage importer

15475. By Jan Henrik Øverland

GIS, interpretation gui bug fixed.

15476. By Lars Helge Øverland

Added academy server index file

15477. By Morten Olav Hansen

minor indent fix

15478. By Morten Olav Hansen

fixes to tracker import, basic import should now work (although dry-run is disabled for certain types)

15479. By Morten Olav Hansen

remove dependency on ExchangeClasses in DefaultIdentifiableObjectImporter and AbstractCrudController

15480. By Lars Helge Øverland

SQL view, download as json

15481. By Morten Olav Hansen

removed dependency of ExchangeClasses in DefaultObjectBridge

15482. By Morten Olav Hansen

minor update to schema order, add a bit more room between each schema, makes it easier to plug in other schemas later

15483. By Morten Olav Hansen

removed usage of ExchangeClasses in DefaultMetaDataDependencyService

15484. By Morten Olav Hansen

minor cleanup

15485. By Lars Helge Øverland

DimensionService, fixed bug, lists of dimensions of type org unit group set and data element group set did not respect sharing

15486. By Bharath <email address hidden>

RBF: QualityPaymentScore calculation

15487. By Morten Olav Hansen

introduces two new services: ContextServices and LinkService. LinkService will generate links automatic based on presence of getUid and setHepref. Also extends SchemaService with new method getDynamicSchema, auto-generates schema based on class, useful for classes that have Jackson exposed properties but have no SchemaDescriptor.

15488. By Morten Olav Hansen

wip, node based object graph with json/xml renderers

15489. By Morten Olav Hansen

minor fix

15490. By Morten Olav Hansen

minor change, double check that value is true if XML_ATTRIBUTE hint is set

15491. By Lars Helge Øverland

Notificating in org unit level screen when no levels have been saved yet

15492. By Lars Helge Øverland

Web API, MaintenanceController, added function for clearing application cache

15493. By Lars Helge Øverland

Minor

15494. By Morten Olav Hansen

minor refactor to node render system

15495. By Morten Olav Hansen

support unwrapped collections in xml writer, minor bugfixes to JacksonJson writer, use Node based rendering system in SystemController/UID (only json output for now, will be both xml/json soon)

15496. By Morten Olav Hansen

removed unused package

15497. By Morten Olav Hansen

add RootNodeMessageConverter (write only), allow usage of @ResponseBody in controllers (and return type RootNode), being used in SystemController/UID to support both xml/json automatic

15498. By Thu Tran

Minor fix

15499. By Morten Olav Hansen

minor changes

15500. By Lars Helge Øverland

Removed file

15501. By Lars Helge Øverland

Data value import, trimming meta data objects before looking up in maps

15502. By Morten Olav Hansen

minor change, add helper method for adding new NodeHint

15503. By Lars Helge Øverland

Data value error code translations

15504. By Thu Tran

Fixed bug - The dropdown list of options of dataelements does not show up in Add function of single event with registration.

15505. By Thu Tran

Small change UI of Tracked entity attributes displayed in list form.

15506. By Thu Tran

Add filter for attributes in available Attribute box of Tracked entity attributes displayed in list.

15507. By Thu Tran

Use ajax to load available attributes in Tracked entity attribute visit schedule form and Tracked entity attributes displayed in list form.

15508. By Thu Tran

Remove unused translation in UI ( tracker module )

15509. By Thu Tran

Add a link to show/hide advanced options into Add/Update program form.

15510. By jason.p.pickering

(Translations) Interim commit of Myanmar translations including clean-up.

15511. By Morten Olav Hansen

minor api update

15512. By Morten Olav Hansen

add RenderServiceMessageConverter, uses renderService to render out objects (based on annotations), don't support viewClasses, but useful for simplifying controllers where we just use JacksonUtils.toX or renderService.toX directly

15513. By Morten Olav Hansen

minor rename in SchemaController

15514. By Jan Henrik Øverland

PT DV GIS ER, startup validation.

15515. By Abyot Asalefew Gizaw <email address hidden>

custom form for event capture

15516. By Mithilesh Kumar Thakur

local/in RBF work in progress

15517. By Jan Henrik Øverland

ER, N/A sorting bug fixed.

15518. By Lars Helge Øverland

Improved logging in module manager

15519. By Lars Helge Øverland

Std dev outlier analysis, paging org units in order to avoid very large sql criteria

15520. By Jim Grace

Added category option start and end dates, blueprint category-start-end-dates

15521. By Morten Olav Hansen

minor indent fix

15522. By Morten Olav Hansen

expose propertyMap on Schema

15523. By Morten Olav Hansen

use SchemaService instead of PropertyIntrospectorService in DefaultFilterService

15524. By Morten Olav Hansen

simplifications to DefaultFilterService code

15525. By Abyot Asalefew Gizaw <email address hidden>

turned-off localestorage for event capture, soon to be replaced with dhis2.storage

15526. By Morten Olav Hansen

rewrote filter functionality to use node rendrer system, only supports json for now (but xml is coming soon)

15527. By Thu Tran

Fixed bug - Exception thrown when to delete a program

15528. By Thu Tran

Small change in Assign program to user roles form.

15529. By Abyot Asalefew Gizaw <email address hidden>

replaced localstorage with indexedDB storage for event capture

15530. By Lars Helge Øverland

Module tostring

15531. By Morten Olav Hansen

minor changes to schema/property classes

15532. By Morten Olav Hansen

expose class-level name/namespaceURI in Schema with data from @JacksonXmlRootElement

15533. By Morten Olav Hansen

support COMMENTs in Nodes (will only be output in XML at the moment, since valid JSON does not support comments)

15534. By Morten Olav Hansen

use nodes to write out DVS template (now supports json and xml)

15535. By Morten Olav Hansen

Minor fix

15536. By Abyot Asalefew Gizaw <email address hidden>

minor

15537. By Thu Tran

Add validation for attribute field with letter value type on TEI registration form.

15538. By Thu Tran

Minor fix.

15539. By Thu Tran

Fixed bug - Display value-field according to the value type of attribute selected in Add/Update Validation Criteria.

15540. By Le Hong Em

[mobile] add feedback for J2ME tracker

15541. By Thu Tran

Add filter field for Validation criteria list form.

15542. By Morten Olav Hansen

minor changes to web-api filter

15543. By Morten Olav Hansen

added class information to ComplexNode, useful in cases where the ComplexNode represents a class, and you want that information for later purposes (like getting the schema, link-generator etc)

15544. By Morten Olav Hansen

minor compilation fix

15545. By Thu Tran

Add filter field for Program Validation rule list form.

15546. By Morten Olav Hansen

minor change to ComplexNode

15547. By Thu Tran

Remove unused classes in tracker module.

15548. By Le Hong Em

[mobile] update org unit controller for J2ME tracker

15549. By Morten Olav Hansen

simplifications to Nodes, removed 'hinting' for now

15550. By Thu Tran

Fixed bug - The Days when to send message isn't save if this values is nagetive

15551. By Morten Olav Hansen

minor fixes to serializers

15552. By Thu Tran

Fixed bug - The Days when to send message isn't save if this values is nagetive in program reminder message template.

15553. By Lars Helge Øverland

Analytics, more descriptive feedback in analytics when tables cannot be updated

15554. By Morten Olav Hansen

minor api changes to NodeService

15555. By Morten Olav Hansen

use map internally in AbstractNode, speeds up lookup based on name, also enforces name uniqueness (might be name+namespace in the future)

15556. By Morten Olav Hansen

remove duplicate license

15557. By Le Hong Em

[mobile] update org unit controller for J2ME tracker

15558. By Morten Olav Hansen

Minor fix

15559. By Morten Olav Hansen

revert to using list instead of map for children list

15560. By Morten Olav Hansen

changed parameter parsing in inclusion/exclusion filter

15561. By Morten Olav Hansen

Minor javadoc update

15562. By Morten Olav Hansen

minor fixes to nodeService

15563. By Morten Olav Hansen

minor fix to contextService

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'dhis-2/dhis-api/pom.xml'
2--- dhis-2/dhis-api/pom.xml 2014-04-25 10:44:39 +0000
3+++ dhis-2/dhis-api/pom.xml 2014-06-05 17:39:07 +0000
4@@ -83,6 +83,10 @@
5 <groupId>org.hibernate</groupId>
6 <artifactId>hibernate-validator</artifactId>
7 </dependency>
8+ <dependency>
9+ <groupId>org.javassist</groupId>
10+ <artifactId>javassist</artifactId>
11+ </dependency>
12
13 </dependencies>
14
15
16=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/appmanager/App.java'
17--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/appmanager/App.java 2014-03-18 08:10:10 +0000
18+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/appmanager/App.java 2014-06-05 17:39:07 +0000
19@@ -78,9 +78,6 @@
20 private String locales;
21
22 @JsonProperty
23- private String permissions;
24-
25- @JsonProperty
26 private AppActivities activities;
27
28 @JsonProperty
29@@ -194,16 +191,6 @@
30 this.locales = locales;
31 }
32
33- public String getPermissions()
34- {
35- return permissions;
36- }
37-
38- public void setPermissions( String permissions )
39- {
40- this.permissions = permissions;
41- }
42-
43 public AppActivities getActivities()
44 {
45 return activities;
46
47=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/AbstractCalendar.java'
48--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/AbstractCalendar.java 2014-05-13 16:00:50 +0000
49+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/AbstractCalendar.java 2014-06-05 17:39:07 +0000
50@@ -143,7 +143,7 @@
51 @Override
52 public DateUnit fromIso( int year, int month, int day )
53 {
54- return fromIso( new DateUnit( year, month, day ) );
55+ return fromIso( new DateUnit( year, month, day, true ) );
56 }
57
58 @Override
59
60=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/Calendar.java'
61--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/Calendar.java 2014-05-13 16:00:50 +0000
62+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/Calendar.java 2014-06-05 17:39:07 +0000
63@@ -32,6 +32,7 @@
64
65 /**
66 * Generic interface for representing a Calendar.
67+ *
68 * @author Morten Olav Hansen <mortenoh@gmail.com>
69 * @see DateUnit
70 * @see DateInterval
71@@ -41,24 +42,28 @@
72 {
73 /**
74 * Name of this calendar.
75+ *
76 * @return Name of calendar.
77 */
78 String name();
79
80 /**
81 * Date format for this calendar
82+ *
83 * @return Default date format
84 */
85 String getDateFormat();
86
87 /**
88 * Set date format for this calendar
89+ *
90 * @param dateFormat Date format to use for this calendar
91 */
92 void setDateFormat( String dateFormat );
93
94 /**
95 * Formats dateUnit using dateFormat
96+ *
97 * @param dateUnit DateUnit representing local year, month, day
98 * @return Default date format
99 * @see #getDateFormat()
100@@ -67,6 +72,7 @@
101
102 /**
103 * Formats dateUnit using dateFormat and ISO 8601
104+ *
105 * @param dateUnit DateUnit representing local year, month, day
106 * @return Default date format
107 * @see #getDateFormat()
108@@ -75,6 +81,7 @@
109
110 /**
111 * Convert local calendar to an ISO 8601 DateUnit.
112+ *
113 * @param year Local year
114 * @param month Local month
115 * @param day Local day
116@@ -85,6 +92,7 @@
117
118 /**
119 * Convert local calendar to an ISO 8601 DateUnit.
120+ *
121 * @param date Date formatted using default date format
122 * @return DateUnit representing local date in ISO 8601
123 * @see <a href="http://en.wikipedia.org/wiki/ISO_8601">http://en.wikipedia.org/wiki/ISO_8601</a>
124@@ -93,6 +101,7 @@
125
126 /**
127 * Convert local calendar to an ISO 8601 DateUnit.
128+ *
129 * @param dateUnit DateUnit representing local year, month, day
130 * @return DateUnit representing local date in ISO 8601
131 * @see <a href="http://en.wikipedia.org/wiki/ISO_8601">http://en.wikipedia.org/wiki/ISO_8601</a>
132@@ -101,6 +110,7 @@
133
134 /**
135 * Convert from local to ISO 8601 DateUnit.
136+ *
137 * @param year ISO 8601 year
138 * @param month ISO 8601 month
139 * @param day ISO 8601 day
140@@ -111,6 +121,7 @@
141
142 /**
143 * Convert from local to ISO 8601 DateUnit.
144+ *
145 * @param dateUnit DateUnit representing ISO 8601 year, month, day
146 * @return DateUnit representing ISO 8601 in local
147 * @see <a href="http://en.wikipedia.org/wiki/ISO_8601">http://en.wikipedia.org/wiki/ISO_8601</a>
148@@ -119,6 +130,7 @@
149
150 /**
151 * Gets interval of type based on DateUnit
152+ *
153 * @param dateUnit DateUnit representing local year, month, day
154 * @param type Interval type to get
155 * @param offset Offset to start at, can be negative of positive
156@@ -130,6 +142,7 @@
157
158 /**
159 * Gets interval of type based on DateUnit using default options, 0 for offset, 1 for length
160+ *
161 * @param dateUnit DateUnit representing local year, month, day
162 * @param type Interval type to get
163 * @return Interval for interval type based on dateUnit
164@@ -139,6 +152,7 @@
165
166 /**
167 * Gets interval of type based on today's date
168+ *
169 * @param type Interval type to get
170 * @return Interval for interval type based on dateUnit
171 * @see DateIntervalType
172@@ -147,6 +161,7 @@
173
174 /**
175 * Gets interval of type based on today's date
176+ *
177 * @param type Interval type to get
178 * @param offset Offset to start at, can be negative of positive
179 * @param length How many periods to asks for, i.e. type = MONTH, length = 2, two months
180@@ -157,6 +172,7 @@
181
182 /**
183 * Gets interval of type based on DateUnit
184+ *
185 * @param dateUnit DateUnit representing local year, month, day
186 * @param type Interval type to get
187 * @param offset Offset to start at, can be negative of positive
188@@ -169,37 +185,50 @@
189
190 /**
191 * Gets current date as local DateUnit
192+ *
193 * @return Today date as local DateUnit
194 */
195 DateUnit today();
196
197 /**
198 * Gets the number of months in a calendar year.
199+ *
200 * @return Number of months in a year
201 */
202 int monthsInYear();
203
204 /**
205 * Gets the number of days in a calendar week.
206+ *
207 * @return Number of days in a week
208 */
209 int daysInWeek();
210
211 /**
212 * Gets the number of days in a calendar year.
213+ *
214 * @return Number of days in this calendar year
215 */
216 int daysInYear( int year );
217
218 /**
219 * Gets the number of days in a calendar year/month.
220+ *
221 * @return Number of days in this calendar year/month
222 */
223 int daysInMonth( int year, int month );
224
225 /**
226+ * Gets the number of weeks in a calendar year.
227+ *
228+ * @return Number of weeks in this calendar year
229+ */
230+ int weeksInYear( int year );
231+
232+ /**
233 * Gets week number using local DateUnit, week number is calculated based on
234 * ISO 8601 week numbers
235+ *
236 * @param dateUnit DateUnit representing local year, month, day
237 * @return Week number
238 * @see <a href="http://en.wikipedia.org/wiki/ISO_8601">http://en.wikipedia.org/wiki/ISO_8601</a>
239@@ -209,6 +238,7 @@
240
241 /**
242 * Returns week number using local DateUnit, week number is calculated based on local calendar.
243+ *
244 * @param dateUnit DateUnit representing local year, month, day
245 * @return Week number
246 */
247@@ -217,6 +247,7 @@
248 /**
249 * Gets the ISO 8601 weekday for this local DateUnit, using ISO 8601 day numbering,
250 * 1=Monday => 7=Sunday.
251+ *
252 * @param dateUnit DateUnit representing local year, month, day
253 * @return Weekday number
254 * @see <a href="http://en.wikipedia.org/wiki/ISO_8601">http://en.wikipedia.org/wiki/ISO_8601</a>
255@@ -227,6 +258,7 @@
256 /**
257 * Gets the local weekday for this local DateUnit, using ISO 8601 day numbering,
258 * 1=Monday => 7=Sunday.
259+ *
260 * @param dateUnit DateUnit representing local year, month, day
261 * @return Weekday number
262 * @see <a href="http://en.wikipedia.org/wiki/ISO_8601">http://en.wikipedia.org/wiki/ISO_8601</a>
263@@ -236,6 +268,7 @@
264
265 /**
266 * Gets the (untranslated) I18n key for local month
267+ *
268 * @param month Month to fetch key for
269 * @return I18n Key for this month
270 * @see <a href="http://en.wikipedia.org/wiki/Internationalization_and_localization">http://en.wikipedia.org/wiki/Internationalization_and_localization</a>
271@@ -244,6 +277,7 @@
272
273 /**
274 * Gets the (untranslated) I18n short key for local month
275+ *
276 * @param month Month to fetch key for
277 * @return I18n Key for this month
278 * @see <a href="http://en.wikipedia.org/wiki/Internationalization_and_localization">http://en.wikipedia.org/wiki/Internationalization_and_localization</a>
279@@ -252,6 +286,7 @@
280
281 /**
282 * Gets the (untranslated) I18n key for local day
283+ *
284 * @param day Day to fetch key for
285 * @return I18n Key for this day
286 * @see <a href="http://en.wikipedia.org/wiki/Internationalization_and_localization">http://en.wikipedia.org/wiki/Internationalization_and_localization</a>
287@@ -260,6 +295,7 @@
288
289 /**
290 * Gets the (untranslated) I18n short key for local day
291+ *
292 * @param day Day to fetch key for
293 * @return I18n Key for this day
294 * @see <a href="http://en.wikipedia.org/wiki/Internationalization_and_localization">http://en.wikipedia.org/wiki/Internationalization_and_localization</a>
295@@ -268,6 +304,7 @@
296
297 /**
298 * Returns a new dateUnit with specified number of days added
299+ *
300 * @param dateUnit DateUnit representing local year, month, day
301 * @param days Days to add
302 * @return dateUnit + days
303@@ -276,6 +313,7 @@
304
305 /**
306 * Returns a new dateUnit with specified number of days subtracted
307+ *
308 * @param dateUnit DateUnit representing local year, month, day
309 * @param days Days to subtract
310 * @return dateUnit - days
311@@ -284,6 +322,7 @@
312
313 /**
314 * Returns a new dateUnit with specified number of weeks added
315+ *
316 * @param dateUnit DateUnit representing local year, month, day
317 * @param weeks Weeks to add
318 * @return dateUnit + weeks
319@@ -292,6 +331,7 @@
320
321 /**
322 * Returns a new dateUnit with specified number of weeks subtracted
323+ *
324 * @param dateUnit DateUnit representing local year, month, day
325 * @param weeks Weeks to subtract
326 * @return dateUnit - weeks
327@@ -300,6 +340,7 @@
328
329 /**
330 * Returns a new dateUnit with specified number of months added
331+ *
332 * @param dateUnit DateUnit representing local year, month, day
333 * @param months Months to add
334 * @return dateUnit + months
335@@ -308,6 +349,7 @@
336
337 /**
338 * Returns a new dateUnit with specified number of months subtracted
339+ *
340 * @param dateUnit DateUnit representing local year, month, day
341 * @param months Months to subtract
342 * @return dateUnit - months
343@@ -316,6 +358,7 @@
344
345 /**
346 * Returns a new dateUnit with specified number of years added
347+ *
348 * @param dateUnit DateUnit representing local year, month, day
349 * @param years Years to add
350 * @return dateUnit + years
351@@ -324,6 +367,7 @@
352
353 /**
354 * Returns a new dateUnit with specified number of years subtracted
355+ *
356 * @param dateUnit DateUnit representing local year, month, day
357 * @param years Years to subtract
358 * @return dateUnit - years
359
360=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/ChronologyBasedCalendar.java'
361--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/ChronologyBasedCalendar.java 2014-05-12 07:52:08 +0000
362+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/ChronologyBasedCalendar.java 2014-06-05 17:39:07 +0000
363@@ -47,15 +47,25 @@
364 @Override
365 public DateUnit toIso( DateUnit dateUnit )
366 {
367+ if ( dateUnit.isIso8601() )
368+ {
369+ return dateUnit;
370+ }
371+
372 DateTime dateTime = dateUnit.toDateTime( chronology );
373 dateTime = dateTime.withChronology( ISOChronology.getInstance() );
374
375- return DateUnit.fromDateTime( dateTime );
376+ return new DateUnit( DateUnit.fromDateTime( dateTime ), true );
377 }
378
379 @Override
380 public DateUnit fromIso( DateUnit dateUnit )
381 {
382+ if ( !dateUnit.isIso8601() )
383+ {
384+ return dateUnit;
385+ }
386+
387 DateTime dateTime = dateUnit.toDateTime( ISOChronology.getInstance() );
388 dateTime = dateTime.withChronology( chronology );
389 return DateUnit.fromDateTime( dateTime );
390@@ -204,7 +214,14 @@
391 public int daysInMonth( int year, int month )
392 {
393 DateTime dateTime = new DateTime( year, month, 1, 0, 0, chronology );
394- return (int) dateTime.monthOfYear().toInterval().toDuration().getStandardDays();
395+ return dateTime.dayOfMonth().getMaximumValue();
396+ }
397+
398+ @Override
399+ public int weeksInYear( int year )
400+ {
401+ DateTime dateTime = new DateTime( year, 1, 1, 0, 0, chronology );
402+ return dateTime.weekOfWeekyear().getMaximumValue();
403 }
404
405 @Override
406
407=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateInterval.java'
408--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateInterval.java 2014-04-27 02:45:02 +0000
409+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateInterval.java 2014-06-05 17:39:07 +0000
410@@ -84,6 +84,30 @@
411 }
412
413 @Override
414+ public boolean equals( Object o )
415+ {
416+ if ( this == o ) return true;
417+ if ( o == null || getClass() != o.getClass() ) return false;
418+
419+ DateInterval that = (DateInterval) o;
420+
421+ if ( from != null ? !from.equals( that.from ) : that.from != null ) return false;
422+ if ( to != null ? !to.equals( that.to ) : that.to != null ) return false;
423+ if ( type != that.type ) return false;
424+
425+ return true;
426+ }
427+
428+ @Override
429+ public int hashCode()
430+ {
431+ int result = from != null ? from.hashCode() : 0;
432+ result = 31 * result + (to != null ? to.hashCode() : 0);
433+ result = 31 * result + (type != null ? type.hashCode() : 0);
434+ return result;
435+ }
436+
437+ @Override
438 public String toString()
439 {
440 return "DateInterval{" +
441
442=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateTimeUnit.java'
443--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateTimeUnit.java 1970-01-01 00:00:00 +0000
444+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateTimeUnit.java 2014-06-05 17:39:07 +0000
445@@ -0,0 +1,134 @@
446+package org.hisp.dhis.calendar;
447+
448+/*
449+ * Copyright (c) 2004-2014, University of Oslo
450+ * All rights reserved.
451+ *
452+ * Redistribution and use in source and binary forms, with or without
453+ * modification, are permitted provided that the following conditions are met:
454+ * Redistributions of source code must retain the above copyright notice, this
455+ * list of conditions and the following disclaimer.
456+ *
457+ * Redistributions in binary form must reproduce the above copyright notice,
458+ * this list of conditions and the following disclaimer in the documentation
459+ * and/or other materials provided with the distribution.
460+ * Neither the name of the HISP project nor the names of its contributors may
461+ * be used to endorse or promote products derived from this software without
462+ * specific prior written permission.
463+ *
464+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
465+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
466+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
467+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
468+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
469+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
470+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
471+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
472+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
473+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
474+ */
475+
476+import org.joda.time.DateTime;
477+
478+import java.util.Date;
479+
480+/**
481+ * Simple class that can hold both a TimeUnit and DateUnit which is useful in cases
482+ * where we are converting from a DateTime, Jdk Calendar or Jdk Date and don't want to
483+ * loose either date or time dimension.
484+ *
485+ * @author Morten Olav Hansen <mortenoh@gmail.com>
486+ * @see DateUnit
487+ * @see TimeUnit
488+ * @see org.joda.time.DateTime
489+ * @see java.util.Calendar
490+ * @see java.util.Date
491+ */
492+public class DateTimeUnit
493+{
494+ private DateUnit dateUnit;
495+
496+ private TimeUnit timeUnit;
497+
498+ public DateTimeUnit()
499+ {
500+ }
501+
502+ public DateTimeUnit( DateUnit dateUnit, TimeUnit timeUnit )
503+ {
504+ this.dateUnit = dateUnit;
505+ this.timeUnit = timeUnit;
506+ }
507+
508+ public DateUnit getDateUnit()
509+ {
510+ return dateUnit;
511+ }
512+
513+ public void setDateUnit( DateUnit dateUnit )
514+ {
515+ this.dateUnit = dateUnit;
516+ }
517+
518+ public TimeUnit getTimeUnit()
519+ {
520+ return timeUnit;
521+ }
522+
523+ public void setTimeUnit( TimeUnit timeUnit )
524+ {
525+ this.timeUnit = timeUnit;
526+ }
527+
528+ public static DateTimeUnit fromDateTime( DateTime dateTime )
529+ {
530+ DateUnit dateUnit = DateUnit.fromDateTime( dateTime );
531+ TimeUnit timeUnit = TimeUnit.fromDateTime( dateTime );
532+
533+ return new DateTimeUnit( dateUnit, timeUnit );
534+ }
535+
536+ public static DateTimeUnit fromJdkCalendar( java.util.Calendar calendar )
537+ {
538+ DateUnit dateUnit = DateUnit.fromJdkCalendar( calendar );
539+ TimeUnit timeUnit = TimeUnit.fromJdkCalendar( calendar );
540+
541+ return new DateTimeUnit( dateUnit, timeUnit );
542+ }
543+
544+ public static DateTimeUnit fromJdkDate( Date date )
545+ {
546+ return fromDateTime( new DateTime( date.getTime() ) );
547+ }
548+
549+ @Override
550+ public boolean equals( Object o )
551+ {
552+ if ( this == o ) return true;
553+ if ( o == null || getClass() != o.getClass() ) return false;
554+
555+ DateTimeUnit that = (DateTimeUnit) o;
556+
557+ if ( dateUnit != null ? !dateUnit.equals( that.dateUnit ) : that.dateUnit != null ) return false;
558+ if ( timeUnit != null ? !timeUnit.equals( that.timeUnit ) : that.timeUnit != null ) return false;
559+
560+ return true;
561+ }
562+
563+ @Override
564+ public int hashCode()
565+ {
566+ int result = dateUnit != null ? dateUnit.hashCode() : 0;
567+ result = 31 * result + (timeUnit != null ? timeUnit.hashCode() : 0);
568+ return result;
569+ }
570+
571+ @Override
572+ public String toString()
573+ {
574+ return "DateTimeUnit{" +
575+ "dateUnit=" + dateUnit +
576+ ", timeUnit=" + timeUnit +
577+ '}';
578+ }
579+}
580
581=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnit.java'
582--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnit.java 2014-05-12 16:57:48 +0000
583+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnit.java 2014-06-05 17:39:07 +0000
584@@ -38,9 +38,12 @@
585
586 /**
587 * Class representing a specific calendar date.
588+ *
589 * @author Morten Olav Hansen <mortenoh@gmail.com>
590 * @see DateInterval
591 * @see Calendar
592+ * @see TimeUnit
593+ * @see DateTimeUnit
594 */
595 public class DateUnit
596 {
597@@ -67,29 +70,61 @@
598 */
599 int dayOfWeek;
600
601+ /**
602+ * Does dateUnit represent ISO 8601.
603+ */
604+ final boolean iso8601;
605+
606+ public DateUnit( boolean iso8601 )
607+ {
608+ this.iso8601 = iso8601;
609+ }
610+
611 public DateUnit()
612 {
613+ this( false );
614 }
615
616 public DateUnit( DateUnit dateUnit )
617 {
618- this.year = dateUnit.getYear();
619- this.month = dateUnit.getMonth();
620- this.day = dateUnit.getDay();
621- this.dayOfWeek = dateUnit.getDayOfWeek();
622+ this( dateUnit.isIso8601() );
623+ this.year = dateUnit.getYear();
624+ this.month = dateUnit.getMonth();
625+ this.day = dateUnit.getDay();
626+ this.dayOfWeek = dateUnit.getDayOfWeek();
627+ }
628+
629+ public DateUnit( DateUnit dateUnit, boolean iso8601 )
630+ {
631+ this( iso8601 );
632+ this.year = dateUnit.getYear();
633+ this.month = dateUnit.getMonth();
634+ this.day = dateUnit.getDay();
635+ this.dayOfWeek = dateUnit.getDayOfWeek();
636+ }
637+
638+ public DateUnit( int year, int month, int day, boolean iso8601 )
639+ {
640+ this.year = year;
641+ this.month = month;
642+ this.day = day;
643+ this.iso8601 = iso8601;
644 }
645
646 public DateUnit( int year, int month, int day )
647 {
648- this.year = year;
649- this.month = month;
650- this.day = day;
651+ this( year, month, day, false );
652+ }
653+
654+ public DateUnit( int year, int month, int day, int dayOfWeek, boolean iso8601 )
655+ {
656+ this( year, month, day, iso8601 );
657+ this.dayOfWeek = dayOfWeek;
658 }
659
660 public DateUnit( int year, int month, int day, int dayOfWeek )
661 {
662- this( year, month, day );
663- this.dayOfWeek = dayOfWeek;
664+ this( year, month, day, dayOfWeek, false );
665 }
666
667 public int getYear()
668@@ -132,8 +167,18 @@
669 this.dayOfWeek = dayOfWeek;
670 }
671
672+ public boolean isIso8601()
673+ {
674+ return iso8601;
675+ }
676+
677 public DateTime toDateTime()
678 {
679+ if ( !iso8601 )
680+ {
681+ throw new RuntimeException( "Cannot convert non-ISO8601 DateUnit to DateTime." );
682+ }
683+
684 return new DateTime( year, month, day, 0, 0, ISOChronology.getInstance() );
685 }
686
687@@ -144,7 +189,15 @@
688
689 public java.util.Calendar toJdkCalendar()
690 {
691- return new GregorianCalendar( year, month - 1, day );
692+ if ( !iso8601 )
693+ {
694+ throw new RuntimeException( "Cannot convert non-ISO8601 DateUnit to JDK Calendar." );
695+ }
696+
697+ java.util.Calendar calendar = new GregorianCalendar( year, month - 1, day );
698+ calendar.setTime( calendar.getTime() );
699+
700+ return calendar;
701 }
702
703 public Date toJdkDate()
704@@ -160,12 +213,39 @@
705 public static DateUnit fromJdkCalendar( java.util.Calendar calendar )
706 {
707 return new DateUnit( calendar.get( java.util.Calendar.YEAR ), calendar.get( java.util.Calendar.MONTH ) + 1,
708- calendar.get( java.util.Calendar.DAY_OF_MONTH ), calendar.get( java.util.Calendar.DAY_OF_WEEK ) );
709+ calendar.get( java.util.Calendar.DAY_OF_MONTH ), calendar.get( java.util.Calendar.DAY_OF_WEEK ), true );
710 }
711
712 public static DateUnit fromJdkDate( Date date )
713 {
714- return fromDateTime( new DateTime( date.getTime() ) );
715+ DateUnit dateUnit = fromDateTime( new DateTime( date.getTime() ) );
716+ return new DateUnit( dateUnit, true );
717+ }
718+
719+ @Override
720+ public boolean equals( Object o )
721+ {
722+ if ( this == o ) return true;
723+ if ( o == null || getClass() != o.getClass() ) return false;
724+
725+ DateUnit dateUnit = (DateUnit) o;
726+
727+ if ( day != dateUnit.day ) return false;
728+ if ( iso8601 != dateUnit.iso8601 ) return false;
729+ if ( month != dateUnit.month ) return false;
730+ if ( year != dateUnit.year ) return false;
731+
732+ return true;
733+ }
734+
735+ @Override
736+ public int hashCode()
737+ {
738+ int result = year;
739+ result = 31 * result + month;
740+ result = 31 * result + day;
741+ result = 31 * result + (iso8601 ? 1 : 0);
742+ return result;
743 }
744
745 @Override
746@@ -175,7 +255,7 @@
747 "year=" + year +
748 ", month=" + month +
749 ", day=" + day +
750- ", dayOfWeek=" + dayOfWeek +
751+ ", iso8601=" + iso8601 +
752 '}';
753 }
754 }
755
756=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitPeriodTypeParser.java'
757--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitPeriodTypeParser.java 1970-01-01 00:00:00 +0000
758+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitPeriodTypeParser.java 2014-06-05 17:39:07 +0000
759@@ -0,0 +1,289 @@
760+package org.hisp.dhis.calendar;
761+
762+/*
763+ * Copyright (c) 2004-2014, University of Oslo
764+ * All rights reserved.
765+ *
766+ * Redistribution and use in source and binary forms, with or without
767+ * modification, are permitted provided that the following conditions are met:
768+ * Redistributions of source code must retain the above copyright notice, this
769+ * list of conditions and the following disclaimer.
770+ *
771+ * Redistributions in binary form must reproduce the above copyright notice,
772+ * this list of conditions and the following disclaimer in the documentation
773+ * and/or other materials provided with the distribution.
774+ * Neither the name of the HISP project nor the names of its contributors may
775+ * be used to endorse or promote products derived from this software without
776+ * specific prior written permission.
777+ *
778+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
779+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
780+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
781+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
782+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
783+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
784+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
785+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
786+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
787+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
788+ */
789+
790+import com.google.common.collect.Maps;
791+import org.hisp.dhis.calendar.impl.Iso8601Calendar;
792+
793+import java.util.Map;
794+import java.util.regex.Matcher;
795+import java.util.regex.Pattern;
796+import java.util.regex.PatternSyntaxException;
797+
798+/**
799+ * @author Morten Olav Hansen <mortenoh@gmail.com>
800+ */
801+public class DateUnitPeriodTypeParser implements PeriodTypeParser
802+{
803+ private final Map<String, Pattern> compileCache = Maps.newHashMap();
804+
805+ private static CalendarService calendarService;
806+
807+ public static void setCalendarService( CalendarService calendarService )
808+ {
809+ DateUnitPeriodTypeParser.calendarService = calendarService;
810+ }
811+
812+ public static CalendarService getCalendarService()
813+ {
814+ return calendarService;
815+ }
816+
817+ public static org.hisp.dhis.calendar.Calendar getCalendar()
818+ {
819+ if ( calendarService != null )
820+ {
821+ return calendarService.getSystemCalendar();
822+ }
823+
824+ return Iso8601Calendar.getInstance();
825+ }
826+
827+ @Override
828+ public DateInterval parse( String period )
829+ {
830+ DateUnitType type = DateUnitType.find( period );
831+
832+ if ( type == null )
833+ {
834+ return null;
835+ }
836+
837+ if ( compileCache.get( type.getType() ) == null )
838+ {
839+ try
840+ {
841+ Pattern pattern = Pattern.compile( type.getFormat() );
842+ compileCache.put( type.getType(), pattern );
843+ }
844+ catch ( PatternSyntaxException ex )
845+ {
846+ return null;
847+ }
848+ }
849+
850+ Pattern pattern = compileCache.get( type.getType() );
851+ Matcher matcher = pattern.matcher( period );
852+ boolean match = matcher.find();
853+
854+ if ( !match )
855+ {
856+ return null;
857+ }
858+
859+ if ( DateUnitType.DAILY.equals( type ) )
860+ {
861+ int year = Integer.parseInt( matcher.group( 1 ) );
862+ int month = Integer.parseInt( matcher.group( 2 ) );
863+ int day = Integer.parseInt( matcher.group( 3 ) );
864+
865+ DateUnit dateUnit = new DateUnit( year, month, day );
866+ dateUnit.setDayOfWeek( getCalendar().weekday( dateUnit ) );
867+
868+ return new DateInterval( dateUnit, dateUnit );
869+ }
870+ else if ( DateUnitType.WEEKLY.equals( type ) )
871+ {
872+ int year = Integer.parseInt( matcher.group( 1 ) );
873+ int week = Integer.parseInt( matcher.group( 2 ) );
874+
875+ if ( week < 1 || week > getCalendar().weeksInYear( year ) )
876+ {
877+ return null;
878+ }
879+
880+ DateUnit start = new DateUnit( year, 1, 1 );
881+ start = getCalendar().minusDays( start, getCalendar().weekday( start ) - 1 ); // rewind to start of week
882+
883+ // since we rewind to start of week, we might end up in the previous years weeks, so we check and forward if needed
884+ if ( getCalendar().isoWeek( start ) == getCalendar().weeksInYear( year ) )
885+ {
886+ start = getCalendar().plusWeeks( start, 1 );
887+ }
888+
889+ start = getCalendar().plusWeeks( start, week - 1 );
890+ DateUnit end = new DateUnit( start );
891+ end = getCalendar().plusWeeks( end, 1 );
892+ end = getCalendar().minusDays( end, 1 );
893+
894+ start.setDayOfWeek( getCalendar().weekday( start ) );
895+ end.setDayOfWeek( getCalendar().weekday( end ) );
896+
897+ return new DateInterval( start, end );
898+ }
899+ else if ( DateUnitType.MONTHLY.equals( type ) )
900+ {
901+ int year = Integer.parseInt( matcher.group( 1 ) );
902+ int month = Integer.parseInt( matcher.group( 2 ) );
903+
904+ DateUnit start = new DateUnit( year, month, 1 );
905+ DateUnit end = new DateUnit( year, month, getCalendar().daysInMonth( start.getYear(), start.getMonth() ) );
906+
907+ start.setDayOfWeek( getCalendar().weekday( start ) );
908+ end.setDayOfWeek( getCalendar().weekday( end ) );
909+
910+ return new DateInterval( start, end );
911+ }
912+ else if ( DateUnitType.BI_MONTHLY.equals( type ) )
913+ {
914+ int year = Integer.parseInt( matcher.group( 1 ) );
915+ int month = Integer.parseInt( matcher.group( 2 ) );
916+
917+ DateUnit start = new DateUnit( year, month, 1 );
918+ DateUnit end = new DateUnit( start );
919+ end = getCalendar().plusMonths( end, 2 );
920+ end = getCalendar().minusDays( end, 1 );
921+
922+ start.setDayOfWeek( getCalendar().weekday( start ) );
923+ end.setDayOfWeek( getCalendar().weekday( end ) );
924+
925+ return new DateInterval( start, end );
926+ }
927+ else if ( DateUnitType.QUARTERLY.equals( type ) )
928+ {
929+ int year = Integer.parseInt( matcher.group( 1 ) );
930+ int quarter = Integer.parseInt( matcher.group( 2 ) );
931+
932+ // valid quarters are from 1 - 4
933+ if ( quarter < 1 || quarter > 4 )
934+ {
935+ return null;
936+ }
937+
938+ DateUnit start = new DateUnit( year, ((quarter - 1) * 3) + 1, 1 );
939+ DateUnit end = new DateUnit( start );
940+ end = getCalendar().plusMonths( end, 3 );
941+ end = getCalendar().minusDays( end, 1 );
942+
943+ start.setDayOfWeek( getCalendar().weekday( start ) );
944+ end.setDayOfWeek( getCalendar().weekday( end ) );
945+
946+ return new DateInterval( start, end );
947+ }
948+ else if ( DateUnitType.SIX_MONTHLY.equals( type ) )
949+ {
950+ int year = Integer.parseInt( matcher.group( 1 ) );
951+ int semester = Integer.parseInt( matcher.group( 2 ) );
952+
953+ // valid six-monthly are from 1 - 2
954+ if ( semester < 1 || semester > 2 )
955+ {
956+ return null;
957+ }
958+
959+ DateUnit start = new DateUnit( year, semester == 1 ? 1 : 7, 1 );
960+ DateUnit end = new DateUnit( start );
961+ end = getCalendar().plusMonths( end, 6 );
962+ end = getCalendar().minusDays( end, 1 );
963+
964+ start.setDayOfWeek( getCalendar().weekday( start ) );
965+ end.setDayOfWeek( getCalendar().weekday( end ) );
966+
967+ return new DateInterval( start, end );
968+ }
969+ else if ( DateUnitType.SIX_MONTHLY_APRIL.equals( type ) )
970+ {
971+ int year = Integer.parseInt( matcher.group( 1 ) );
972+ int semester = Integer.parseInt( matcher.group( 2 ) );
973+
974+ // valid six-monthly are from 1 - 2
975+ if ( semester < 1 || semester > 2 )
976+ {
977+ return null;
978+ }
979+
980+ DateUnit start = new DateUnit( year, semester == 1 ? 4 : 10, 1 );
981+ DateUnit end = new DateUnit( start );
982+ end = getCalendar().plusMonths( end, 6 );
983+ end = getCalendar().minusDays( end, 1 );
984+
985+ start.setDayOfWeek( getCalendar().weekday( start ) );
986+ end.setDayOfWeek( getCalendar().weekday( end ) );
987+
988+ return new DateInterval( start, end );
989+ }
990+ else if ( DateUnitType.YEARLY.equals( type ) )
991+ {
992+ int year = Integer.parseInt( matcher.group( 1 ) );
993+
994+ DateUnit start = new DateUnit( year, 1, 1 );
995+ DateUnit end = new DateUnit( year, getCalendar().monthsInYear(),
996+ getCalendar().daysInMonth( start.getYear(), getCalendar().monthsInYear() ) );
997+
998+ start.setDayOfWeek( getCalendar().weekday( start ) );
999+ end.setDayOfWeek( getCalendar().weekday( end ) );
1000+
1001+ return new DateInterval( start, end );
1002+ }
1003+ else if ( DateUnitType.FINANCIAL_APRIL.equals( type ) )
1004+ {
1005+ int year = Integer.parseInt( matcher.group( 1 ) );
1006+
1007+ DateUnit start = new DateUnit( year, 4, 1 );
1008+ DateUnit end = new DateUnit( start );
1009+ end = getCalendar().plusYears( end, 1 );
1010+ end = getCalendar().minusDays( end, 1 );
1011+
1012+ start.setDayOfWeek( getCalendar().weekday( start ) );
1013+ end.setDayOfWeek( getCalendar().weekday( end ) );
1014+
1015+ return new DateInterval( start, end );
1016+ }
1017+ else if ( DateUnitType.FINANCIAL_JULY.equals( type ) )
1018+ {
1019+ int year = Integer.parseInt( matcher.group( 1 ) );
1020+
1021+ DateUnit start = new DateUnit( year, 7, 1 );
1022+ DateUnit end = new DateUnit( start );
1023+ end = getCalendar().plusYears( end, 1 );
1024+ end = getCalendar().minusDays( end, 1 );
1025+
1026+ start.setDayOfWeek( getCalendar().weekday( start ) );
1027+ end.setDayOfWeek( getCalendar().weekday( end ) );
1028+
1029+ return new DateInterval( start, end );
1030+ }
1031+ else if ( DateUnitType.FINANCIAL_OCTOBER.equals( type ) )
1032+ {
1033+ int year = Integer.parseInt( matcher.group( 1 ) );
1034+
1035+ DateUnit start = new DateUnit( year, 10, 1 );
1036+ DateUnit end = new DateUnit( start );
1037+ end = getCalendar().plusYears( end, 1 );
1038+ end = getCalendar().minusDays( end, 1 );
1039+
1040+ start.setDayOfWeek( getCalendar().weekday( start ) );
1041+ end.setDayOfWeek( getCalendar().weekday( end ) );
1042+
1043+ return new DateInterval( start, end );
1044+ }
1045+
1046+ return null;
1047+ }
1048+}
1049
1050=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitType.java'
1051--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitType.java 1970-01-01 00:00:00 +0000
1052+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitType.java 2014-06-05 17:39:07 +0000
1053@@ -0,0 +1,92 @@
1054+package org.hisp.dhis.calendar;
1055+
1056+/*
1057+ * Copyright (c) 2004-2014, University of Oslo
1058+ * All rights reserved.
1059+ *
1060+ * Redistribution and use in source and binary forms, with or without
1061+ * modification, are permitted provided that the following conditions are met:
1062+ * Redistributions of source code must retain the above copyright notice, this
1063+ * list of conditions and the following disclaimer.
1064+ *
1065+ * Redistributions in binary form must reproduce the above copyright notice,
1066+ * this list of conditions and the following disclaimer in the documentation
1067+ * and/or other materials provided with the distribution.
1068+ * Neither the name of the HISP project nor the names of its contributors may
1069+ * be used to endorse or promote products derived from this software without
1070+ * specific prior written permission.
1071+ *
1072+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1073+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1074+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1075+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
1076+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1077+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1078+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1079+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1080+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1081+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1082+ */
1083+
1084+import org.hisp.dhis.period.BiMonthlyPeriodType;
1085+import org.hisp.dhis.period.DailyPeriodType;
1086+import org.hisp.dhis.period.FinancialAprilPeriodType;
1087+import org.hisp.dhis.period.FinancialJulyPeriodType;
1088+import org.hisp.dhis.period.FinancialOctoberPeriodType;
1089+import org.hisp.dhis.period.MonthlyPeriodType;
1090+import org.hisp.dhis.period.QuarterlyPeriodType;
1091+import org.hisp.dhis.period.SixMonthlyAprilPeriodType;
1092+import org.hisp.dhis.period.SixMonthlyPeriodType;
1093+import org.hisp.dhis.period.WeeklyPeriodType;
1094+import org.hisp.dhis.period.YearlyPeriodType;
1095+
1096+/**
1097+ * @author Morten Olav Hansen <mortenoh@gmail.com>
1098+ */
1099+public enum DateUnitType
1100+{
1101+ DAILY( DailyPeriodType.NAME, "\\b(\\d{4})(\\d{2})(\\d{2})\\b" ),
1102+ WEEKLY( WeeklyPeriodType.NAME, "\\b(\\d{4})W(\\d[\\d]?)\\b" ),
1103+ MONTHLY( MonthlyPeriodType.NAME, "\\b(\\d{4})[-]?(\\d{2})\\b" ),
1104+ BI_MONTHLY( BiMonthlyPeriodType.NAME, "\\b(\\d{4})(\\d{2})B\\b" ),
1105+ QUARTERLY( QuarterlyPeriodType.NAME, "\\b(\\d{4})Q(\\d)\\b" ),
1106+ SIX_MONTHLY( SixMonthlyPeriodType.NAME, "\\b(\\d{4})S(\\d)\\b" ),
1107+ SIX_MONTHLY_APRIL( SixMonthlyAprilPeriodType.NAME, "\\b(\\d{4})AprilS(\\d)\\b" ),
1108+ YEARLY( YearlyPeriodType.NAME, "\\b(\\d{4})\\b" ),
1109+ FINANCIAL_APRIL( FinancialAprilPeriodType.NAME, "\\b(\\d{4})April\\b" ),
1110+ FINANCIAL_JULY( FinancialJulyPeriodType.NAME, "\\b(\\d{4})July\\b" ),
1111+ FINANCIAL_OCTOBER( FinancialOctoberPeriodType.NAME, "\\b(\\d{4})Oct\\b" );
1112+
1113+ private final String type;
1114+
1115+ private final String format;
1116+
1117+ public String getType()
1118+ {
1119+ return type;
1120+ }
1121+
1122+ public String getFormat()
1123+ {
1124+ return format;
1125+ }
1126+
1127+ DateUnitType( String type, String format )
1128+ {
1129+ this.type = type;
1130+ this.format = format;
1131+ }
1132+
1133+ public static DateUnitType find( String format )
1134+ {
1135+ for ( DateUnitType type : DateUnitType.values() )
1136+ {
1137+ if ( format.matches( type.format ) )
1138+ {
1139+ return type;
1140+ }
1141+ }
1142+
1143+ return null;
1144+ }
1145+}
1146
1147=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/PeriodTypeParser.java'
1148--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/PeriodTypeParser.java 1970-01-01 00:00:00 +0000
1149+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/PeriodTypeParser.java 2014-06-05 17:39:07 +0000
1150@@ -0,0 +1,37 @@
1151+package org.hisp.dhis.calendar;
1152+
1153+/*
1154+ * Copyright (c) 2004-2014, University of Oslo
1155+ * All rights reserved.
1156+ *
1157+ * Redistribution and use in source and binary forms, with or without
1158+ * modification, are permitted provided that the following conditions are met:
1159+ * Redistributions of source code must retain the above copyright notice, this
1160+ * list of conditions and the following disclaimer.
1161+ *
1162+ * Redistributions in binary form must reproduce the above copyright notice,
1163+ * this list of conditions and the following disclaimer in the documentation
1164+ * and/or other materials provided with the distribution.
1165+ * Neither the name of the HISP project nor the names of its contributors may
1166+ * be used to endorse or promote products derived from this software without
1167+ * specific prior written permission.
1168+ *
1169+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1170+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1171+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1172+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
1173+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1174+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1175+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1176+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1177+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1178+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1179+ */
1180+
1181+/**
1182+ * @author Morten Olav Hansen <mortenoh@gmail.com>
1183+ */
1184+public interface PeriodTypeParser
1185+{
1186+ public DateInterval parse( String period );
1187+}
1188
1189=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/TimeUnit.java'
1190--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/TimeUnit.java 1970-01-01 00:00:00 +0000
1191+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/TimeUnit.java 2014-06-05 17:39:07 +0000
1192@@ -0,0 +1,154 @@
1193+package org.hisp.dhis.calendar;
1194+
1195+/*
1196+ * Copyright (c) 2004-2014, University of Oslo
1197+ * All rights reserved.
1198+ *
1199+ * Redistribution and use in source and binary forms, with or without
1200+ * modification, are permitted provided that the following conditions are met:
1201+ * Redistributions of source code must retain the above copyright notice, this
1202+ * list of conditions and the following disclaimer.
1203+ *
1204+ * Redistributions in binary form must reproduce the above copyright notice,
1205+ * this list of conditions and the following disclaimer in the documentation
1206+ * and/or other materials provided with the distribution.
1207+ * Neither the name of the HISP project nor the names of its contributors may
1208+ * be used to endorse or promote products derived from this software without
1209+ * specific prior written permission.
1210+ *
1211+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1212+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1213+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1214+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
1215+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1216+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1217+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1218+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1219+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1220+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1221+ */
1222+
1223+import org.joda.time.DateTime;
1224+
1225+import java.util.Calendar;
1226+import java.util.Date;
1227+
1228+/**
1229+ * Simple class to hold information about time, can be used together with DateUnit to form
1230+ * a DateTimeUnit which holds both date and time information. Useful in cases where converting
1231+ * from a JDK Date/Calendar and you don't want to loose the time dimension.
1232+ *
1233+ * @author Morten Olav Hansen <mortenoh@gmail.com>
1234+ * @see DateUnit
1235+ * @see DateTimeUnit
1236+ */
1237+public class TimeUnit
1238+{
1239+ /**
1240+ * Hour of day, range is 1 - 24.
1241+ */
1242+ private int hour;
1243+
1244+ /**
1245+ * Minute of day, range is 0 - 59.
1246+ */
1247+ private int minute;
1248+
1249+ /**
1250+ * Second of day, range is 0 - 59.
1251+ */
1252+ private int second;
1253+
1254+ public TimeUnit()
1255+ {
1256+ }
1257+
1258+ public TimeUnit( int hour, int minute, int second )
1259+ {
1260+ this.hour = hour;
1261+ this.minute = minute;
1262+ this.second = second;
1263+ }
1264+
1265+ public int getHour()
1266+ {
1267+ return hour;
1268+ }
1269+
1270+ public void setHour( int hour )
1271+ {
1272+ this.hour = hour;
1273+ }
1274+
1275+ public int getMinute()
1276+ {
1277+ return minute;
1278+ }
1279+
1280+ public void setMinute( int minute )
1281+ {
1282+ this.minute = minute;
1283+ }
1284+
1285+ public int getSecond()
1286+ {
1287+ return second;
1288+ }
1289+
1290+ public void setSecond( int second )
1291+ {
1292+ this.second = second;
1293+ }
1294+
1295+ public static TimeUnit fromDateTime( DateTime dateTime )
1296+ {
1297+ return new TimeUnit( dateTime.getHourOfDay(), dateTime.getMinuteOfHour(), dateTime.getSecondOfMinute() );
1298+ }
1299+
1300+ public static TimeUnit fromJdkCalendar( Calendar calendar )
1301+ {
1302+ int amPm = calendar.get( Calendar.AM_PM );
1303+
1304+ return new TimeUnit( calendar.get( Calendar.HOUR ) + (amPm * 12), calendar.get( Calendar.MINUTE ),
1305+ calendar.get( Calendar.SECOND ) );
1306+ }
1307+
1308+ public static TimeUnit fromJdkDate( Date date )
1309+ {
1310+ return fromDateTime( new DateTime( date.getTime() ) );
1311+ }
1312+
1313+ @Override
1314+ public boolean equals( Object o )
1315+ {
1316+ if ( this == o ) return true;
1317+ if ( o == null || getClass() != o.getClass() ) return false;
1318+
1319+ TimeUnit timeUnit = (TimeUnit) o;
1320+
1321+ if ( hour != timeUnit.hour ) return false;
1322+ if ( minute != timeUnit.minute ) return false;
1323+ if ( second != timeUnit.second ) return false;
1324+
1325+ return true;
1326+ }
1327+
1328+ @Override
1329+ public int hashCode()
1330+ {
1331+ int result = hour;
1332+ result = 31 * result + minute;
1333+ result = 31 * result + second;
1334+ return result;
1335+ }
1336+
1337+ @Override
1338+ public String toString()
1339+ {
1340+ return "TimeUnit{" +
1341+ "hour=" + hour +
1342+ ", minute=" + minute +
1343+ ", second=" + second +
1344+ '}';
1345+ }
1346+}
1347
1348=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/impl/NepaliCalendar.java'
1349--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/impl/NepaliCalendar.java 2014-05-12 07:52:08 +0000
1350+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/impl/NepaliCalendar.java 2014-06-05 17:39:07 +0000
1351@@ -49,7 +49,7 @@
1352 {
1353 private static final DateUnit startNepal = new DateUnit( 2000, 1, 1, java.util.Calendar.WEDNESDAY );
1354
1355- private static final DateUnit startIso = new DateUnit( 1943, 4, 14, java.util.Calendar.WEDNESDAY );
1356+ private static final DateUnit startIso = new DateUnit( 1943, 4, 14, java.util.Calendar.WEDNESDAY, true );
1357
1358 private static final Calendar self = new NepaliCalendar();
1359
1360@@ -85,7 +85,7 @@
1361
1362 dateTime = dateTime.plusDays( totalDays );
1363
1364- return DateUnit.fromDateTime( dateTime );
1365+ return new DateUnit( DateUnit.fromDateTime( dateTime ), true );
1366 }
1367
1368 @Override
1369@@ -219,6 +219,13 @@
1370 }
1371
1372 @Override
1373+ public int weeksInYear( int year )
1374+ {
1375+ DateTime dateTime = new DateTime( year, 1, 1, 0, 0, ISOChronology.getInstance() );
1376+ return dateTime.weekOfWeekyear().getMaximumValue();
1377+ }
1378+
1379+ @Override
1380 public int isoWeek( DateUnit dateUnit )
1381 {
1382 DateTime dateTime = toIso( dateUnit ).toDateTime( ISOChronology.getInstance() );
1383
1384=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/AuditLogUtil.java'
1385--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/AuditLogUtil.java 2014-03-18 08:10:10 +0000
1386+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/AuditLogUtil.java 2014-06-05 17:39:07 +0000
1387@@ -28,6 +28,7 @@
1388 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1389 */
1390
1391+import javassist.util.proxy.ProxyFactory;
1392 import org.apache.commons.logging.Log;
1393
1394 public class AuditLogUtil
1395@@ -52,7 +53,15 @@
1396 StringBuilder builder = new StringBuilder();
1397
1398 builder.append( "'" ).append( username ).append( "' " ).append( action );
1399- builder.append( " " ).append( object.getClass().getName() );
1400+
1401+ if ( !ProxyFactory.isProxyClass( object.getClass() ) )
1402+ {
1403+ builder.append( " " ).append( object.getClass().getName() );
1404+ }
1405+ else
1406+ {
1407+ builder.append( " " ).append( object.getClass().getSuperclass().getName() );
1408+ }
1409
1410 if ( idObject.getName() != null && !idObject.getName().isEmpty() )
1411 {
1412
1413=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionService.java'
1414--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionService.java 2014-03-18 08:10:10 +0000
1415+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionService.java 2014-06-05 17:39:07 +0000
1416@@ -30,6 +30,8 @@
1417
1418 import java.util.List;
1419
1420+import org.hisp.dhis.user.User;
1421+
1422 /**
1423 * @author Lars Helge Overland
1424 */
1425@@ -39,9 +41,13 @@
1426
1427 List<NameableObject> getCanReadDimensionItems( String uid );
1428
1429+ <T extends IdentifiableObject> List<T> filterCanRead( User user, List<T> objects );
1430+
1431 DimensionType getDimensionType( String uid );
1432
1433 List<DimensionalObject> getAllDimensions();
1434
1435+ List<DimensionalObject> getDimensionConstraints();
1436+
1437 void mergeAnalyticalObject( BaseAnalyticalObject object );
1438 }
1439
1440=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/ListMap.java'
1441--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/ListMap.java 2014-03-18 08:10:10 +0000
1442+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/ListMap.java 2014-06-05 17:39:07 +0000
1443@@ -31,6 +31,7 @@
1444 import java.util.ArrayList;
1445 import java.util.HashMap;
1446 import java.util.List;
1447+import java.util.Map;
1448
1449 /**
1450 * @author Lars Helge Overland
1451@@ -38,6 +39,11 @@
1452 public class ListMap<T, V>
1453 extends HashMap<T, List<V>>
1454 {
1455+ /**
1456+ * Determines if a de-serialized file is compatible with this class.
1457+ */
1458+ private static final long serialVersionUID = 4880664228933342003L;
1459+
1460 public ListMap()
1461 {
1462 super();
1463@@ -56,4 +62,12 @@
1464 super.put( key, list );
1465 return null;
1466 }
1467+
1468+ public void putValueMap( Map<T, V> map )
1469+ {
1470+ for ( Map.Entry<T, V> entry : map.entrySet() )
1471+ {
1472+ putValue( entry.getKey(), entry.getValue() );
1473+ }
1474+ }
1475 }
1476
1477=== renamed file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/MapMap.java' => 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/MapMap.java'
1478--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/MapMap.java 2014-03-18 08:10:10 +0000
1479+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/MapMap.java 2014-06-05 17:39:07 +0000
1480@@ -1,4 +1,4 @@
1481-package org.hisp.dhis.system.util;
1482+package org.hisp.dhis.common;
1483
1484 /*
1485 * Copyright (c) 2004-2014, University of Oslo
1486@@ -52,4 +52,9 @@
1487 map.putAll( m );
1488 this.put( key, map );
1489 }
1490+
1491+ public V getValue( T key, U valueKey )
1492+ {
1493+ return this.get( key ) == null ? null : this.get( key ).get( valueKey );
1494+ }
1495 }
1496
1497=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SetMap.java'
1498--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SetMap.java 2014-03-18 08:10:10 +0000
1499+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SetMap.java 2014-06-05 17:39:07 +0000
1500@@ -55,4 +55,11 @@
1501 set.add( value );
1502 return super.put( key, set );
1503 }
1504+
1505+ public Set<V> getSet( T key )
1506+ {
1507+ Set<V> set = this.get( key );
1508+ set = set == null ? new HashSet<V>() : set;
1509+ return super.put( key, set );
1510+ }
1511 }
1512
1513=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementCategoryOption.java'
1514--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementCategoryOption.java 2014-04-25 11:22:12 +0000
1515+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementCategoryOption.java 2014-06-05 17:39:07 +0000
1516@@ -28,6 +28,7 @@
1517 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1518 */
1519
1520+import java.util.Date;
1521 import java.util.HashSet;
1522 import java.util.Set;
1523
1524@@ -59,6 +60,10 @@
1525
1526 public static final String DEFAULT_NAME = "default";
1527
1528+ private Date startDate;
1529+
1530+ private Date endDate;
1531+
1532 private Set<DataElementCategory> categories = new HashSet<DataElementCategory>();
1533
1534 @Scanned
1535@@ -152,6 +157,30 @@
1536 }
1537
1538 @JsonProperty
1539+ @JsonView( {DetailedView.class } )
1540+ public Date getStartDate()
1541+ {
1542+ return startDate;
1543+ }
1544+
1545+ public void setStartDate( Date startDate )
1546+ {
1547+ this.startDate = startDate;
1548+ }
1549+
1550+ @JsonProperty
1551+ @JsonView( {DetailedView.class } )
1552+ public Date getEndDate()
1553+ {
1554+ return endDate;
1555+ }
1556+
1557+ public void setEndDate( Date endDate )
1558+ {
1559+ this.endDate = endDate;
1560+ }
1561+
1562+ @JsonProperty
1563 @JsonSerialize(contentAs = BaseIdentifiableObject.class)
1564 @JsonView({ DetailedView.class })
1565 @JacksonXmlElementWrapper(localName = "categories", namespace = DxfNamespaces.DXF_2_0)
1566
1567=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java'
1568--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java 2014-04-17 14:19:13 +0000
1569+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java 2014-06-05 17:39:07 +0000
1570@@ -30,9 +30,12 @@
1571
1572 import java.util.Collection;
1573 import java.util.Date;
1574-import java.util.Map;
1575+import java.util.Set;
1576
1577+import org.hisp.dhis.common.MapMap;
1578+import org.hisp.dhis.dataelement.CategoryOptionGroup;
1579 import org.hisp.dhis.dataelement.DataElement;
1580+import org.hisp.dhis.dataelement.DataElementCategoryOption;
1581 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
1582 import org.hisp.dhis.dataelement.DataElementOperand;
1583 import org.hisp.dhis.organisationunit.OrganisationUnit;
1584@@ -296,33 +299,26 @@
1585 * @return the number of DataValues.
1586 */
1587 int getDataValueCount( int days );
1588-
1589- /**
1590- * Returns a map of values indexed by DataElementOperand.
1591- *
1592- * @param dataElements collection of DataElements to fetch for
1593- * @param period period for which to fetch the values
1594- * @param unit OrganisationUnit for which to fetch the values
1595- * @return
1596- */
1597- Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Period period, OrganisationUnit source );
1598
1599 /**
1600- * Returns a map of values indexed by DataElementOperand.
1601- *
1602+ * Returns a map of values for each attribute option combo found.
1603+ * <p>
1604 * In the (unlikely) event that the same dataElement/optionCombo is found in
1605- * more than one period for the same organisationUnit and date, the value
1606- * is returned from the period with the shortest duration.
1607- *
1608+ * more than one period for the same organisationUnit, date, and attribute
1609+ * combo, the value is returned from the period with the shortest duration.
1610+ *
1611 * @param dataElements collection of DataElements to fetch for
1612 * @param date date which must be present in the period
1613- * @param unit OrganisationUnit for which to fetch the values
1614+ * @param source OrganisationUnit for which to fetch the values
1615 * @param periodTypes allowable period types in which to find the data
1616+ * @param attributeCombo the attribute combo to check (if restricted)
1617 * @param lastUpdatedMap map in which to return the lastUpdated date for each value
1618- * @return
1619+ * @return map of values by attribute option combo id, then DataElementOperand
1620 */
1621- Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Date date, OrganisationUnit source,
1622- Collection<PeriodType> periodTypes, Map<DataElementOperand, Date> lastUpdatedMap );
1623+ MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date,
1624+ OrganisationUnit source, Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo,
1625+ Set<CategoryOptionGroup> cogDimensionConstraints, Set<DataElementCategoryOption> coDimensionConstraints,
1626+ MapMap<Integer, DataElementOperand, Date> lastUpdatedMap );
1627
1628 /**
1629 * Gets a Collection of DeflatedDataValues.
1630
1631=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java'
1632--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java 2014-03-18 08:10:10 +0000
1633+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java 2014-06-05 17:39:07 +0000
1634@@ -30,9 +30,12 @@
1635
1636 import java.util.Collection;
1637 import java.util.Date;
1638-import java.util.Map;
1639+import java.util.Set;
1640
1641+import org.hisp.dhis.common.MapMap;
1642+import org.hisp.dhis.dataelement.CategoryOptionGroup;
1643 import org.hisp.dhis.dataelement.DataElement;
1644+import org.hisp.dhis.dataelement.DataElementCategoryOption;
1645 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
1646 import org.hisp.dhis.dataelement.DataElementOperand;
1647 import org.hisp.dhis.organisationunit.OrganisationUnit;
1648@@ -229,19 +232,19 @@
1649 * collection of Periods, and collection of Sources.
1650 *
1651 * @param dataElement the DataElements of the DataValues.
1652- * @param optionCombo the DataElementCategoryOptionCombo of the DataValues.
1653+ * @param categoryOptionCombo the DataElementCategoryOptionCombo of the DataValues.
1654 * @param periods the Periods of the DataValues.
1655 * @param sources the Sources of the DataValues.
1656 * @return a collection of all DataValues which match the given DataElement,
1657 * Periods, and Sources.
1658 */
1659- Collection<DataValue> getDataValues( DataElement dataElement, DataElementCategoryOptionCombo categoryOptionCombos,
1660+ Collection<DataValue> getDataValues( DataElement dataElement, DataElementCategoryOptionCombo categoryOptionCombo,
1661 Collection<Period> periods, Collection<OrganisationUnit> sources );
1662
1663 /**
1664 * Returns all DataValues for a given collection of DataElementCategoryOptionCombos.
1665 *
1666- * @param optionCombos the DataElementCategoryOptionCombos of the DataValue.
1667+ * @param categoryOptionCombos the DataElementCategoryOptionCombos of the DataValue.
1668 * @return a collection of all DataValues which match the given collection of
1669 * DataElementCategoryOptionCombos.
1670 */
1671@@ -273,34 +276,26 @@
1672 * @return the number of DataValues.
1673 */
1674 int getDataValueCount( Date date );
1675-
1676- /**
1677- * Returns a map of values indexed by DataElementOperand.
1678- *
1679- * @param dataElements collection of DataElements to fetch for
1680- * @param period period for which to fetch the values
1681- * @param unit OrganisationUnit for which to fetch the values
1682- * @param lastUpdatedMap optional map in which to return the lastUpdated date for each value
1683- * @return
1684- */
1685- Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Period period, OrganisationUnit source );
1686
1687 /**
1688- * Returns a map of values indexed by DataElementOperand.
1689- *
1690+ * Returns a map of values for each attribute option combo found.
1691+ * <p>
1692 * In the (unlikely) event that the same dataElement/optionCombo is found in
1693- * more than one period for the same organisationUnit and date, the value
1694- * is returned from the period with the shortest duration.
1695+ * more than one period for the same organisationUnit, date, and attribute
1696+ * combo, the value is returned from the period with the shortest duration.
1697 *
1698 * @param dataElements collection of DataElements to fetch for
1699 * @param date date which must be present in the period
1700- * @param unit OrganisationUnit for which to fetch the values
1701+ * @param source OrganisationUnit for which to fetch the values
1702 * @param periodTypes allowable period types in which to find the data
1703+ * @param attributeCombo the attribute combo to check (if restricted)
1704 * @param lastUpdatedMap map in which to return the lastUpdated date for each value
1705- * @return
1706+ * @return map of values by attribute option combo id, then DataElementOperand
1707 */
1708- Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Date date, OrganisationUnit source,
1709- Collection<PeriodType> periodTypes, Map<DataElementOperand, Date> lastUpdatedMap );
1710+ public MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date,
1711+ OrganisationUnit source, Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo,
1712+ Set<CategoryOptionGroup> cogDimensionConstraints, Set<DataElementCategoryOption> coDimensionConstraints,
1713+ MapMap<Integer, DataElementOperand, Date> lastUpdatedMap );
1714
1715 /**
1716 * Gets a Collection of DeflatedDataValues.
1717
1718=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/eventreport/EventReport.java'
1719--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/eventreport/EventReport.java 2014-05-12 23:03:35 +0000
1720+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/eventreport/EventReport.java 2014-06-05 17:39:07 +0000
1721@@ -28,10 +28,11 @@
1722 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1723 */
1724
1725-import java.util.ArrayList;
1726-import java.util.Date;
1727-import java.util.List;
1728-
1729+import com.fasterxml.jackson.annotation.JsonProperty;
1730+import com.fasterxml.jackson.annotation.JsonView;
1731+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
1732+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
1733+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
1734 import org.hisp.dhis.common.BaseAnalyticalObject;
1735 import org.hisp.dhis.common.BaseIdentifiableObject;
1736 import org.hisp.dhis.common.DxfNamespaces;
1737@@ -45,11 +46,9 @@
1738 import org.hisp.dhis.program.ProgramStage;
1739 import org.hisp.dhis.user.User;
1740
1741-import com.fasterxml.jackson.annotation.JsonProperty;
1742-import com.fasterxml.jackson.annotation.JsonView;
1743-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
1744-import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
1745-import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
1746+import java.util.ArrayList;
1747+import java.util.Date;
1748+import java.util.List;
1749
1750 /**
1751 * @author Lars Helge Overland
1752@@ -183,39 +182,6 @@
1753 }
1754 }
1755
1756- @Override
1757- public void mergeWith( IdentifiableObject other )
1758- {
1759- super.mergeWith( other );
1760-
1761- if ( other.getClass().isInstance( this ) )
1762- {
1763- EventReport report = (EventReport) other;
1764-
1765- dataType = report.getDataType();
1766- program = report.getProgram();
1767- programStage = report.getProgramStage();
1768- startDate = report.getStartDate();
1769- endDate = report.getEndDate();
1770- totals = report.isTotals();
1771- subtotals = report.isSubtotals();
1772- hideEmptyRows = report.isHideEmptyRows();
1773- countType = report.getCountType();
1774- showHierarchy = report.isShowHierarchy();
1775- displayDensity = report.getDisplayDensity();
1776- fontSize = report.getFontSize();
1777-
1778- columnDimensions.clear();
1779- columnDimensions.addAll( report.getColumnDimensions() );
1780-
1781- rowDimensions.clear();
1782- rowDimensions.addAll( report.getRowDimensions() );
1783-
1784- filterDimensions.clear();
1785- filterDimensions.addAll( report.getFilterDimensions() );
1786- }
1787- }
1788-
1789 // -------------------------------------------------------------------------
1790 // Getters and setters
1791 // -------------------------------------------------------------------------
1792@@ -419,4 +385,37 @@
1793 {
1794 this.fontSize = fontSize;
1795 }
1796+
1797+ @Override
1798+ public void mergeWith( IdentifiableObject other )
1799+ {
1800+ super.mergeWith( other );
1801+
1802+ if ( other.getClass().isInstance( this ) )
1803+ {
1804+ EventReport eventReport = (EventReport) other;
1805+
1806+ dataType = eventReport.getDataType();
1807+ program = eventReport.getProgram();
1808+ programStage = eventReport.getProgramStage();
1809+ startDate = eventReport.getStartDate();
1810+ endDate = eventReport.getEndDate();
1811+ totals = eventReport.isTotals();
1812+ subtotals = eventReport.isSubtotals();
1813+ hideEmptyRows = eventReport.isHideEmptyRows();
1814+ countType = eventReport.getCountType();
1815+ showHierarchy = eventReport.isShowHierarchy();
1816+ displayDensity = eventReport.getDisplayDensity();
1817+ fontSize = eventReport.getFontSize();
1818+
1819+ columnDimensions.clear();
1820+ columnDimensions.addAll( eventReport.getColumnDimensions() );
1821+
1822+ rowDimensions.clear();
1823+ rowDimensions.addAll( eventReport.getRowDimensions() );
1824+
1825+ filterDimensions.clear();
1826+ filterDimensions.addAll( eventReport.getFilterDimensions() );
1827+ }
1828+ }
1829 }
1830
1831=== added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node'
1832=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java'
1833--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java 1970-01-01 00:00:00 +0000
1834+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java 2014-06-05 17:39:07 +0000
1835@@ -0,0 +1,178 @@
1836+package org.hisp.dhis.node;
1837+
1838+/*
1839+ * Copyright (c) 2004-2014, University of Oslo
1840+ * All rights reserved.
1841+ *
1842+ * Redistribution and use in source and binary forms, with or without
1843+ * modification, are permitted provided that the following conditions are met:
1844+ * Redistributions of source code must retain the above copyright notice, this
1845+ * list of conditions and the following disclaimer.
1846+ *
1847+ * Redistributions in binary form must reproduce the above copyright notice,
1848+ * this list of conditions and the following disclaimer in the documentation
1849+ * and/or other materials provided with the distribution.
1850+ * Neither the name of the HISP project nor the names of its contributors may
1851+ * be used to endorse or promote products derived from this software without
1852+ * specific prior written permission.
1853+ *
1854+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1855+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1856+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1857+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
1858+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1859+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1860+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1861+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1862+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1863+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
1864+ */
1865+
1866+import com.google.common.collect.ImmutableList;
1867+import com.google.common.collect.Lists;
1868+import org.hisp.dhis.node.exception.InvalidTypeException;
1869+
1870+import java.util.List;
1871+
1872+/**
1873+ * @author Morten Olav Hansen <mortenoh@gmail.com>
1874+ */
1875+public abstract class AbstractNode implements Node
1876+{
1877+ private String name;
1878+
1879+ private final NodeType nodeType;
1880+
1881+ private String namespace;
1882+
1883+ private String comment;
1884+
1885+ private List<Node> children = Lists.newArrayList();
1886+
1887+ protected AbstractNode( String name, NodeType nodeType )
1888+ {
1889+ this.name = name;
1890+ this.nodeType = nodeType;
1891+ }
1892+
1893+ @Override
1894+ public String getName()
1895+ {
1896+ return name;
1897+ }
1898+
1899+ public void setName( String name )
1900+ {
1901+ this.name = name;
1902+ }
1903+
1904+ @Override
1905+ public NodeType getType()
1906+ {
1907+ return nodeType;
1908+ }
1909+
1910+ @Override
1911+ public boolean is( NodeType type )
1912+ {
1913+ return type.equals( nodeType );
1914+ }
1915+
1916+ @Override
1917+ public boolean isSimple()
1918+ {
1919+ return is( NodeType.SIMPLE );
1920+ }
1921+
1922+ @Override
1923+ public boolean isComplex()
1924+ {
1925+ return is( NodeType.COMPLEX );
1926+ }
1927+
1928+ @Override
1929+ public boolean isCollection()
1930+ {
1931+ return is( NodeType.COLLECTION );
1932+ }
1933+
1934+ @Override
1935+ public String getNamespace()
1936+ {
1937+ return namespace;
1938+ }
1939+
1940+ public void setNamespace( String namespace )
1941+ {
1942+ this.namespace = namespace;
1943+ }
1944+
1945+ @Override
1946+ public String getComment()
1947+ {
1948+ return comment;
1949+ }
1950+
1951+ public void setComment( String comment )
1952+ {
1953+ this.comment = comment;
1954+ }
1955+
1956+ @Override
1957+ public <T extends Node> T addChild( T child ) throws InvalidTypeException
1958+ {
1959+ if ( child == null || child.getName() == null )
1960+ {
1961+ return null;
1962+ }
1963+
1964+ children.add( child );
1965+ return child;
1966+ }
1967+
1968+ @Override
1969+ public <T extends Node> void addChildren( Iterable<T> children )
1970+ {
1971+ for ( Node child : children )
1972+ {
1973+ addChild( child );
1974+ }
1975+ }
1976+
1977+ @Override
1978+ public List<Node> getChildren()
1979+ {
1980+ return ImmutableList.copyOf( children );
1981+ }
1982+
1983+ @Override
1984+ public boolean equals( Object o )
1985+ {
1986+ if ( this == o ) return true;
1987+ if ( o == null || getClass() != o.getClass() ) return false;
1988+
1989+ AbstractNode that = (AbstractNode) o;
1990+
1991+ if ( name != null ? !name.equals( that.name ) : that.name != null ) return false;
1992+
1993+ return true;
1994+ }
1995+
1996+ @Override
1997+ public int hashCode()
1998+ {
1999+ return name != null ? name.hashCode() : 0;
2000+ }
2001+
2002+ @Override
2003+ public String toString()
2004+ {
2005+ return "Node{" +
2006+ "name='" + name + '\'' +
2007+ ", nodeType=" + nodeType +
2008+ ", namespace='" + namespace + '\'' +
2009+ ", comment='" + comment + '\'' +
2010+ ", children=" + children +
2011+ '}';
2012+ }
2013+}
2014
2015=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Node.java'
2016--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Node.java 1970-01-01 00:00:00 +0000
2017+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Node.java 2014-06-05 17:39:07 +0000
2018@@ -0,0 +1,124 @@
2019+package org.hisp.dhis.node;
2020+
2021+/*
2022+ * Copyright (c) 2004-2014, University of Oslo
2023+ * All rights reserved.
2024+ *
2025+ * Redistribution and use in source and binary forms, with or without
2026+ * modification, are permitted provided that the following conditions are met:
2027+ * Redistributions of source code must retain the above copyright notice, this
2028+ * list of conditions and the following disclaimer.
2029+ *
2030+ * Redistributions in binary form must reproduce the above copyright notice,
2031+ * this list of conditions and the following disclaimer in the documentation
2032+ * and/or other materials provided with the distribution.
2033+ * Neither the name of the HISP project nor the names of its contributors may
2034+ * be used to endorse or promote products derived from this software without
2035+ * specific prior written permission.
2036+ *
2037+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2038+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2039+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2040+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2041+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2042+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2043+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2044+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2045+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2046+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2047+ */
2048+
2049+import java.util.List;
2050+
2051+/**
2052+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2053+ */
2054+public interface Node
2055+{
2056+ /**
2057+ * Name of this node.
2058+ *
2059+ * @return current name of node
2060+ */
2061+ String getName();
2062+
2063+ /**
2064+ * Type specifier for this node.
2065+ *
2066+ * @return Node type
2067+ * @see org.hisp.dhis.node.NodeType
2068+ */
2069+ NodeType getType();
2070+
2071+ /**
2072+ * @param type Type to check for
2073+ * @return True if node is of this type
2074+ */
2075+ boolean is( NodeType type );
2076+
2077+ /**
2078+ * Helper that checks if node is of simple type, useful to checking if
2079+ * you are allowed to add children to this node.
2080+ *
2081+ * @return true if type is simple
2082+ * @see org.hisp.dhis.node.NodeType
2083+ */
2084+ boolean isSimple();
2085+
2086+ /**
2087+ * Helper that checks if node is of complex type.
2088+ *
2089+ * @return true if type is complex
2090+ * @see org.hisp.dhis.node.NodeType
2091+ */
2092+ boolean isComplex();
2093+
2094+ /**
2095+ * Helper that checks if node is of collection type.
2096+ *
2097+ * @return true if type is collection
2098+ * @see org.hisp.dhis.node.NodeType
2099+ */
2100+ boolean isCollection();
2101+
2102+ /**
2103+ * Namespace for this node. Not all serializers support this, and its up to the
2104+ * NodeSerializer implementation to decide what to do with this.
2105+ *
2106+ * @return namespace
2107+ * @see org.hisp.dhis.node.NodeSerializer
2108+ */
2109+ String getNamespace();
2110+
2111+ /**
2112+ * Comment for this node. Not all serializers support this, and its up to the
2113+ * NodeSerializer implementation to decide what to do with this.
2114+ *
2115+ * @return namespace
2116+ * @see org.hisp.dhis.node.NodeSerializer
2117+ */
2118+ String getComment();
2119+
2120+ /**
2121+ * Adds a child to this node.
2122+ *
2123+ * @param child Child node to add
2124+ * @return Child node that was added
2125+ */
2126+ <T extends Node> T addChild( T child );
2127+
2128+ /**
2129+ * Adds a collection of children to this node.
2130+ *
2131+ * @param children Child nodes to add
2132+ */
2133+ <T extends Node> void addChildren( Iterable<T> children );
2134+
2135+ /**
2136+ * Get all child notes associated with this node. Please note that the returned list is a copy
2137+ * of the internal list, and changes to the list will not be reflected in the node.
2138+ *
2139+ * @return List of child nodes associated with this node
2140+ */
2141+ List<Node> getChildren();
2142+}
2143
2144=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeDeserializer.java'
2145--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeDeserializer.java 1970-01-01 00:00:00 +0000
2146+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeDeserializer.java 2014-06-05 17:39:07 +0000
2147@@ -0,0 +1,45 @@
2148+package org.hisp.dhis.node;
2149+
2150+/*
2151+ * Copyright (c) 2004-2014, University of Oslo
2152+ * All rights reserved.
2153+ *
2154+ * Redistribution and use in source and binary forms, with or without
2155+ * modification, are permitted provided that the following conditions are met:
2156+ * Redistributions of source code must retain the above copyright notice, this
2157+ * list of conditions and the following disclaimer.
2158+ *
2159+ * Redistributions in binary form must reproduce the above copyright notice,
2160+ * this list of conditions and the following disclaimer in the documentation
2161+ * and/or other materials provided with the distribution.
2162+ * Neither the name of the HISP project nor the names of its contributors may
2163+ * be used to endorse or promote products derived from this software without
2164+ * specific prior written permission.
2165+ *
2166+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2167+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2168+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2169+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2170+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2171+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2172+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2173+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2174+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2175+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2176+ */
2177+
2178+import org.hisp.dhis.node.types.RootNode;
2179+
2180+import java.io.IOException;
2181+import java.io.InputStream;
2182+import java.util.List;
2183+
2184+/**
2185+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2186+ */
2187+public interface NodeDeserializer
2188+{
2189+ List<String> contentTypes();
2190+
2191+ RootNode deserialize( InputStream inputStream ) throws IOException;
2192+}
2193
2194=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeSerializer.java'
2195--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeSerializer.java 1970-01-01 00:00:00 +0000
2196+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeSerializer.java 2014-06-05 17:39:07 +0000
2197@@ -0,0 +1,45 @@
2198+package org.hisp.dhis.node;
2199+
2200+/*
2201+ * Copyright (c) 2004-2014, University of Oslo
2202+ * All rights reserved.
2203+ *
2204+ * Redistribution and use in source and binary forms, with or without
2205+ * modification, are permitted provided that the following conditions are met:
2206+ * Redistributions of source code must retain the above copyright notice, this
2207+ * list of conditions and the following disclaimer.
2208+ *
2209+ * Redistributions in binary form must reproduce the above copyright notice,
2210+ * this list of conditions and the following disclaimer in the documentation
2211+ * and/or other materials provided with the distribution.
2212+ * Neither the name of the HISP project nor the names of its contributors may
2213+ * be used to endorse or promote products derived from this software without
2214+ * specific prior written permission.
2215+ *
2216+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2217+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2218+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2219+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2220+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2221+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2222+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2223+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2224+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2225+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2226+ */
2227+
2228+import org.hisp.dhis.node.types.RootNode;
2229+
2230+import java.io.IOException;
2231+import java.io.OutputStream;
2232+import java.util.List;
2233+
2234+/**
2235+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2236+ */
2237+public interface NodeSerializer
2238+{
2239+ List<String> contentTypes();
2240+
2241+ void serialize( RootNode rootNode, OutputStream outputStream ) throws IOException;
2242+}
2243
2244=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeService.java'
2245--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeService.java 1970-01-01 00:00:00 +0000
2246+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeService.java 2014-06-05 17:39:07 +0000
2247@@ -0,0 +1,75 @@
2248+package org.hisp.dhis.node;
2249+
2250+/*
2251+ * Copyright (c) 2004-2014, University of Oslo
2252+ * All rights reserved.
2253+ *
2254+ * Redistribution and use in source and binary forms, with or without
2255+ * modification, are permitted provided that the following conditions are met:
2256+ * Redistributions of source code must retain the above copyright notice, this
2257+ * list of conditions and the following disclaimer.
2258+ *
2259+ * Redistributions in binary form must reproduce the above copyright notice,
2260+ * this list of conditions and the following disclaimer in the documentation
2261+ * and/or other materials provided with the distribution.
2262+ * Neither the name of the HISP project nor the names of its contributors may
2263+ * be used to endorse or promote products derived from this software without
2264+ * specific prior written permission.
2265+ *
2266+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2267+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2268+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2269+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2270+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2271+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2272+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2273+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2274+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2275+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2276+ */
2277+
2278+import org.hisp.dhis.node.types.RootNode;
2279+
2280+import java.io.IOException;
2281+import java.io.InputStream;
2282+import java.io.OutputStream;
2283+
2284+/**
2285+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2286+ */
2287+public interface NodeService
2288+{
2289+ /**
2290+ * Find a nodeSerializer that supports contentType or return null.
2291+ *
2292+ * @param contentType NodeSerializer contentType
2293+ * @return NodeSerializer that support contentType, or null if not match was found
2294+ * @see org.hisp.dhis.node.NodeSerializer
2295+ */
2296+ NodeSerializer getNodeSerializer( String contentType );
2297+
2298+ /**
2299+ * Write out rootNode to a nodeSerializer that matches the contentType.
2300+ *
2301+ * @param rootNode RootNode to write
2302+ * @param contentType NodeSerializer contentType
2303+ * @param outputStream Write to this outputStream
2304+ */
2305+ void serialize( RootNode rootNode, String contentType, OutputStream outputStream ) throws IOException;
2306+
2307+ /**
2308+ * Find a nodeDeserializer that supports contentType or return null.
2309+ *
2310+ * @param contentType NodeDeserializer contentType
2311+ * @return NodeDeserializer that support contentType, or null if not match was found
2312+ * @see org.hisp.dhis.node.NodeDeserializer
2313+ */
2314+ NodeDeserializer getNodeDeserializer( String contentType );
2315+
2316+ /**
2317+ * @param contentType NodeDeserializer contentType
2318+ * @param inputStream Read RootNode from this stream
2319+ * @return RootNode deserialized from inputStream
2320+ */
2321+ RootNode deserialize( String contentType, InputStream inputStream ) throws IOException;
2322+}
2323
2324=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeType.java'
2325--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeType.java 1970-01-01 00:00:00 +0000
2326+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeType.java 2014-06-05 17:39:07 +0000
2327@@ -0,0 +1,39 @@
2328+package org.hisp.dhis.node;
2329+
2330+/*
2331+ * Copyright (c) 2004-2014, University of Oslo
2332+ * All rights reserved.
2333+ *
2334+ * Redistribution and use in source and binary forms, with or without
2335+ * modification, are permitted provided that the following conditions are met:
2336+ * Redistributions of source code must retain the above copyright notice, this
2337+ * list of conditions and the following disclaimer.
2338+ *
2339+ * Redistributions in binary form must reproduce the above copyright notice,
2340+ * this list of conditions and the following disclaimer in the documentation
2341+ * and/or other materials provided with the distribution.
2342+ * Neither the name of the HISP project nor the names of its contributors may
2343+ * be used to endorse or promote products derived from this software without
2344+ * specific prior written permission.
2345+ *
2346+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2347+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2348+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2349+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2350+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2351+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2352+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2353+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2354+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2355+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2356+ */
2357+
2358+/**
2359+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2360+ */
2361+public enum NodeType
2362+{
2363+ SIMPLE,
2364+ COMPLEX,
2365+ COLLECTION
2366+}
2367
2368=== added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation'
2369=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportCollection.java'
2370--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportCollection.java 1970-01-01 00:00:00 +0000
2371+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportCollection.java 2014-06-05 17:39:07 +0000
2372@@ -0,0 +1,54 @@
2373+package org.hisp.dhis.node.annotation;
2374+
2375+/*
2376+ * Copyright (c) 2004-2014, University of Oslo
2377+ * All rights reserved.
2378+ *
2379+ * Redistribution and use in source and binary forms, with or without
2380+ * modification, are permitted provided that the following conditions are met:
2381+ * Redistributions of source code must retain the above copyright notice, this
2382+ * list of conditions and the following disclaimer.
2383+ *
2384+ * Redistributions in binary form must reproduce the above copyright notice,
2385+ * this list of conditions and the following disclaimer in the documentation
2386+ * and/or other materials provided with the distribution.
2387+ * Neither the name of the HISP project nor the names of its contributors may
2388+ * be used to endorse or promote products derived from this software without
2389+ * specific prior written permission.
2390+ *
2391+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2392+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2393+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2394+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2395+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2396+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2397+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2398+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2399+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2400+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2401+ */
2402+
2403+import java.lang.annotation.ElementType;
2404+import java.lang.annotation.Retention;
2405+import java.lang.annotation.RetentionPolicy;
2406+import java.lang.annotation.Target;
2407+
2408+/**
2409+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2410+ */
2411+@Target( { ElementType.FIELD, ElementType.METHOD } )
2412+@Retention( RetentionPolicy.RUNTIME )
2413+public @interface ExportCollection
2414+{
2415+ String value() default "";
2416+
2417+ String namespace() default "";
2418+
2419+ String itemName() default "";
2420+
2421+ String itemNamespace() default "";
2422+
2423+ boolean owner() default false;
2424+
2425+ boolean useWrapping() default true;
2426+}
2427
2428=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportComplex.java'
2429--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportComplex.java 1970-01-01 00:00:00 +0000
2430+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportComplex.java 2014-06-05 17:39:07 +0000
2431@@ -0,0 +1,46 @@
2432+package org.hisp.dhis.node.annotation;
2433+
2434+/*
2435+ * Copyright (c) 2004-2014, University of Oslo
2436+ * All rights reserved.
2437+ *
2438+ * Redistribution and use in source and binary forms, with or without
2439+ * modification, are permitted provided that the following conditions are met:
2440+ * Redistributions of source code must retain the above copyright notice, this
2441+ * list of conditions and the following disclaimer.
2442+ *
2443+ * Redistributions in binary form must reproduce the above copyright notice,
2444+ * this list of conditions and the following disclaimer in the documentation
2445+ * and/or other materials provided with the distribution.
2446+ * Neither the name of the HISP project nor the names of its contributors may
2447+ * be used to endorse or promote products derived from this software without
2448+ * specific prior written permission.
2449+ *
2450+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2451+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2452+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2453+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2454+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2455+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2456+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2457+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2458+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2459+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2460+ */
2461+
2462+import java.lang.annotation.ElementType;
2463+import java.lang.annotation.Retention;
2464+import java.lang.annotation.RetentionPolicy;
2465+import java.lang.annotation.Target;
2466+
2467+/**
2468+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2469+ */
2470+@Target( { ElementType.FIELD, ElementType.METHOD } )
2471+@Retention( RetentionPolicy.RUNTIME )
2472+public @interface ExportComplex
2473+{
2474+ String value() default "";
2475+
2476+ String namespace() default "";
2477+}
2478
2479=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportRoot.java'
2480--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportRoot.java 1970-01-01 00:00:00 +0000
2481+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportRoot.java 2014-06-05 17:39:07 +0000
2482@@ -0,0 +1,46 @@
2483+package org.hisp.dhis.node.annotation;
2484+
2485+/*
2486+ * Copyright (c) 2004-2014, University of Oslo
2487+ * All rights reserved.
2488+ *
2489+ * Redistribution and use in source and binary forms, with or without
2490+ * modification, are permitted provided that the following conditions are met:
2491+ * Redistributions of source code must retain the above copyright notice, this
2492+ * list of conditions and the following disclaimer.
2493+ *
2494+ * Redistributions in binary form must reproduce the above copyright notice,
2495+ * this list of conditions and the following disclaimer in the documentation
2496+ * and/or other materials provided with the distribution.
2497+ * Neither the name of the HISP project nor the names of its contributors may
2498+ * be used to endorse or promote products derived from this software without
2499+ * specific prior written permission.
2500+ *
2501+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2502+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2503+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2504+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2505+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2506+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2507+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2508+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2509+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2510+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2511+ */
2512+
2513+import java.lang.annotation.ElementType;
2514+import java.lang.annotation.Retention;
2515+import java.lang.annotation.RetentionPolicy;
2516+import java.lang.annotation.Target;
2517+
2518+/**
2519+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2520+ */
2521+@Target( { ElementType.TYPE } )
2522+@Retention( RetentionPolicy.RUNTIME )
2523+public @interface ExportRoot
2524+{
2525+ String value() default "";
2526+
2527+ String namespace() default "";
2528+}
2529
2530=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportSimple.java'
2531--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportSimple.java 1970-01-01 00:00:00 +0000
2532+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/annotation/ExportSimple.java 2014-06-05 17:39:07 +0000
2533@@ -0,0 +1,48 @@
2534+package org.hisp.dhis.node.annotation;
2535+
2536+/*
2537+ * Copyright (c) 2004-2014, University of Oslo
2538+ * All rights reserved.
2539+ *
2540+ * Redistribution and use in source and binary forms, with or without
2541+ * modification, are permitted provided that the following conditions are met:
2542+ * Redistributions of source code must retain the above copyright notice, this
2543+ * list of conditions and the following disclaimer.
2544+ *
2545+ * Redistributions in binary form must reproduce the above copyright notice,
2546+ * this list of conditions and the following disclaimer in the documentation
2547+ * and/or other materials provided with the distribution.
2548+ * Neither the name of the HISP project nor the names of its contributors may
2549+ * be used to endorse or promote products derived from this software without
2550+ * specific prior written permission.
2551+ *
2552+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2553+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2554+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2555+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2556+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2557+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2558+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2559+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2560+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2561+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2562+ */
2563+
2564+import java.lang.annotation.ElementType;
2565+import java.lang.annotation.Retention;
2566+import java.lang.annotation.RetentionPolicy;
2567+import java.lang.annotation.Target;
2568+
2569+/**
2570+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2571+ */
2572+@Target( { ElementType.FIELD, ElementType.METHOD } )
2573+@Retention( RetentionPolicy.RUNTIME )
2574+public @interface ExportSimple
2575+{
2576+ String value() default "";
2577+
2578+ boolean isAttribute() default false;
2579+
2580+ String namespace() default "";
2581+}
2582
2583=== added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception'
2584=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception/DuplicateNodeException.java'
2585--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception/DuplicateNodeException.java 1970-01-01 00:00:00 +0000
2586+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception/DuplicateNodeException.java 2014-06-05 17:39:07 +0000
2587@@ -0,0 +1,40 @@
2588+package org.hisp.dhis.node.exception;
2589+
2590+/*
2591+ * Copyright (c) 2004-2014, University of Oslo
2592+ * All rights reserved.
2593+ *
2594+ * Redistribution and use in source and binary forms, with or without
2595+ * modification, are permitted provided that the following conditions are met:
2596+ * Redistributions of source code must retain the above copyright notice, this
2597+ * list of conditions and the following disclaimer.
2598+ *
2599+ * Redistributions in binary form must reproduce the above copyright notice,
2600+ * this list of conditions and the following disclaimer in the documentation
2601+ * and/or other materials provided with the distribution.
2602+ * Neither the name of the HISP project nor the names of its contributors may
2603+ * be used to endorse or promote products derived from this software without
2604+ * specific prior written permission.
2605+ *
2606+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2607+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2608+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2609+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2610+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2611+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2612+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2613+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2614+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2615+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2616+ */
2617+
2618+/**
2619+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2620+ */
2621+public class DuplicateNodeException extends RuntimeException
2622+{
2623+ public DuplicateNodeException()
2624+ {
2625+ super( "A node with that name already exists in the child list." );
2626+ }
2627+}
2628
2629=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception/InvalidTypeException.java'
2630--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception/InvalidTypeException.java 1970-01-01 00:00:00 +0000
2631+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception/InvalidTypeException.java 2014-06-05 17:39:07 +0000
2632@@ -0,0 +1,40 @@
2633+package org.hisp.dhis.node.exception;
2634+
2635+/*
2636+ * Copyright (c) 2004-2014, University of Oslo
2637+ * All rights reserved.
2638+ *
2639+ * Redistribution and use in source and binary forms, with or without
2640+ * modification, are permitted provided that the following conditions are met:
2641+ * Redistributions of source code must retain the above copyright notice, this
2642+ * list of conditions and the following disclaimer.
2643+ *
2644+ * Redistributions in binary form must reproduce the above copyright notice,
2645+ * this list of conditions and the following disclaimer in the documentation
2646+ * and/or other materials provided with the distribution.
2647+ * Neither the name of the HISP project nor the names of its contributors may
2648+ * be used to endorse or promote products derived from this software without
2649+ * specific prior written permission.
2650+ *
2651+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2652+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2653+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2654+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2655+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2656+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2657+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2658+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2659+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2660+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2661+ */
2662+
2663+/**
2664+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2665+ */
2666+public class InvalidTypeException extends RuntimeException
2667+{
2668+ public InvalidTypeException()
2669+ {
2670+ super( "Adding children to a node of type simple is not allowed." );
2671+ }
2672+}
2673
2674=== added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers'
2675=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/JacksonJsonNodeSerializer.java'
2676--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/JacksonJsonNodeSerializer.java 1970-01-01 00:00:00 +0000
2677+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/JacksonJsonNodeSerializer.java 2014-06-05 17:39:07 +0000
2678@@ -0,0 +1,165 @@
2679+package org.hisp.dhis.node.serializers;
2680+
2681+/*
2682+ * Copyright (c) 2004-2014, University of Oslo
2683+ * All rights reserved.
2684+ *
2685+ * Redistribution and use in source and binary forms, with or without
2686+ * modification, are permitted provided that the following conditions are met:
2687+ * Redistributions of source code must retain the above copyright notice, this
2688+ * list of conditions and the following disclaimer.
2689+ *
2690+ * Redistributions in binary form must reproduce the above copyright notice,
2691+ * this list of conditions and the following disclaimer in the documentation
2692+ * and/or other materials provided with the distribution.
2693+ * Neither the name of the HISP project nor the names of its contributors may
2694+ * be used to endorse or promote products derived from this software without
2695+ * specific prior written permission.
2696+ *
2697+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2698+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2699+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2700+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2701+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2702+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2703+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2704+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2705+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2706+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2707+ */
2708+
2709+import com.fasterxml.jackson.annotation.JsonInclude;
2710+import com.fasterxml.jackson.core.JsonGenerator;
2711+import com.fasterxml.jackson.databind.ObjectMapper;
2712+import com.fasterxml.jackson.databind.SerializationFeature;
2713+import com.google.common.collect.Lists;
2714+import org.hisp.dhis.node.Node;
2715+import org.hisp.dhis.node.NodeSerializer;
2716+import org.hisp.dhis.node.types.CollectionNode;
2717+import org.hisp.dhis.node.types.ComplexNode;
2718+import org.hisp.dhis.node.types.RootNode;
2719+import org.hisp.dhis.node.types.SimpleNode;
2720+import org.springframework.stereotype.Component;
2721+
2722+import java.io.IOException;
2723+import java.io.OutputStream;
2724+import java.util.List;
2725+
2726+/**
2727+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2728+ */
2729+@Component
2730+public class JacksonJsonNodeSerializer implements NodeSerializer
2731+{
2732+ public static final String CONTENT_TYPE = "application/json";
2733+
2734+ private final ObjectMapper objectMapper = new ObjectMapper();
2735+
2736+ @Override
2737+ public List<String> contentTypes()
2738+ {
2739+ return Lists.newArrayList( CONTENT_TYPE );
2740+ }
2741+
2742+ public JacksonJsonNodeSerializer()
2743+ {
2744+ objectMapper.setSerializationInclusion( JsonInclude.Include.NON_NULL );
2745+ objectMapper.configure( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false );
2746+ objectMapper.configure( SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false );
2747+ objectMapper.configure( SerializationFeature.WRAP_EXCEPTIONS, true );
2748+ objectMapper.getFactory().enable( JsonGenerator.Feature.QUOTE_FIELD_NAMES );
2749+ }
2750+
2751+ @Override
2752+ public void serialize( RootNode rootNode, OutputStream outputStream ) throws IOException
2753+ {
2754+ JsonGenerator generator = objectMapper.getFactory().createGenerator( outputStream );
2755+
2756+ writeRootNode( rootNode, generator );
2757+ generator.flush();
2758+ }
2759+
2760+ private void writeRootNode( RootNode rootNode, JsonGenerator generator ) throws IOException
2761+ {
2762+ generator.writeStartObject();
2763+
2764+ for ( Node node : rootNode.getChildren() )
2765+ {
2766+ dispatcher( node, generator, true );
2767+ generator.flush();
2768+ }
2769+
2770+ generator.writeEndObject();
2771+ }
2772+
2773+ private void writeSimpleNode( SimpleNode simpleNode, JsonGenerator generator, boolean writeKey ) throws IOException
2774+ {
2775+ if ( simpleNode.getValue() == null ) // add hint for this, exclude if null
2776+ {
2777+ return;
2778+ }
2779+
2780+ if ( writeKey )
2781+ {
2782+ generator.writeObjectField( simpleNode.getName(), simpleNode.getValue() );
2783+ }
2784+ else
2785+ {
2786+ generator.writeObject( simpleNode.getValue() );
2787+ }
2788+ }
2789+
2790+ private void writeComplexNode( ComplexNode complexNode, JsonGenerator generator, boolean writeKey ) throws IOException
2791+ {
2792+ if ( writeKey )
2793+ {
2794+ generator.writeObjectFieldStart( complexNode.getName() );
2795+ }
2796+ else
2797+ {
2798+ generator.writeStartObject();
2799+ }
2800+
2801+ for ( Node node : complexNode.getChildren() )
2802+ {
2803+ dispatcher( node, generator, true );
2804+ }
2805+
2806+ generator.writeEndObject();
2807+ }
2808+
2809+ private void writeCollectionNode( CollectionNode collectionNode, JsonGenerator generator, boolean writeKey ) throws IOException
2810+ {
2811+ if ( writeKey )
2812+ {
2813+ generator.writeArrayFieldStart( collectionNode.getName() );
2814+ }
2815+ else
2816+ {
2817+ generator.writeStartArray();
2818+ }
2819+
2820+ for ( Node node : collectionNode.getChildren() )
2821+ {
2822+ dispatcher( node, generator, false );
2823+ }
2824+
2825+ generator.writeEndArray();
2826+ }
2827+
2828+ private void dispatcher( Node node, JsonGenerator generator, boolean writeKey ) throws IOException
2829+ {
2830+ switch ( node.getType() )
2831+ {
2832+ case SIMPLE:
2833+ writeSimpleNode( (SimpleNode) node, generator, writeKey );
2834+ break;
2835+ case COMPLEX:
2836+ writeComplexNode( (ComplexNode) node, generator, writeKey );
2837+ break;
2838+ case COLLECTION:
2839+ writeCollectionNode( (CollectionNode) node, generator, writeKey );
2840+ break;
2841+ }
2842+ }
2843+}
2844
2845=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java'
2846--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java 1970-01-01 00:00:00 +0000
2847+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java 2014-06-05 17:39:07 +0000
2848@@ -0,0 +1,197 @@
2849+package org.hisp.dhis.node.serializers;
2850+
2851+/*
2852+ * Copyright (c) 2004-2014, University of Oslo
2853+ * All rights reserved.
2854+ *
2855+ * Redistribution and use in source and binary forms, with or without
2856+ * modification, are permitted provided that the following conditions are met:
2857+ * Redistributions of source code must retain the above copyright notice, this
2858+ * list of conditions and the following disclaimer.
2859+ *
2860+ * Redistributions in binary form must reproduce the above copyright notice,
2861+ * this list of conditions and the following disclaimer in the documentation
2862+ * and/or other materials provided with the distribution.
2863+ * Neither the name of the HISP project nor the names of its contributors may
2864+ * be used to endorse or promote products derived from this software without
2865+ * specific prior written permission.
2866+ *
2867+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2868+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2869+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2870+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2871+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2872+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2873+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2874+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2875+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2876+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
2877+ */
2878+
2879+import com.google.common.collect.Lists;
2880+import org.hisp.dhis.node.Node;
2881+import org.hisp.dhis.node.NodeSerializer;
2882+import org.hisp.dhis.node.types.CollectionNode;
2883+import org.hisp.dhis.node.types.ComplexNode;
2884+import org.hisp.dhis.node.types.RootNode;
2885+import org.hisp.dhis.node.types.SimpleNode;
2886+import org.springframework.stereotype.Component;
2887+import org.springframework.util.StringUtils;
2888+
2889+import javax.xml.stream.XMLOutputFactory;
2890+import javax.xml.stream.XMLStreamException;
2891+import javax.xml.stream.XMLStreamWriter;
2892+import java.io.IOException;
2893+import java.io.OutputStream;
2894+import java.util.List;
2895+
2896+/**
2897+ * @author Morten Olav Hansen <mortenoh@gmail.com>
2898+ */
2899+@Component
2900+public class StAXNodeSerializer implements NodeSerializer
2901+{
2902+ public static final String CONTENT_TYPE = "application/xml";
2903+
2904+ private final XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
2905+
2906+ @Override
2907+ public List<String> contentTypes()
2908+ {
2909+ return Lists.newArrayList( CONTENT_TYPE );
2910+ }
2911+
2912+ @Override
2913+ public void serialize( RootNode rootNode, OutputStream outputStream ) throws IOException
2914+ {
2915+ XMLStreamWriter writer;
2916+
2917+ try
2918+ {
2919+ writer = xmlFactory.createXMLStreamWriter( outputStream );
2920+ writeRootNode( rootNode, writer );
2921+ writer.flush();
2922+ }
2923+ catch ( XMLStreamException e )
2924+ {
2925+ throw new IOException( e.getMessage(), e.getCause() );
2926+ }
2927+ }
2928+
2929+ private void writeRootNode( RootNode rootNode, XMLStreamWriter writer ) throws IOException, XMLStreamException
2930+ {
2931+ writer.writeStartDocument( "UTF-8", "1.0" );
2932+
2933+ if ( !StringUtils.isEmpty( rootNode.getComment() ) )
2934+ {
2935+ writer.writeComment( rootNode.getComment() );
2936+ }
2937+
2938+ writeStartElement( rootNode, writer );
2939+
2940+ for ( Node node : rootNode.getChildren() )
2941+ {
2942+ dispatcher( node, writer );
2943+ writer.flush();
2944+ }
2945+
2946+ writeEndElement( writer );
2947+ writer.writeEndDocument();
2948+ }
2949+
2950+ private void writeSimpleNode( SimpleNode simpleNode, XMLStreamWriter writer ) throws XMLStreamException
2951+ {
2952+ if ( simpleNode.getValue() == null ) // TODO include null or not?
2953+ {
2954+ return;
2955+ }
2956+
2957+ String value = String.format( "%s", simpleNode.getValue() );
2958+
2959+ if ( simpleNode.isAttribute() )
2960+ {
2961+ if ( !StringUtils.isEmpty( simpleNode.getNamespace() ) )
2962+ {
2963+ writer.writeAttribute( "", simpleNode.getNamespace(), simpleNode.getName(), value );
2964+ }
2965+ else
2966+ {
2967+ writer.writeAttribute( simpleNode.getName(), value );
2968+ }
2969+ }
2970+ else
2971+ {
2972+ writeStartElement( simpleNode, writer );
2973+ writer.writeCharacters( value );
2974+ writeEndElement( writer );
2975+ }
2976+ }
2977+
2978+ private void writeComplexNode( ComplexNode complexNode, XMLStreamWriter writer ) throws XMLStreamException, IOException
2979+ {
2980+ writeStartElement( complexNode, writer );
2981+
2982+ for ( Node node : complexNode.getChildren() )
2983+ {
2984+ dispatcher( node, writer );
2985+ }
2986+
2987+ writeEndElement( writer );
2988+ }
2989+
2990+ private void writeCollectionNode( CollectionNode collectionNode, XMLStreamWriter writer ) throws XMLStreamException, IOException
2991+ {
2992+ if ( collectionNode.isWrapping() )
2993+ {
2994+ writeStartElement( collectionNode, writer );
2995+ }
2996+
2997+ for ( Node node : collectionNode.getChildren() )
2998+ {
2999+ dispatcher( node, writer );
3000+ }
3001+
3002+ if ( collectionNode.isWrapping() )
3003+ {
3004+ writeEndElement( writer );
3005+ }
3006+ }
3007+
3008+ private void dispatcher( Node node, XMLStreamWriter writer ) throws IOException, XMLStreamException
3009+ {
3010+ if ( !StringUtils.isEmpty( node.getComment() ) )
3011+ {
3012+ writer.writeComment( node.getComment() );
3013+ }
3014+
3015+ switch ( node.getType() )
3016+ {
3017+ case SIMPLE:
3018+ writeSimpleNode( (SimpleNode) node, writer );
3019+ break;
3020+ case COMPLEX:
3021+ writeComplexNode( (ComplexNode) node, writer );
3022+ break;
3023+ case COLLECTION:
3024+ writeCollectionNode( (CollectionNode) node, writer );
3025+ break;
3026+ }
3027+ }
3028+
3029+ private void writeStartElement( Node node, XMLStreamWriter writer ) throws XMLStreamException
3030+ {
3031+ if ( !StringUtils.isEmpty( node.getNamespace() ) )
3032+ {
3033+ writer.writeStartElement( "", node.getName(), node.getNamespace() );
3034+ }
3035+ else
3036+ {
3037+ writer.writeStartElement( node.getName() );
3038+ }
3039+ }
3040+
3041+ private void writeEndElement( XMLStreamWriter writer ) throws XMLStreamException
3042+ {
3043+ writer.writeEndElement();
3044+ }
3045+}
3046
3047=== added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types'
3048=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/CollectionNode.java'
3049--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/CollectionNode.java 1970-01-01 00:00:00 +0000
3050+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/CollectionNode.java 2014-06-05 17:39:07 +0000
3051@@ -0,0 +1,58 @@
3052+package org.hisp.dhis.node.types;
3053+
3054+/*
3055+ * Copyright (c) 2004-2014, University of Oslo
3056+ * All rights reserved.
3057+ *
3058+ * Redistribution and use in source and binary forms, with or without
3059+ * modification, are permitted provided that the following conditions are met:
3060+ * Redistributions of source code must retain the above copyright notice, this
3061+ * list of conditions and the following disclaimer.
3062+ *
3063+ * Redistributions in binary form must reproduce the above copyright notice,
3064+ * this list of conditions and the following disclaimer in the documentation
3065+ * and/or other materials provided with the distribution.
3066+ * Neither the name of the HISP project nor the names of its contributors may
3067+ * be used to endorse or promote products derived from this software without
3068+ * specific prior written permission.
3069+ *
3070+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3071+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3072+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3073+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
3074+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3075+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3076+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
3077+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3078+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3079+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
3080+ */
3081+
3082+import org.hisp.dhis.node.AbstractNode;
3083+import org.hisp.dhis.node.NodeType;
3084+
3085+/**
3086+ * @author Morten Olav Hansen <mortenoh@gmail.com>
3087+ */
3088+public class CollectionNode extends AbstractNode
3089+{
3090+ /**
3091+ * Should this collection act as a wrapper around its children.
3092+ */
3093+ boolean wrapping = true;
3094+
3095+ public CollectionNode( String name )
3096+ {
3097+ super( name, NodeType.COLLECTION );
3098+ }
3099+
3100+ public boolean isWrapping()
3101+ {
3102+ return wrapping;
3103+ }
3104+
3105+ public void setWrapping( boolean wrapping )
3106+ {
3107+ this.wrapping = wrapping;
3108+ }
3109+}
3110
3111=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/ComplexNode.java'
3112--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/ComplexNode.java 1970-01-01 00:00:00 +0000
3113+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/ComplexNode.java 2014-06-05 17:39:07 +0000
3114@@ -0,0 +1,43 @@
3115+package org.hisp.dhis.node.types;
3116+
3117+/*
3118+ * Copyright (c) 2004-2014, University of Oslo
3119+ * All rights reserved.
3120+ *
3121+ * Redistribution and use in source and binary forms, with or without
3122+ * modification, are permitted provided that the following conditions are met:
3123+ * Redistributions of source code must retain the above copyright notice, this
3124+ * list of conditions and the following disclaimer.
3125+ *
3126+ * Redistributions in binary form must reproduce the above copyright notice,
3127+ * this list of conditions and the following disclaimer in the documentation
3128+ * and/or other materials provided with the distribution.
3129+ * Neither the name of the HISP project nor the names of its contributors may
3130+ * be used to endorse or promote products derived from this software without
3131+ * specific prior written permission.
3132+ *
3133+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3134+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3135+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3136+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
3137+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3138+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3139+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
3140+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3141+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3142+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
3143+ */
3144+
3145+import org.hisp.dhis.node.AbstractNode;
3146+import org.hisp.dhis.node.NodeType;
3147+
3148+/**
3149+ * @author Morten Olav Hansen <mortenoh@gmail.com>
3150+ */
3151+public class ComplexNode extends AbstractNode
3152+{
3153+ public ComplexNode( String name )
3154+ {
3155+ super( name, NodeType.COMPLEX );
3156+ }
3157+}
3158
3159=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/RootNode.java'
3160--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/RootNode.java 1970-01-01 00:00:00 +0000
3161+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/RootNode.java 2014-06-05 17:39:07 +0000
3162@@ -0,0 +1,40 @@
3163+package org.hisp.dhis.node.types;
3164+
3165+/*
3166+ * Copyright (c) 2004-2014, University of Oslo
3167+ * All rights reserved.
3168+ *
3169+ * Redistribution and use in source and binary forms, with or without
3170+ * modification, are permitted provided that the following conditions are met:
3171+ * Redistributions of source code must retain the above copyright notice, this
3172+ * list of conditions and the following disclaimer.
3173+ *
3174+ * Redistributions in binary form must reproduce the above copyright notice,
3175+ * this list of conditions and the following disclaimer in the documentation
3176+ * and/or other materials provided with the distribution.
3177+ * Neither the name of the HISP project nor the names of its contributors may
3178+ * be used to endorse or promote products derived from this software without
3179+ * specific prior written permission.
3180+ *
3181+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3182+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3183+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3184+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
3185+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3186+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3187+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
3188+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3189+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3190+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
3191+ */
3192+
3193+/**
3194+ * @author Morten Olav Hansen <mortenoh@gmail.com>
3195+ */
3196+public class RootNode extends ComplexNode
3197+{
3198+ public RootNode( String name )
3199+ {
3200+ super( name );
3201+ }
3202+}
3203
3204=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/SimpleNode.java'
3205--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/SimpleNode.java 1970-01-01 00:00:00 +0000
3206+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/SimpleNode.java 2014-06-05 17:39:07 +0000
3207@@ -0,0 +1,78 @@
3208+package org.hisp.dhis.node.types;
3209+
3210+/*
3211+ * Copyright (c) 2004-2014, University of Oslo
3212+ * All rights reserved.
3213+ *
3214+ * Redistribution and use in source and binary forms, with or without
3215+ * modification, are permitted provided that the following conditions are met:
3216+ * Redistributions of source code must retain the above copyright notice, this
3217+ * list of conditions and the following disclaimer.
3218+ *
3219+ * Redistributions in binary form must reproduce the above copyright notice,
3220+ * this list of conditions and the following disclaimer in the documentation
3221+ * and/or other materials provided with the distribution.
3222+ * Neither the name of the HISP project nor the names of its contributors may
3223+ * be used to endorse or promote products derived from this software without
3224+ * specific prior written permission.
3225+ *
3226+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
3227+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3228+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3229+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
3230+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3231+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3232+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
3233+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3234+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3235+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
3236+ */
3237+
3238+import org.hisp.dhis.node.AbstractNode;
3239+import org.hisp.dhis.node.Node;
3240+import org.hisp.dhis.node.NodeType;
3241+import org.hisp.dhis.node.exception.InvalidTypeException;
3242+
3243+/**
3244+ * @author Morten Olav Hansen <mortenoh@gmail.com>
3245+ */
3246+public class SimpleNode extends AbstractNode
3247+{
3248+ private final Object value;
3249+
3250+ private boolean attribute;
3251+
3252+ public SimpleNode( String name, Object value )
3253+ {
3254+ super( name, NodeType.SIMPLE );
3255+ this.value = value;
3256+ this.attribute = false;
3257+ }
3258+
3259+ public Object getValue()
3260+ {
3261+ return value;
3262+ }
3263+
3264+ public boolean isAttribute()
3265+ {
3266+ return attribute;
3267+ }
3268+
3269+ public void setAttribute( boolean attribute )
3270+ {
3271+ this.attribute = attribute;
3272+ }
3273+
3274+ @Override
3275+ public <T extends Node> T addChild( T child ) throws InvalidTypeException
3276+ {
3277+ throw new InvalidTypeException();
3278+ }
3279+
3280+ @Override
3281+ public <T extends Node> void addChildren( Iterable<T> children )
3282+ {
3283+ throw new InvalidTypeException();
3284+ }
3285+}
3286
3287=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/BiMonthlyPeriodType.java'
3288--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/BiMonthlyPeriodType.java 2014-03-18 08:10:10 +0000
3289+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/BiMonthlyPeriodType.java 2014-06-05 17:39:07 +0000
3290@@ -28,10 +28,9 @@
3291 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3292 */
3293
3294-import java.text.ParseException;
3295-import java.text.SimpleDateFormat;
3296-import java.util.ArrayList;
3297-import java.util.Calendar;
3298+import com.google.common.collect.Lists;
3299+import org.hisp.dhis.calendar.DateUnit;
3300+
3301 import java.util.Date;
3302 import java.util.List;
3303
3304@@ -61,29 +60,18 @@
3305 }
3306
3307 @Override
3308- public Period createPeriod()
3309- {
3310- return createPeriod( createCalendarInstance() );
3311- }
3312-
3313- @Override
3314- public Period createPeriod( Date date )
3315- {
3316- return createPeriod( createCalendarInstance( date ) );
3317- }
3318-
3319- @Override
3320- public Period createPeriod( Calendar cal )
3321- {
3322- cal.set( Calendar.MONTH, cal.get( Calendar.MONTH ) - cal.get( Calendar.MONTH ) % 2 );
3323- cal.set( Calendar.DAY_OF_MONTH, 1 );
3324-
3325- Date startDate = cal.getTime();
3326-
3327- cal.add( Calendar.MONTH, 1 );
3328- cal.set( Calendar.DAY_OF_MONTH, cal.getActualMaximum( Calendar.DAY_OF_MONTH ) );
3329-
3330- return new Period( this, startDate, cal.getTime() );
3331+ public Period createPeriod( DateUnit dateUnit )
3332+ {
3333+ DateUnit start = new DateUnit( dateUnit );
3334+ start.setMonth( ((start.getMonth() - 1) - (start.getMonth() - 1) % 2) + 1 );
3335+ start.setDay( 1 );
3336+
3337+ DateUnit end = new DateUnit( start );
3338+
3339+ end = getCalendar().plusMonths( end, 1 );
3340+ end.setDay( getCalendar().daysInMonth( end.getYear(), end.getMonth() ) );
3341+
3342+ return toIsoPeriod( start, end );
3343 }
3344
3345 @Override
3346@@ -99,17 +87,19 @@
3347 @Override
3348 public Period getNextPeriod( Period period )
3349 {
3350- Calendar cal = createCalendarInstance( period.getStartDate() );
3351- cal.add( Calendar.MONTH, 2 );
3352- return createPeriod( cal );
3353+ DateUnit dateUnit = getCalendar().fromIso( DateUnit.fromJdkDate( period.getStartDate() ) );
3354+ dateUnit = getCalendar().plusMonths( dateUnit, 2 );
3355+
3356+ return createPeriod( getCalendar().toIso( dateUnit ) );
3357 }
3358
3359 @Override
3360 public Period getPreviousPeriod( Period period )
3361 {
3362- Calendar cal = createCalendarInstance( period.getStartDate() );
3363- cal.add( Calendar.MONTH, -2 );
3364- return createPeriod( cal );
3365+ DateUnit dateUnit = getCalendar().fromIso( DateUnit.fromJdkDate( period.getStartDate() ) );
3366+ dateUnit = getCalendar().minusMonths( dateUnit, 2 );
3367+
3368+ return createPeriod( getCalendar().toIso( dateUnit ) );
3369 }
3370
3371 /**
3372@@ -117,18 +107,19 @@
3373 * the given Period exists.
3374 */
3375 @Override
3376- public List<Period> generatePeriods( Date date )
3377+ public List<Period> generatePeriods( DateUnit dateUnit )
3378 {
3379- Calendar cal = createCalendarInstance( date );
3380- cal.set( Calendar.DAY_OF_YEAR, 1 );
3381-
3382- int year = cal.get( Calendar.YEAR );
3383- ArrayList<Period> periods = new ArrayList<Period>();
3384-
3385- while ( cal.get( Calendar.YEAR ) == year )
3386+ dateUnit.setMonth( 1 );
3387+ dateUnit.setDay( 1 );
3388+
3389+ List<Period> periods = Lists.newArrayList();
3390+
3391+ int year = dateUnit.getYear();
3392+
3393+ while ( dateUnit.getYear() == year )
3394 {
3395- periods.add( createPeriod( cal ) );
3396- cal.add( Calendar.MONTH, 2 );
3397+ periods.add( createPeriod( dateUnit ) );
3398+ dateUnit = getCalendar().plusMonths( dateUnit, 2 );
3399 }
3400
3401 return periods;
3402@@ -139,41 +130,26 @@
3403 * which the given date is inside.
3404 */
3405 @Override
3406- public List<Period> generateRollingPeriods( Date date )
3407+ public List<Period> generateRollingPeriods( DateUnit dateUnit )
3408 {
3409- Calendar cal = createCalendarInstance( date );
3410- cal.set( Calendar.DAY_OF_MONTH, 1 );
3411- cal.add( Calendar.MONTH, ( ( cal.get( Calendar.MONTH ) % 2 ) * -1 ) - 10 );
3412-
3413- ArrayList<Period> periods = new ArrayList<Period>();
3414-
3415+ dateUnit.setDay( 1 );
3416+ dateUnit = getCalendar().minusMonths( dateUnit, (dateUnit.getMonth() % 2) + 10 );
3417+
3418+ List<Period> periods = Lists.newArrayList();
3419+
3420 for ( int i = 0; i < 6; i++ )
3421 {
3422- periods.add( createPeriod( cal ) );
3423- cal.add( Calendar.MONTH, 2 );
3424+ periods.add( createPeriod( dateUnit ) );
3425+ dateUnit = getCalendar().plusMonths( dateUnit, 2 );
3426 }
3427-
3428+
3429 return periods;
3430 }
3431
3432 @Override
3433- public String getIsoDate( Period period )
3434- {
3435- return new SimpleDateFormat( "yyyyMM" ).format( period.getStartDate() ) + "B";
3436- }
3437-
3438- @Override
3439- public Period createPeriod( String isoDate )
3440+ public String getIsoDate( DateUnit dateUnit )
3441 {
3442- try
3443- {
3444- Date date = new SimpleDateFormat( "yyyyMM" ).parse( isoDate.substring( 0, 6 ) );
3445- return createPeriod( date );
3446- }
3447- catch ( ParseException ex )
3448- {
3449- throw new RuntimeException( ex );
3450- }
3451+ return String.format( "%d%02dB", dateUnit.getYear(), dateUnit.getMonth() );
3452 }
3453
3454 @Override
3455@@ -181,16 +157,16 @@
3456 {
3457 return ISO_FORMAT;
3458 }
3459-
3460+
3461 @Override
3462 public Date getRewindedDate( Date date, Integer rewindedPeriods )
3463 {
3464- date = date != null ? date : new Date();
3465+ date = date != null ? date : new Date();
3466 rewindedPeriods = rewindedPeriods != null ? rewindedPeriods : 1;
3467
3468- Calendar cal = createCalendarInstance( date );
3469- cal.add( Calendar.MONTH, (rewindedPeriods * -2) );
3470+ DateUnit dateUnit = getCalendar().fromIso( DateUnit.fromJdkDate( date ) );
3471+ dateUnit = getCalendar().minusMonths( dateUnit, rewindedPeriods );
3472
3473- return cal.getTime();
3474+ return getCalendar().toIso( dateUnit ).toJdkDate();
3475 }
3476 }
3477
3478=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/Cal.java'
3479--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/Cal.java 2014-05-14 07:18:32 +0000
3480+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/Cal.java 2014-06-05 17:39:07 +0000
3481@@ -28,43 +28,62 @@
3482 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3483 */
3484
3485+import org.hisp.dhis.calendar.CalendarService;
3486+import org.hisp.dhis.calendar.DateUnit;
3487+import org.hisp.dhis.calendar.impl.Iso8601Calendar;
3488+
3489 import java.util.Calendar;
3490 import java.util.Date;
3491-import java.util.GregorianCalendar;
3492
3493 /**
3494+ * An abstraction over a calendar implementation, expects input to be in whatever the current
3495+ * system calendar is using, and all output will be in ISO 8601.
3496+ *
3497 * @author Lars Helge Overland
3498+ * @author Morten Olav Hansen <mortenoh@gmail.com>
3499 */
3500 public class Cal
3501 {
3502- private Calendar calendar;
3503-
3504+ private static CalendarService calendarService;
3505+
3506+ public static void setCalendarService( CalendarService calendarService )
3507+ {
3508+ Cal.calendarService = calendarService;
3509+ }
3510+
3511+ public static org.hisp.dhis.calendar.Calendar getCalendar()
3512+ {
3513+ if ( calendarService != null )
3514+ {
3515+ return calendarService.getSystemCalendar();
3516+ }
3517+
3518+ return Iso8601Calendar.getInstance();
3519+ }
3520+
3521+ private DateUnit dateUnit = new DateUnit( 1, 1, 1 );
3522+
3523 public Cal()
3524 {
3525- calendar = new GregorianCalendar();
3526- calendar.clear();
3527+ dateUnit = getCalendar().today();
3528 }
3529
3530 /**
3531- * @param year the year starting at AD 1.
3532- * @param month the month starting at 1.
3533- * @param day the day of the month starting at 1.
3534- */
3535+ * @param year the year starting at AD 1.
3536+ * @param month the month starting at 1.
3537+ * @param day the day of the month starting at 1.
3538+ */
3539 public Cal( int year, int month, int day )
3540 {
3541- calendar = new GregorianCalendar();
3542- calendar.clear();
3543- set( year, month, day );
3544+ dateUnit = new DateUnit( year, month, day );
3545 }
3546-
3547+
3548 /**
3549 * @param date the date.
3550 */
3551 public Cal( Date date )
3552 {
3553- calendar = new GregorianCalendar();
3554- calendar.clear();
3555- calendar.setTime( date );
3556+ dateUnit = DateUnit.fromJdkDate( date );
3557 }
3558
3559 /**
3560@@ -72,95 +91,107 @@
3561 */
3562 public Cal now()
3563 {
3564- calendar.setTime( new Date() );
3565+ dateUnit = getCalendar().today();
3566 return this;
3567 }
3568-
3569+
3570 /**
3571 * Adds the given amount of time to the given calendar field.
3572- *
3573- * @param field the calendar field.
3574+ * @param field the calendar field.
3575 * @param amount the amount of time.
3576 */
3577 public Cal add( int field, int amount )
3578 {
3579- calendar.add( field, amount );
3580+ switch ( field )
3581+ {
3582+ case Calendar.YEAR:
3583+ getCalendar().plusYears( dateUnit, amount );
3584+ case Calendar.MONTH:
3585+ getCalendar().plusMonths( dateUnit, amount );
3586+ case Calendar.DAY_OF_MONTH:
3587+ getCalendar().plusDays( dateUnit, amount );
3588+ }
3589+
3590 return this;
3591 }
3592
3593 /**
3594 * Subtracts the given amount of time to the given calendar field.
3595- *
3596- * @param field the calendar field.
3597+ * @param field the calendar field.
3598 * @param amount the amount of time.
3599 */
3600 public Cal subtract( int field, int amount )
3601 {
3602- calendar.add( field, amount * -1 );
3603+ switch ( field )
3604+ {
3605+ case Calendar.YEAR:
3606+ getCalendar().minusYears( dateUnit, amount );
3607+ case Calendar.MONTH:
3608+ getCalendar().minusMonths( dateUnit, amount );
3609+ case Calendar.DAY_OF_MONTH:
3610+ getCalendar().minusDays( dateUnit, amount );
3611+ }
3612+
3613 return this;
3614 }
3615
3616 /**
3617 * Returns the value of the given calendar field.
3618- *
3619 * @param field the field.
3620 */
3621 public int get( int field )
3622 {
3623- return calendar.get( field );
3624+ return getCalendar().toIso( dateUnit ).toJdkCalendar().get( field );
3625 }
3626-
3627+
3628 /**
3629 * Returns the current year.
3630 * @return current year
3631 */
3632 public int getYear()
3633 {
3634- return calendar.get( Calendar.YEAR );
3635+ return getCalendar().toIso( dateUnit ).toJdkCalendar().get( Calendar.YEAR );
3636 }
3637-
3638+
3639 /**
3640 * Sets the current time.
3641- *
3642- * @param year the year starting at AD 1.
3643+ * @param year the year starting at AD 1.
3644 * @param month the month starting at 1.
3645- * @param day the day of the month starting at 1.
3646+ * @param day the day of the month starting at 1.
3647 */
3648 public Cal set( int year, int month, int day )
3649 {
3650- calendar.set( year, month - 1, day );
3651+ dateUnit = new DateUnit( year, month, day );
3652 return this;
3653 }
3654
3655 /**
3656 * Sets the current month and day.
3657- *
3658 * @param month the month starting at 1.
3659- * @param day the day of the month starting at 1.
3660+ * @param day the day of the month starting at 1.
3661 */
3662 public Cal set( int month, int day )
3663 {
3664- calendar.set( Calendar.MONTH, month - 1 );
3665- calendar.set( Calendar.DAY_OF_MONTH, day );
3666+ dateUnit.setMonth( month );
3667+ dateUnit.setDay( day );
3668 return this;
3669- }
3670-
3671+ }
3672+
3673 /**
3674 * Sets the current time.
3675- *
3676 * @param date the date to base time on.
3677 */
3678 public Cal set( Date date )
3679 {
3680- calendar.setTime( date );
3681+ dateUnit = getCalendar().fromIso( DateUnit.fromJdkDate( date ) );
3682 return this;
3683 }
3684-
3685+
3686 /**
3687 * Returns the current date the cal.
3688 */
3689 public Date time()
3690 {
3691- return calendar.getTime();
3692+ return getCalendar().toIso( dateUnit ).toJdkDate();
3693 }
3694 }
3695
3696=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/CalendarPeriodType.java'
3697--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/CalendarPeriodType.java 2014-03-18 08:10:10 +0000
3698+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/CalendarPeriodType.java 2014-06-05 17:39:07 +0000
3699@@ -28,15 +28,17 @@
3700 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3701 */
3702
3703+import com.google.common.collect.Lists;
3704+import org.hisp.dhis.calendar.DateUnit;
3705+
3706 import java.util.ArrayList;
3707-import java.util.Calendar;
3708 import java.util.Date;
3709 import java.util.List;
3710
3711 /**
3712 * The superclass of all PeriodTypes which represent typical calendar periods
3713 * like days, weeks, months, etc.
3714- *
3715+ *
3716 * @author Torgeir Lorange Ostby
3717 * @version $Id: CalendarPeriodType.java 2952 2007-03-01 23:40:10Z torgeilo $
3718 */
3719@@ -57,7 +59,7 @@
3720 * Periods are returned. If the given Period is of different PeriodType than
3721 * the executing PeriodType, or the given Period is invalid, the returned
3722 * Period might overlap the given Period.
3723- *
3724+ *
3725 * @param period the Period to base the next Period on.
3726 * @return a Period which is the next of the given Period.
3727 */
3728@@ -68,7 +70,7 @@
3729 * Periods are returned. If the given Period is of different PeriodType than
3730 * the executing PeriodType, or the given Period is invalid, the returned
3731 * Period might overlap the given Period.
3732- *
3733+ *
3734 * @param period the Period to base the previous Period on.
3735 * @return a Period which is the previous of the given Period.
3736 */
3737@@ -79,73 +81,83 @@
3738 * Period. E.g. if the given Period is March 2007, and a monthly PeriodType
3739 * generates for a year, all months in 2007 should be generated and returned
3740 * in order.
3741- *
3742+ *
3743 * @param period the Period which touches the time span to generate Periods
3744- * for.
3745+ * for.
3746 * @return a list of Periods for a defined time span.
3747 */
3748 public List<Period> generatePeriods( Period period )
3749 {
3750 return generatePeriods( period.getStartDate() );
3751- }
3752-
3753+ }
3754+
3755 /**
3756 * Generates a list of Periods for a defined time span containing the given
3757 * date. E.g. if the given date is March 2007, and a monthly PeriodType
3758 * generates for a year, all months in 2007 should be generated and returned
3759 * in order.
3760- *
3761+ *
3762 * @param date the date which touches the time span to generate Periods for.
3763 * @return a list of Periods for a defined time span.
3764 */
3765- public abstract List<Period> generatePeriods( Date date );
3766-
3767- public abstract List<Period> generateRollingPeriods( Date date );
3768-
3769+ public List<Period> generatePeriods( Date date )
3770+ {
3771+ return generatePeriods( createLocalDateUnitInstance( date ) );
3772+ }
3773+
3774+ public abstract List<Period> generatePeriods( DateUnit dateUnit );
3775+
3776+ public List<Period> generateRollingPeriods( Date date )
3777+ {
3778+ return generateRollingPeriods( createLocalDateUnitInstance( date ) );
3779+ }
3780+
3781+ public abstract List<Period> generateRollingPeriods( DateUnit dateUnit );
3782+
3783 /**
3784 * Generates a list of Periods for the last 5 years. Must be overridden by
3785 * CalendarPeriodTypes which do not generate periods for the current year
3786 * only in their implementation of generatePeriods( Date ).
3787- *
3788+ *
3789 * @param date the date which touches the time span to generate Periods for.
3790 * @return a list of Periods for a defined time span.
3791 */
3792 public List<Period> generateLast5Years( Date date )
3793 {
3794- ArrayList<Period> periods = new ArrayList<Period>();
3795- Calendar cal = createCalendarInstance( date );
3796- cal.add( Calendar.YEAR, -4 );
3797-
3798+ DateUnit dateUnit = createLocalDateUnitInstance( date );
3799+ dateUnit = getCalendar().minusYears( dateUnit, 4 );
3800+ List<Period> periods = Lists.newArrayList();
3801+
3802 for ( int i = 0; i < 5; i++ )
3803 {
3804- periods.addAll( generatePeriods( cal.getTime() ) );
3805- cal.add( Calendar.YEAR, 1 );
3806+ periods.addAll( generatePeriods( dateUnit ) );
3807+ dateUnit = getCalendar().plusYears( dateUnit, 1 );
3808 }
3809-
3810+
3811 return periods;
3812 }
3813-
3814+
3815 /**
3816 * Generates a list of all Periods between the given start and end date. The
3817 * first period will span the start date. The last period will span the end
3818 * date.
3819- *
3820+ *
3821 * @param startDate the start date.
3822- * @param endDate the end date.
3823+ * @param endDate the end date.
3824 * @return a list of Periods for the defined time span.
3825 */
3826 public List<Period> generatePeriods( Date startDate, Date endDate )
3827 {
3828 List<Period> periods = new ArrayList<Period>();
3829-
3830+
3831 Period period = createPeriod( startDate );
3832-
3833+
3834 while ( period.getStartDate().before( endDate ) )
3835 {
3836 periods.add( period );
3837 period = getNextPeriod( period );
3838 }
3839-
3840+
3841 return periods;
3842 }
3843 }
3844
3845=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/DailyPeriodType.java'
3846--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/DailyPeriodType.java 2014-03-18 08:10:10 +0000
3847+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/DailyPeriodType.java 2014-06-05 17:39:07 +0000
3848@@ -28,19 +28,17 @@
3849 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3850 */
3851
3852-import java.text.ParseException;
3853-import java.text.SimpleDateFormat;
3854-import java.util.ArrayList;
3855-import java.util.Calendar;
3856+import com.google.common.collect.Lists;
3857+import org.hisp.dhis.calendar.DateUnit;
3858+
3859 import java.util.Date;
3860 import java.util.List;
3861
3862 /**
3863 * PeriodType for daily Periods. A valid daily Period has equal startDate and
3864 * endDate.
3865- *
3866+ *
3867 * @author Torgeir Lorange Ostby
3868- * @version $Id: DailyPeriodType.java 2971 2007-03-03 18:54:56Z torgeilo $
3869 */
3870 public class DailyPeriodType
3871 extends CalendarPeriodType
3872@@ -70,31 +68,17 @@
3873 }
3874
3875 @Override
3876- public Period createPeriod()
3877- {
3878- return createPeriod( createCalendarInstance() );
3879- }
3880-
3881- @Override
3882- public Period createPeriod( Date date )
3883- {
3884- return createPeriod( createCalendarInstance( date ) );
3885- }
3886-
3887- @Override
3888- public Period createPeriod( Calendar cal )
3889- {
3890- Date date = cal.getTime();
3891-
3892- return new Period( this, date, date );
3893- }
3894-
3895+ public Period createPeriod( DateUnit dateUnit )
3896+ {
3897+ return toIsoPeriod( dateUnit );
3898+ }
3899+
3900 @Override
3901 public int getFrequencyOrder()
3902 {
3903 return FREQUENCY_ORDER;
3904 }
3905-
3906+
3907 // -------------------------------------------------------------------------
3908 // CalendarPeriodType functionality
3909 // -------------------------------------------------------------------------
3910@@ -102,10 +86,10 @@
3911 @Override
3912 public Period getNextPeriod( Period period )
3913 {
3914- Calendar cal = createCalendarInstance( period.getStartDate() );
3915- cal.add( Calendar.DAY_OF_YEAR, 1 );
3916+ DateUnit dateUnit = createLocalDateUnitInstance( period.getStartDate() );
3917+ dateUnit = getCalendar().plusDays( dateUnit, 1 );
3918
3919- Date date = cal.getTime();
3920+ Date date = getCalendar().toIso( dateUnit ).toJdkDate();
3921
3922 return new Period( this, date, date );
3923 }
3924@@ -113,75 +97,61 @@
3925 @Override
3926 public Period getPreviousPeriod( Period period )
3927 {
3928- Calendar cal = createCalendarInstance( period.getStartDate() );
3929- cal.add( Calendar.DAY_OF_YEAR, -1 );
3930+ DateUnit dateUnit = createLocalDateUnitInstance( period.getStartDate() );
3931+ dateUnit = getCalendar().minusDays( dateUnit, 1 );
3932
3933- Date date = cal.getTime();
3934+ Date date = getCalendar().toIso( dateUnit ).toJdkDate();
3935
3936 return new Period( this, date, date );
3937 }
3938-
3939+
3940 /**
3941 * Generates daily Periods for the whole year in which the given Period's
3942 * startDate exists.
3943 */
3944 @Override
3945- public List<Period> generatePeriods( Date date )
3946+ public List<Period> generatePeriods( DateUnit dateUnit )
3947 {
3948- Calendar cal = createCalendarInstance( date );
3949- cal.set( Calendar.DAY_OF_YEAR, 1 );
3950-
3951- int year = cal.get( Calendar.YEAR );
3952- ArrayList<Period> periods = new ArrayList<Period>();
3953-
3954- while ( cal.get( Calendar.YEAR ) == year )
3955+ dateUnit.setMonth( 1 );
3956+ dateUnit.setDay( 1 );
3957+
3958+ List<Period> periods = Lists.newArrayList();
3959+
3960+ int year = dateUnit.getYear();
3961+
3962+ while ( year == dateUnit.getYear() )
3963 {
3964- periods.add( createPeriod( cal.getTime() ) );
3965- cal.add( Calendar.DAY_OF_YEAR, 1 );
3966+ periods.add( createPeriod( dateUnit ) );
3967+ dateUnit = getCalendar().plusDays( dateUnit, 1 );
3968 }
3969
3970 return periods;
3971 }
3972
3973 /**
3974- * Generates the last 365 days where the last one is the day of the given
3975+ * Generates the last 365 days where the last one is the day of the given
3976 * date.
3977 */
3978 @Override
3979- public List<Period> generateRollingPeriods( Date date )
3980+ public List<Period> generateRollingPeriods( DateUnit dateUnit )
3981 {
3982- Calendar cal = createCalendarInstance( date );
3983- cal.set( Calendar.DAY_OF_MONTH, -364 );
3984-
3985- ArrayList<Period> periods = new ArrayList<Period>();
3986-
3987+ dateUnit = getCalendar().minusDays( dateUnit, 364 );
3988+
3989+ List<Period> periods = Lists.newArrayList();
3990+
3991 for ( int i = 0; i < 365; i++ )
3992 {
3993- periods.add( createPeriod( cal ) );
3994- cal.add( Calendar.MONTH, 1 );
3995- }
3996-
3997- return periods;
3998- }
3999-
4000- @Override
4001- public String getIsoDate( Period period )
4002- {
4003- return new SimpleDateFormat( ISO_FORMAT ).format( period.getStartDate() );
4004- }
4005-
4006- @Override
4007- public Period createPeriod( String isoDate )
4008- {
4009- try
4010- {
4011- Date date = new SimpleDateFormat( ISO_FORMAT ).parse( isoDate );
4012- return createPeriod( date );
4013- }
4014- catch ( ParseException e )
4015- {
4016- throw new RuntimeException( e );
4017- }
4018+ periods.add( createPeriod( dateUnit ) );
4019+ dateUnit = getCalendar().plusDays( dateUnit, 1 );
4020+ }
4021+
4022+ return periods;
4023+ }
4024+
4025+ @Override
4026+ public String getIsoDate( DateUnit dateUnit )
4027+ {
4028+ return String.format( "%d%02d%02d", dateUnit.getYear(), dateUnit.getMonth(), dateUnit.getDay() );
4029 }
4030
4031 @Override
4032@@ -189,16 +159,16 @@
4033 {
4034 return ISO_FORMAT;
4035 }
4036-
4037+
4038 @Override
4039 public Date getRewindedDate( Date date, Integer rewindedPeriods )
4040 {
4041- date = date != null ? date : new Date();
4042+ date = date != null ? date : new Date();
4043 rewindedPeriods = rewindedPeriods != null ? rewindedPeriods : 1;
4044
4045- Calendar cal = createCalendarInstance( date );
4046- cal.add( Calendar.DAY_OF_YEAR, (rewindedPeriods * -1) );
4047+ DateUnit dateUnit = createLocalDateUnitInstance( date );
4048+ dateUnit = getCalendar().minusDays( dateUnit, rewindedPeriods );
4049
4050- return cal.getTime();
4051+ return getCalendar().toIso( dateUnit ).toJdkDate();
4052 }
4053 }
4054
4055=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialAprilPeriodType.java'
4056--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialAprilPeriodType.java 2014-03-18 08:10:10 +0000
4057+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialAprilPeriodType.java 2014-06-05 17:39:07 +0000
4058@@ -28,6 +28,8 @@
4059 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4060 */
4061
4062+import org.hisp.dhis.calendar.DateUnit;
4063+
4064 import java.util.Calendar;
4065
4066 /**
4067@@ -58,11 +60,9 @@
4068 }
4069
4070 @Override
4071- public String getIsoDate( Period period )
4072+ public String getIsoDate( DateUnit dateUnit )
4073 {
4074- Calendar cal = createCalendarInstance( period.getStartDate() );
4075- int year = cal.get( Calendar.YEAR );
4076- return String.valueOf( year ) + "April";
4077+ return String.format( "%dApril", dateUnit.getYear() );
4078 }
4079
4080 @Override
4081
4082=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialJulyPeriodType.java'
4083--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialJulyPeriodType.java 2014-03-18 08:10:10 +0000
4084+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialJulyPeriodType.java 2014-06-05 17:39:07 +0000
4085@@ -28,6 +28,8 @@
4086 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4087 */
4088
4089+import org.hisp.dhis.calendar.DateUnit;
4090+
4091 import java.util.Calendar;
4092
4093 /**
4094@@ -58,11 +60,9 @@
4095 }
4096
4097 @Override
4098- public String getIsoDate( Period period )
4099+ public String getIsoDate( DateUnit dateUnit )
4100 {
4101- Calendar cal = createCalendarInstance( period.getStartDate() );
4102- int year = cal.get( Calendar.YEAR );
4103- return String.valueOf( year ) + "July";
4104+ return String.format( "%dJuly", dateUnit.getYear() );
4105 }
4106
4107 @Override
4108
4109=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialOctoberPeriodType.java'
4110--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialOctoberPeriodType.java 2014-03-18 08:10:10 +0000
4111+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialOctoberPeriodType.java 2014-06-05 17:39:07 +0000
4112@@ -28,6 +28,8 @@
4113 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4114 */
4115
4116+import org.hisp.dhis.calendar.DateUnit;
4117+
4118 import java.util.Calendar;
4119
4120 /**
4121@@ -50,7 +52,7 @@
4122 {
4123 return Calendar.OCTOBER;
4124 }
4125-
4126+
4127 @Override
4128 public String getName()
4129 {
4130@@ -58,11 +60,9 @@
4131 }
4132
4133 @Override
4134- public String getIsoDate( Period period )
4135+ public String getIsoDate( DateUnit dateUnit )
4136 {
4137- Calendar cal = createCalendarInstance( period.getStartDate() );
4138- int year = cal.get( Calendar.YEAR );
4139- return String.valueOf( year ) + "Oct";
4140+ return String.format( "%dOct", dateUnit.getYear() );
4141 }
4142
4143 @Override
4144
4145=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialPeriodType.java'
4146--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialPeriodType.java 2014-03-18 08:10:10 +0000
4147+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/FinancialPeriodType.java 2014-06-05 17:39:07 +0000
4148@@ -28,8 +28,9 @@
4149 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4150 */
4151
4152-import java.util.ArrayList;
4153-import java.util.Calendar;
4154+import com.google.common.collect.Lists;
4155+import org.hisp.dhis.calendar.DateUnit;
4156+
4157 import java.util.Date;
4158 import java.util.List;
4159
4160@@ -45,44 +46,37 @@
4161 private static final long serialVersionUID = 2649990007010207631L;
4162
4163 public static final int FREQUENCY_ORDER = 365;
4164-
4165+
4166 // -------------------------------------------------------------------------
4167 // Abstract methods
4168 // -------------------------------------------------------------------------
4169
4170 protected abstract int getBaseMonth();
4171-
4172+
4173 // -------------------------------------------------------------------------
4174 // PeriodType functionality
4175 // -------------------------------------------------------------------------
4176
4177 @Override
4178- public Period createPeriod()
4179- {
4180- return createPeriod( createCalendarInstance() );
4181- }
4182-
4183- @Override
4184- public Period createPeriod( Date date )
4185- {
4186- return createPeriod( createCalendarInstance( date ) );
4187- }
4188-
4189- @Override
4190- public Period createPeriod( Calendar cal )
4191- {
4192- boolean past = cal.get( Calendar.MONTH ) >= getBaseMonth();
4193-
4194- cal.set( Calendar.YEAR, past ? cal.get( Calendar.YEAR ) : cal.get( Calendar.YEAR ) - 1 );
4195- cal.set( Calendar.MONTH, getBaseMonth() );
4196- cal.set( Calendar.DATE, 1 );
4197-
4198- Date startDate = cal.getTime();
4199-
4200- cal.add( Calendar.YEAR, 1 );
4201- cal.set( Calendar.DAY_OF_YEAR, cal.get( Calendar.DAY_OF_YEAR ) - 1 );
4202-
4203- return new Period( this, startDate, cal.getTime() );
4204+ public Period createPeriod( DateUnit dateUnit )
4205+ {
4206+ boolean past = dateUnit.getMonth() >= (getBaseMonth() + 1);
4207+
4208+ if ( !past )
4209+ {
4210+ dateUnit = getCalendar().minusYears( dateUnit, 1 );
4211+ }
4212+
4213+ dateUnit.setMonth( getBaseMonth() + 1 );
4214+ dateUnit.setDay( 1 );
4215+
4216+ DateUnit start = new DateUnit( dateUnit );
4217+ DateUnit end = new DateUnit( dateUnit );
4218+
4219+ end = getCalendar().plusYears( end, 1 );
4220+ end = getCalendar().minusDays( end, 1 );
4221+
4222+ return toIsoPeriod( start, end );
4223 }
4224
4225 @Override
4226@@ -98,40 +92,40 @@
4227 @Override
4228 public Period getNextPeriod( Period period )
4229 {
4230- Calendar cal = createCalendarInstance( period.getStartDate() );
4231- cal.add( Calendar.YEAR, 1 );
4232- return createPeriod( cal );
4233+ DateUnit dateUnit = createLocalDateUnitInstance( period.getStartDate() );
4234+ dateUnit = getCalendar().plusYears( dateUnit, 1 );
4235+
4236+ return createPeriod( dateUnit );
4237 }
4238
4239 @Override
4240 public Period getPreviousPeriod( Period period )
4241 {
4242- Calendar cal = createCalendarInstance( period.getStartDate() );
4243- cal.add( Calendar.YEAR, -1 );
4244- return createPeriod( cal );
4245+ DateUnit dateUnit = createLocalDateUnitInstance( period.getStartDate() );
4246+ dateUnit = getCalendar().minusYears( dateUnit, 1 );
4247+
4248+ return createPeriod( dateUnit );
4249 }
4250
4251 /**
4252- * Generates financial yearly periods for the last 5, current and next 5
4253+ * Generates financial yearly periods for the last 5, current and next 5
4254 * financial years.
4255 */
4256 @Override
4257- public List<Period> generatePeriods( Date date )
4258+ public List<Period> generatePeriods( DateUnit dateUnit )
4259 {
4260- Calendar cal = createCalendarInstance( date );
4261-
4262- boolean past = cal.get( Calendar.MONTH ) >= getBaseMonth();
4263-
4264- cal.add( Calendar.YEAR, past ? -5 : -6 );
4265- cal.set( Calendar.MONTH, getBaseMonth() );
4266- cal.set( Calendar.DATE, 1 );
4267-
4268- ArrayList<Period> periods = new ArrayList<Period>();
4269-
4270- for ( int i = 0; i < 11; ++i )
4271+ boolean past = dateUnit.getMonth() >= (getBaseMonth() + 1);
4272+
4273+ List<Period> periods = Lists.newArrayList();
4274+
4275+ dateUnit = getCalendar().minusYears( dateUnit, past ? 5 : 6 );
4276+ dateUnit.setMonth( getBaseMonth() + 1 );
4277+ dateUnit.setDay( 1 );
4278+
4279+ for ( int i = 0; i < 11; i++ )
4280 {
4281- periods.add( createPeriod( cal ) );
4282- cal.add( Calendar.YEAR, 1 );
4283+ periods.add( createPeriod( dateUnit ) );
4284+ dateUnit = getCalendar().plusYears( dateUnit, 1 );
4285 }
4286
4287 return periods;
4288@@ -146,49 +140,43 @@
4289 {
4290 return generateLast5Years( date );
4291 }
4292-
4293+
4294+ @Override
4295+ public List<Period> generateRollingPeriods( DateUnit dateUnit )
4296+ {
4297+ return generateLast5Years( getCalendar().toIso( dateUnit ).toJdkDate() );
4298+ }
4299+
4300 @Override
4301 public List<Period> generateLast5Years( Date date )
4302 {
4303- Calendar cal = createCalendarInstance( date );
4304-
4305- boolean past = cal.get( Calendar.MONTH ) >= getBaseMonth();
4306-
4307- cal.add( Calendar.YEAR, past ? -4 : -5 );
4308- cal.set( Calendar.MONTH, getBaseMonth() );
4309- cal.set( Calendar.DATE, 1 );
4310-
4311- ArrayList<Period> periods = new ArrayList<Period>();
4312-
4313- for ( int i = 0; i < 5; ++i )
4314+ DateUnit dateUnit = createLocalDateUnitInstance( date );
4315+ boolean past = dateUnit.getMonth() >= (getBaseMonth() + 1);
4316+
4317+ List<Period> periods = Lists.newArrayList();
4318+
4319+ dateUnit = getCalendar().minusYears( dateUnit, past ? 4 : 5 );
4320+ dateUnit.setMonth( getBaseMonth() + 1 );
4321+ dateUnit.setDay( 1 );
4322+
4323+ for ( int i = 0; i < 5; i++ )
4324 {
4325- periods.add( createPeriod( cal ) );
4326- cal.add( Calendar.YEAR, 1 );
4327+ periods.add( createPeriod( dateUnit ) );
4328+ dateUnit = getCalendar().plusYears( dateUnit, 1 );
4329 }
4330
4331 return periods;
4332 }
4333
4334 @Override
4335- public Period createPeriod( String isoDate )
4336- {
4337- int year = Integer.parseInt( isoDate.substring( 0, 4 ) );
4338- Calendar cal = createCalendarInstance();
4339- cal.set( Calendar.YEAR, year );
4340- cal.set( Calendar.MONTH, 11 );
4341- cal.set( Calendar.DAY_OF_MONTH, 31 );
4342- return createPeriod( cal );
4343- }
4344-
4345- @Override
4346 public Date getRewindedDate( Date date, Integer rewindedPeriods )
4347 {
4348- date = date != null ? date : new Date();
4349+ date = date != null ? date : new Date();
4350 rewindedPeriods = rewindedPeriods != null ? rewindedPeriods : 1;
4351
4352- Calendar cal = createCalendarInstance( date );
4353- cal.add( Calendar.YEAR, (rewindedPeriods * -1) );
4354+ DateUnit dateUnit = createLocalDateUnitInstance( date );
4355+ dateUnit = getCalendar().minusYears( dateUnit, rewindedPeriods );
4356
4357- return cal.getTime();
4358+ return getCalendar().toIso( dateUnit ).toJdkDate();
4359 }
4360 }
4361
4362=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/MonthlyPeriodType.java'
4363--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/MonthlyPeriodType.java 2014-05-13 16:00:50 +0000
4364+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/MonthlyPeriodType.java 2014-06-05 17:39:07 +0000
4365@@ -28,10 +28,9 @@
4366 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4367 */
4368
4369-import java.text.ParseException;
4370-import java.text.SimpleDateFormat;
4371-import java.util.ArrayList;
4372-import java.util.Calendar;
4373+import com.google.common.collect.Lists;
4374+import org.hisp.dhis.calendar.DateUnit;
4375+
4376 import java.util.Date;
4377 import java.util.List;
4378
4379@@ -39,6 +38,7 @@
4380 * PeriodType for monthly Periods. A valid monthly Period has startDate set to
4381 * the first day of a calendar month, and endDate set to the last day of the
4382 * same month.
4383+ *
4384 * @author Torgeir Lorange Ostby
4385 * @version $Id: MonthlyPeriodType.java 2971 2007-03-03 18:54:56Z torgeilo $
4386 */
4387@@ -52,8 +52,6 @@
4388
4389 private static final String ISO_FORMAT = "yyyyMM";
4390
4391- private static final String ALTERNATIVE_ISO_FORMAT = "yyyy-MM";
4392-
4393 /**
4394 * The name of the MonthlyPeriodType, which is "Monthly".
4395 */
4396@@ -72,25 +70,15 @@
4397 }
4398
4399 @Override
4400- public Period createPeriod()
4401- {
4402- return createPeriod( createCalendarInstance() );
4403- }
4404-
4405- @Override
4406- public Period createPeriod( Date date )
4407- {
4408- return createPeriod( createCalendarInstance( date ) );
4409- }
4410-
4411- @Override
4412- public Period createPeriod( Calendar cal )
4413- {
4414- cal.set( Calendar.DAY_OF_MONTH, 1 );
4415- Date startDate = cal.getTime();
4416- cal.set( Calendar.DAY_OF_MONTH, cal.getActualMaximum( Calendar.DAY_OF_MONTH ) );
4417-
4418- return new Period( this, startDate, cal.getTime() );
4419+ public Period createPeriod( DateUnit dateUnit )
4420+ {
4421+ DateUnit start = new DateUnit( dateUnit );
4422+ start.setDay( 1 );
4423+
4424+ DateUnit end = new DateUnit( dateUnit );
4425+ end.setDay( getCalendar().daysInMonth( end.getYear(), end.getMonth() ) );
4426+
4427+ return toIsoPeriod( start, end );
4428 }
4429
4430 @Override
4431@@ -106,17 +94,19 @@
4432 @Override
4433 public Period getNextPeriod( Period period )
4434 {
4435- Calendar cal = createCalendarInstance( period.getStartDate() );
4436- cal.add( Calendar.MONTH, 1 );
4437- return createPeriod( cal );
4438+ DateUnit dateUnit = getCalendar().fromIso( DateUnit.fromJdkDate( period.getStartDate() ) );
4439+ dateUnit = getCalendar().plusMonths( dateUnit, 1 );
4440+
4441+ return createPeriod( getCalendar().toIso( dateUnit ) );
4442 }
4443
4444 @Override
4445 public Period getPreviousPeriod( Period period )
4446 {
4447- Calendar cal = createCalendarInstance( period.getStartDate() );
4448- cal.add( Calendar.MONTH, -1 );
4449- return createPeriod( cal );
4450+ DateUnit dateUnit = getCalendar().fromIso( DateUnit.fromJdkDate( period.getStartDate() ) );
4451+ dateUnit = getCalendar().minusMonths( dateUnit, 1 );
4452+
4453+ return createPeriod( getCalendar().toIso( dateUnit ) );
4454 }
4455
4456 /**
4457@@ -124,18 +114,19 @@
4458 * startDate exists.
4459 */
4460 @Override
4461- public List<Period> generatePeriods( Date date )
4462+ public List<Period> generatePeriods( DateUnit dateUnit )
4463 {
4464- Calendar cal = createCalendarInstance( date );
4465- cal.set( Calendar.DAY_OF_YEAR, 1 );
4466-
4467- int year = cal.get( Calendar.YEAR );
4468- ArrayList<Period> periods = new ArrayList<Period>();
4469-
4470- while ( cal.get( Calendar.YEAR ) == year )
4471+ dateUnit.setMonth( 1 );
4472+ dateUnit.setDay( 1 );
4473+
4474+ List<Period> periods = Lists.newArrayList();
4475+
4476+ int year = dateUnit.getYear();
4477+
4478+ while ( dateUnit.getYear() == year )
4479 {
4480- periods.add( createPeriod( cal ) );
4481- cal.add( Calendar.MONTH, 1 );
4482+ periods.add( createPeriod( dateUnit ) );
4483+ dateUnit = getCalendar().plusMonths( dateUnit, 1 );
4484 }
4485
4486 return periods;
4487@@ -146,51 +137,26 @@
4488 * given date is inside.
4489 */
4490 @Override
4491- public List<Period> generateRollingPeriods( Date date )
4492+ public List<Period> generateRollingPeriods( DateUnit dateUnit )
4493 {
4494- Calendar cal = createCalendarInstance( date );
4495- cal.set( Calendar.DAY_OF_MONTH, 1 );
4496- cal.add( Calendar.MONTH, -11 );
4497+ dateUnit.setDay( 1 );
4498+ dateUnit = getCalendar().minusMonths( dateUnit, 11 );
4499
4500- ArrayList<Period> periods = new ArrayList<Period>();
4501+ List<Period> periods = Lists.newArrayList();
4502
4503 for ( int i = 0; i < 12; i++ )
4504 {
4505- periods.add( createPeriod( cal ) );
4506- cal.add( Calendar.MONTH, 1 );
4507+ periods.add( createPeriod( dateUnit ) );
4508+ dateUnit = getCalendar().plusMonths( dateUnit, 1 );
4509 }
4510
4511 return periods;
4512 }
4513
4514 @Override
4515- public String getIsoDate( Period period )
4516- {
4517- return new SimpleDateFormat( ISO_FORMAT ).format( period.getStartDate() );
4518- }
4519-
4520- @Override
4521- public Period createPeriod( String isoDate )
4522- {
4523- try
4524- {
4525- Date date = new SimpleDateFormat( ISO_FORMAT ).parse( isoDate );
4526- return createPeriod( date );
4527- }
4528- catch ( ParseException ex )
4529- {
4530- // Ignore and try alternative format
4531- }
4532-
4533- try
4534- {
4535- Date date = new SimpleDateFormat( ALTERNATIVE_ISO_FORMAT ).parse( isoDate );
4536- return createPeriod( date );
4537- }
4538- catch ( ParseException ex )
4539- {
4540- throw new RuntimeException( ex );
4541- }
4542+ public String getIsoDate( DateUnit dateUnit )
4543+ {
4544+ return String.format( "%d%02d", dateUnit.getYear(), dateUnit.getMonth() );
4545 }
4546
4547 @Override
4548@@ -205,9 +171,9 @@
4549 date = date != null ? date : new Date();
4550 rewindedPeriods = rewindedPeriods != null ? rewindedPeriods : 1;
4551
4552- Calendar cal = createCalendarInstance( date );
4553- cal.add( Calendar.MONTH, (rewindedPeriods * -1) );
4554+ DateUnit dateUnit = getCalendar().fromIso( DateUnit.fromJdkDate( date ) );
4555+ dateUnit = getCalendar().minusMonths( dateUnit, rewindedPeriods );
4556
4557- return cal.getTime();
4558+ return getCalendar().toIso( dateUnit ).toJdkDate();
4559 }
4560 }
4561
4562=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/PeriodType.java'
4563--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/PeriodType.java 2014-05-13 16:00:50 +0000
4564+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/PeriodType.java 2014-06-05 17:39:07 +0000
4565@@ -30,13 +30,15 @@
4566
4567 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
4568 import org.hisp.dhis.calendar.CalendarService;
4569+import org.hisp.dhis.calendar.DateInterval;
4570+import org.hisp.dhis.calendar.DateUnit;
4571+import org.hisp.dhis.calendar.DateUnitPeriodTypeParser;
4572+import org.hisp.dhis.calendar.DateUnitType;
4573+import org.hisp.dhis.calendar.PeriodTypeParser;
4574 import org.hisp.dhis.calendar.impl.Iso8601Calendar;
4575 import org.hisp.dhis.common.DxfNamespaces;
4576-import org.springframework.beans.factory.annotation.Autowired;
4577
4578 import java.io.Serializable;
4579-import java.text.ParseException;
4580-import java.text.SimpleDateFormat;
4581 import java.util.ArrayList;
4582 import java.util.Calendar;
4583 import java.util.Date;
4584@@ -47,9 +49,10 @@
4585
4586 /**
4587 * The superclass of all PeriodTypes.
4588+ *
4589 * @author Kristian Nordal
4590 */
4591-@JacksonXmlRootElement(localName = "periodType", namespace = DxfNamespaces.DXF_2_0)
4592+@JacksonXmlRootElement( localName = "periodType", namespace = DxfNamespaces.DXF_2_0 )
4593 public abstract class PeriodType
4594 implements Serializable
4595 {
4596@@ -58,15 +61,19 @@
4597 */
4598 private static final long serialVersionUID = 2402122626196305083L;
4599
4600- private CalendarService calendarService;
4601-
4602- @Autowired
4603- public void setCalendarService( CalendarService calendarService )
4604- {
4605- this.calendarService = calendarService;
4606- }
4607-
4608- public org.hisp.dhis.calendar.Calendar getCalendar()
4609+ private static CalendarService calendarService;
4610+
4611+ public static void setCalendarService( CalendarService calendarService )
4612+ {
4613+ PeriodType.calendarService = calendarService;
4614+ }
4615+
4616+ public static CalendarService getCalendarService()
4617+ {
4618+ return calendarService;
4619+ }
4620+
4621+ public static org.hisp.dhis.calendar.Calendar getCalendar()
4622 {
4623 if ( calendarService != null )
4624 {
4625@@ -76,6 +83,8 @@
4626 return Iso8601Calendar.getInstance();
4627 }
4628
4629+ protected PeriodTypeParser dateUnitFormat = new DateUnitPeriodTypeParser();
4630+
4631 // -------------------------------------------------------------------------
4632 // Available PeriodTypes
4633 // -------------------------------------------------------------------------
4634@@ -112,6 +121,7 @@
4635
4636 /**
4637 * Returns an immutable list of all available PeriodTypes in their natural order.
4638+ *
4639 * @return all available PeriodTypes in their natural order.
4640 */
4641 public static List<PeriodType> getAvailablePeriodTypes()
4642@@ -121,6 +131,7 @@
4643
4644 /**
4645 * Returns a PeriodType with a given name.
4646+ *
4647 * @param name the name of the PeriodType to return.
4648 * @return the PeriodType with the given name or null if no such PeriodType
4649 * exists.
4650@@ -145,6 +156,7 @@
4651
4652 /**
4653 * Get period type according to natural order order.
4654+ *
4655 * @param index the index of the period type with base 1
4656 * @return period type according to index order or null if no match
4657 * TODO: Consider manual ordering, since relying on natural order might create problems if new periods are introduced.
4658@@ -183,6 +195,7 @@
4659
4660 /**
4661 * Returns a unique name for the PeriodType.
4662+ *
4663 * @return a unique name for the PeriodType. E.g. "Monthly".
4664 */
4665 public abstract String getName();
4666@@ -190,29 +203,54 @@
4667 /**
4668 * Creates a valid Period based on the current date. E.g. if today is
4669 * January 5. 2007, a monthly PeriodType should return January 2007.
4670+ *
4671 * @return a valid Period based on the current date.
4672 */
4673- public abstract Period createPeriod();
4674+ public Period createPeriod()
4675+ {
4676+ return createPeriod( createCalendarInstance() );
4677+ }
4678
4679 /**
4680 * Creates a valid Period based on the given date. E.g. the given date is
4681 * February 10. 2007, a monthly PeriodType should return February 2007.
4682+ *
4683 * @param date the date which is contained by the created period.
4684 * @return the valid Period based on the given date
4685 */
4686- public abstract Period createPeriod( Date date );
4687-
4688- public abstract Period createPeriod( Calendar cal );
4689+ public Period createPeriod( Date date )
4690+ {
4691+ return createPeriod( createCalendarInstance( date ) );
4692+ }
4693+
4694+ public Period createPeriod( Calendar cal )
4695+ {
4696+ return createPeriod( getCalendar().fromIso( DateUnit.fromJdkCalendar( cal ) ) );
4697+ }
4698+
4699+ public Period toIsoPeriod( DateUnit start, DateUnit end )
4700+ {
4701+ return new Period( this, getCalendar().toIso( start ).toJdkDate(), getCalendar().toIso( end ).toJdkDate() );
4702+ }
4703+
4704+ public Period toIsoPeriod( DateUnit dateUnit )
4705+ {
4706+ return toIsoPeriod( dateUnit, dateUnit );
4707+ }
4708+
4709+ public abstract Period createPeriod( DateUnit dateUnit );
4710
4711 /**
4712 * Returns a comparable value for the frequency length of this PeriodType.
4713 * Shortest is 0.
4714+ *
4715 * @return the frequency order.
4716 */
4717 public abstract int getFrequencyOrder();
4718
4719 /**
4720 * Returns a new date rewinded from now.
4721+ *
4722 * @return the Date.
4723 */
4724 public abstract Date getRewindedDate( Date date, Integer rewindedPeriods );
4725@@ -224,20 +262,18 @@
4726 /**
4727 * Returns an instance of a Calendar without any time of day, with the
4728 * current date.
4729+ *
4730 * @return an instance of a Calendar without any time of day.
4731 */
4732 public static Calendar createCalendarInstance()
4733 {
4734- Calendar calendar = new GregorianCalendar();
4735-
4736- clearTimeOfDay( calendar );
4737-
4738- return calendar;
4739+ return getCalendar().toIso( getCalendar().today() ).toJdkCalendar();
4740 }
4741
4742 /**
4743 * Returns an instance of a Calendar without any time of day, with the given
4744 * date.
4745+ *
4746 * @param date the date of the Calendar.
4747 * @return an instance of a Calendar without any time of day.
4748 */
4749@@ -252,7 +288,19 @@
4750 }
4751
4752 /**
4753+ * Returns an instance of a DateUnit.
4754+ *
4755+ * @param date date of calendar in local calendar
4756+ * @return an instance of a Calendar without any time of day.
4757+ */
4758+ public static DateUnit createLocalDateUnitInstance( Date date )
4759+ {
4760+ return getCalendar().fromIso( DateUnit.fromJdkDate( date ) );
4761+ }
4762+
4763+ /**
4764 * Clears the time of day in a Calendar instance.
4765+ *
4766 * @param calendar the Calendar to fix.
4767 */
4768 public static void clearTimeOfDay( Calendar calendar )
4769@@ -264,85 +312,24 @@
4770 }
4771
4772 /**
4773- * Parses a date from a String on the format YYYY-MM-DD.
4774- * @param dateString the String to parse.
4775- * @return a Date based on the given String.
4776- */
4777- public static Date getMediumDate( String dateString )
4778- {
4779- try
4780- {
4781- final SimpleDateFormat format = new SimpleDateFormat();
4782- format.applyPattern( "yyyy-MM-dd" );
4783- return dateString != null ? format.parse( dateString ) : null;
4784- }
4785- catch ( ParseException ex )
4786- {
4787- throw new RuntimeException( "Failed to parse medium date", ex );
4788- }
4789- }
4790-
4791- /**
4792 * Returns a PeriodType corresponding to the provided string The test is
4793 * quite rudimentary, testing for string format rather than invalid periods.
4794 * Currently only recognizes the basic subset of common period types.
4795+ *
4796 * @param isoPeriod String formatted period (2011, 201101, 2011W34, 2011Q1
4797 * etc
4798 * @return the PeriodType or null if unrecognized
4799 */
4800 public static PeriodType getPeriodTypeFromIsoString( String isoPeriod )
4801 {
4802- if ( isoPeriod.matches( "\\b\\d{4}\\b" ) )
4803- {
4804- return PERIOD_TYPE_MAP.get( YearlyPeriodType.NAME );
4805- }
4806- if ( isoPeriod.matches( "\\b\\d{4}[-]?\\d{2}\\b" ) )
4807- {
4808- return PERIOD_TYPE_MAP.get( MonthlyPeriodType.NAME );
4809- }
4810- if ( isoPeriod.matches( "\\b\\d{4}W\\d[\\d]?\\b" ) )
4811- {
4812- return PERIOD_TYPE_MAP.get( WeeklyPeriodType.NAME );
4813- }
4814- if ( isoPeriod.matches( "\\b\\d{8}\\b" ) )
4815- {
4816- return PERIOD_TYPE_MAP.get( DailyPeriodType.NAME );
4817- }
4818- if ( isoPeriod.matches( "\\b\\d{4}Q\\d\\b" ) )
4819- {
4820- return PERIOD_TYPE_MAP.get( QuarterlyPeriodType.NAME );
4821- }
4822- if ( isoPeriod.matches( "\\b\\d{4}S\\d\\b" ) )
4823- {
4824- return PERIOD_TYPE_MAP.get( SixMonthlyPeriodType.NAME );
4825- }
4826- if ( isoPeriod.matches( "\\b\\d{4}AprilS\\d\\b" ) )
4827- {
4828- return PERIOD_TYPE_MAP.get( SixMonthlyAprilPeriodType.NAME );
4829- }
4830- if ( isoPeriod.matches( "\\b\\d{6}B\\b" ) )
4831- {
4832- return PERIOD_TYPE_MAP.get( BiMonthlyPeriodType.NAME );
4833- }
4834- if ( isoPeriod.matches( "\\b\\d{4}April\\b" ) )
4835- {
4836- return PERIOD_TYPE_MAP.get( FinancialAprilPeriodType.NAME );
4837- }
4838- if ( isoPeriod.matches( "\\b\\d{4}July\\b" ) )
4839- {
4840- return PERIOD_TYPE_MAP.get( FinancialJulyPeriodType.NAME );
4841- }
4842- if ( isoPeriod.matches( "\\b\\d{4}Oct\\b" ) )
4843- {
4844- return PERIOD_TYPE_MAP.get( FinancialOctoberPeriodType.NAME );
4845- }
4846-
4847- return null;
4848+ DateUnitType dateUnitType = DateUnitType.find( isoPeriod );
4849+ return dateUnitType != null ? PERIOD_TYPE_MAP.get( dateUnitType.getType() ) : null;
4850 }
4851
4852 /**
4853 * Returns a period type based on the given date string in ISO format. Returns
4854 * null if the date string cannot be parsed to a date.
4855+ *
4856 * @param isoPeriod the date string in ISO format.
4857 * @return a period.
4858 */
4859@@ -368,6 +355,7 @@
4860 /**
4861 * Return the potential number of periods of the given period type which is
4862 * spanned by this period.
4863+ *
4864 * @param type the period type.
4865 * @return the potential number of periods of the given period type spanned
4866 * by this period.
4867@@ -384,21 +372,55 @@
4868 // -------------------------------------------------------------------------
4869
4870 /**
4871+ * @param dateInterval DateInterval to create period from
4872+ * @return the period.
4873+ */
4874+ public Period createPeriod( DateInterval dateInterval )
4875+ {
4876+ if ( dateInterval == null || dateInterval.getFrom() == null || dateInterval.getTo() == null )
4877+ {
4878+ return null;
4879+ }
4880+
4881+ final DateUnit from = getCalendar().toIso( dateInterval.getFrom() );
4882+ final DateUnit to = getCalendar().toIso( dateInterval.getTo() );
4883+
4884+ return new Period( this, from.toJdkDate(), to.toJdkDate() );
4885+ }
4886+
4887+ /**
4888 * Returns an iso8601 formatted string representation of the period
4889+ *
4890 * @param period Period
4891 * @return the period as string
4892 */
4893- public abstract String getIsoDate( Period period );
4894+ public String getIsoDate( Period period )
4895+ {
4896+ return getIsoDate( createLocalDateUnitInstance( period.getStartDate() ) );
4897+ }
4898+
4899+ /**
4900+ * Returns an iso8601 formatted string representation of the dataUnit
4901+ *
4902+ * @param dateUnit Period
4903+ * @return the period as string
4904+ */
4905+ public abstract String getIsoDate( DateUnit dateUnit );
4906
4907 /**
4908 * Generates a period based on the given iso8601 formatted string.
4909+ *
4910 * @param isoDate the iso8601 string.
4911 * @return the period.
4912 */
4913- public abstract Period createPeriod( String isoDate );
4914+ public Period createPeriod( String isoDate )
4915+ {
4916+ return createPeriod( dateUnitFormat.parse( isoDate ) );
4917+ }
4918
4919 /**
4920 * Returns the iso8601 format as a string for this period type.
4921+ *
4922 * @return the iso8601 format.
4923 */
4924 public abstract String getIsoFormat();
4925
4926=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/QuarterlyPeriodType.java'
4927--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/QuarterlyPeriodType.java 2014-03-18 08:10:10 +0000
4928+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/QuarterlyPeriodType.java 2014-06-05 17:39:07 +0000
4929@@ -28,7 +28,9 @@
4930 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4931 */
4932
4933-import java.util.ArrayList;
4934+import com.google.common.collect.Lists;
4935+import org.hisp.dhis.calendar.DateUnit;
4936+
4937 import java.util.Calendar;
4938 import java.util.Date;
4939 import java.util.List;
4940@@ -37,7 +39,7 @@
4941 * PeriodType for quarterly Periods. A valid quarterly Period has startDate set
4942 * to the first day of a calendar quarter, and endDate set to the last day of
4943 * the same quarter.
4944- *
4945+ *
4946 * @author Torgeir Lorange Ostby
4947 * @version $Id: QuarterlyPeriodType.java 2971 2007-03-03 18:54:56Z torgeilo $
4948 */
4949@@ -69,29 +71,18 @@
4950 }
4951
4952 @Override
4953- public Period createPeriod()
4954- {
4955- return createPeriod( createCalendarInstance() );
4956- }
4957-
4958- @Override
4959- public Period createPeriod( Date date )
4960- {
4961- return createPeriod( createCalendarInstance( date ) );
4962- }
4963-
4964- @Override
4965- public Period createPeriod( Calendar cal )
4966- {
4967- cal.set( Calendar.MONTH, cal.get( Calendar.MONTH ) - cal.get( Calendar.MONTH ) % 3 );
4968- cal.set( Calendar.DAY_OF_MONTH, 1 );
4969-
4970- Date startDate = cal.getTime();
4971-
4972- cal.add( Calendar.MONTH, 2 );
4973- cal.set( Calendar.DAY_OF_MONTH, cal.getActualMaximum( Calendar.DAY_OF_MONTH ) );
4974-
4975- return new Period( this, startDate, cal.getTime() );
4976+ public Period createPeriod( DateUnit dateUnit )
4977+ {
4978+ DateUnit start = new DateUnit( dateUnit );
4979+
4980+ start.setMonth( ((dateUnit.getMonth() - 1) - ((dateUnit.getMonth() - 1) % 3)) + 1 );
4981+ start.setDay( 1 );
4982+
4983+ DateUnit end = new DateUnit( start );
4984+ end = getCalendar().plusMonths( end, 2 );
4985+ end.setDay( getCalendar().daysInMonth( end.getYear(), end.getMonth() ) );
4986+
4987+ return toIsoPeriod( start, end );
4988 }
4989
4990 @Override
4991@@ -107,17 +98,19 @@
4992 @Override
4993 public Period getNextPeriod( Period period )
4994 {
4995- Calendar cal = createCalendarInstance( period.getStartDate() );
4996- cal.add( Calendar.MONTH, 3 );
4997- return createPeriod( cal );
4998+ DateUnit dateUnit = createLocalDateUnitInstance( period.getStartDate() );
4999+ dateUnit = getCalendar().plusMonths( dateUnit, 3 );
5000+
The diff has been truncated for viewing.