From 89a698bc02a9af76989bb983ecd3af1b210c3d65 Mon Sep 17 00:00:00 2001 From: Steve Harris Date: Fri, 8 Feb 2013 15:59:40 -0600 Subject: [PATCH] 13.2.1-6 baseline Former-commit-id: c5df294c580862d0ac52b44bc473d4512f77cf2e --- .../bundles/DefaultRadarDualPolBaseData.xml | 704 +---------------- .../DefaultRadarDualPolFourPanelZHCML.xml | 717 +----------------- .../etc/bundles/DefaultRadarDualPolHCA.xml | 381 +--------- .../DefaultRadarDualPolPrecipAnalysis.xml | 62 +- .../raytheon/uf/viz/core/RecordFactory.java | 64 +- .../core/drawables/AbstractDescriptor.java | 22 +- .../localization/CAVELocalizationAdapter.java | 2 +- .../localization/LocalizationManager.java | 2 +- .../rsc/AbstractRequestableResourceData.java | 19 +- .../uf/viz/d2d/core/time/D2DTimeMatcher.java | 10 +- .../ui/dialogs/procedures/HistoryListDlg.java | 41 +- .../dialogs/procedures/ProcedureLoadJob.java | 15 +- .../raytheon/uf/viz/d2d/ui/map/SideView.java | 15 +- .../feature.xml | 7 + .../META-INF/MANIFEST.MF | 4 +- .../res/spring/datadelivery-services.xml | 6 +- .../bandwidth/ui/BandwidthCanvasComp.java | 4 +- .../bandwidth/ui/BandwidthImageMgr.java | 27 +- .../datadelivery/bandwidth/ui/GraphImage.java | 12 +- .../bandwidth/ui/IGraphOptions.java | 2 +- .../bandwidth/ui/XHeaderImage.java | 5 +- .../datadelivery/browser/DataBrowserDlg.java | 4 + .../datadelivery/common/ui/PriorityComp.java | 32 +- .../common/ui/UserSelectComp.java | 1 + .../notification/NotificationDlg.java | 49 +- .../notification/NotificationTableComp.java | 57 +- .../services/DataDeliveryServices.java | 25 +- .../subscription/CreateSubscriptionDlg.java | 21 +- .../subscription/DeleteGroupDlg.java | 15 +- .../subscription/GroupAddDlg.java | 1 + .../RequestFromServerPermissionsService.java | 14 +- .../subscription/SubscriptionManagerDlg.java | 84 +- .../SubscriptionManagerRowData.java | 5 +- .../subscription/SubscriptionService.java | 5 + .../subscription/SubscriptionTableComp.java | 16 +- .../approve/SubApprovalTableComp.java | 8 +- .../approve/SubscriptionApprovalDlg.java | 2 +- .../approve/SubscriptionDiff.java | 3 +- .../CreateSubscriptionDlgPresenter.java | 28 +- .../subset/GriddedEnsembleSubsetTab.java | 177 +++++ .../subset/GriddedSubsetManagerDlg.java | 101 ++- .../subset/GriddedTimingSelectionDlg.java | 9 +- .../subscription/subset/SubsetManagerDlg.java | 196 ++--- .../subset/VerticalSubsetTab.java | 2 +- .../GriddedTimingSelectionPresenter.java | 30 +- .../IGriddedTimingSelectionDlgView.java | 7 +- .../subscription/subset/xml/SubsetXML.java | 19 + .../view/ICreateSubscriptionDlgView.java | 15 +- .../subscription/xml/OperatorAdapter.java | 74 +- .../subscription/xml/PriorityRuleXML.java | 9 +- .../subscription/xml/RuleXML.java | 41 +- .../system/CreateEditRuleDlg.java | 105 ++- .../system/IRulesUpdateListener.java | 42 +- .../uf/viz/datadelivery/system/Operator.java | 9 +- .../datadelivery/system/SystemLatencyTab.java | 8 +- .../system/SystemManagementDlg.java | 58 +- .../system/SystemPriorityTab.java | 5 +- .../system/SystemRuleManager.java | 258 +++++-- .../utils/DataDeliveryGUIUtils.java | 65 +- .../datadelivery/utils/DataDeliveryUtils.java | 74 +- .../datadelivery/utils/DataSetFrequency.java | 21 +- .../utils/NotificationHandler.java | 17 +- .../uf/viz/monitor/ffmp/FFMPMonitor.java | 121 ++- .../monitor/ffmp/ui/rsc/FFMPDataLoader.java | 335 ++++---- .../viz/monitor/ffmp/ui/rsc/FFMPResource.java | 33 +- .../monitor/ffmp/ui/rsc/FFMPResourceData.java | 30 +- .../viz/npp/crimss/map/CrimssMapResource.java | 4 +- .../viz/plugin/nwsauth/NwsNotAuthHandler.java | 4 +- ...questableProductBrowserDataDefinition.java | 17 +- .../raytheon/uf/viz/spring/dm/Activator.java | 268 ++++--- .../META-INF/MANIFEST.MF | 3 +- .../uf/viz/stats/ui/GroupingComp.java | 149 ++-- .../com/raytheon/uf/viz/stats/ui/HideDlg.java | 161 ++++ .../uf/viz/stats/ui/IGroupSelection.java | 31 +- .../uf/viz/stats/ui/IStatsDisplay.java | 27 +- .../uf/viz/stats/ui/SelectionEntry.java | 87 +++ .../uf/viz/stats/ui/SelectionManagerDlg.java | 45 +- .../uf/viz/stats/ui/StatsControlDlg.java | 24 +- .../uf/viz/stats/ui/StatsDisplayCanvas.java | 380 +++++++--- .../uf/viz/stats/ui/StatsGraphDlg.java | 251 +++--- .../thinclient/cave/ThinClientComponent.java | 10 +- .../menus/widgets/BundleContributionItem.java | 21 +- .../observers/ProductAlertObserver.java | 85 +-- .../raytheon/viz/gfe/BaseGfePyController.java | 18 + .../raytheon/viz/gfe/core/parm/DbParm.java | 19 +- .../viz/gfe/gridmanager/GridCanvas.java | 29 +- .../viz/gfe/ifpimage/ImageLegendResource.java | 21 +- .../viz/gfe/procedures/ProcedureJob.java | 2 + .../viz/gfe/rsc/GFELegendResource.java | 179 ++--- .../gfe/rsc/colorbar/DiscreteColorbar.java | 79 +- .../gfe/rsc/colorbar/GFEColorbarResource.java | 10 +- .../gfe/smarttool/script/SmartToolJob.java | 2 + .../GridProductBrowserDataDefinition.java | 45 ++ .../raytheon/viz/grid/inv/GridUpdater.java | 2 +- .../raytheon/viz/grid/inv/RadarUpdater.java | 2 +- .../rsc/general/AbstractGridResource.java | 8 + .../viz/lightning/LightningResourceData.java | 10 + .../pointdata/rsc/MetarPrecipResource.java | 91 ++- .../rsc/MetarPrecipResourceData.java | 10 + .../util/PointMetadataContainer.java | 16 +- .../awips/AbstractCAVEComponent.java | 13 +- .../src/com/raytheon/viz/ui/BundleLoader.java | 346 +++++++++ .../raytheon/viz/ui/BundleProductLoader.java | 168 ++++ .../src/com/raytheon/viz/ui/HistoryList.java | 5 +- .../src/com/raytheon/viz/ui/MenuLoader.java | 350 --------- .../viz/ui/actions/LoadSerializedXml.java | 146 +--- .../AbstractVizPerspectiveManager.java | 20 +- .../viz/ui/tools/AbstractModalTool.java | 1 + .../volumebrowser/vbui/ProductTableComp.java | 4 +- .../config/DbAreaSourceDataAdaptor.java | 4 +- .../com/raytheon/viz/warngen/gis/Area.java | 6 +- .../com/raytheon/viz/warngen/gis/GisUtil.java | 22 +- .../raytheon/viz/warngen/gis/PolygonUtil.java | 36 +- .../viz/warngen/gui/WarngenLayer.java | 213 +++--- .../viz/warngen/util/CurrentWarnings.java | 68 +- .../viz/warnings/rsc/WarningsResource.java | 205 ++--- .../viz/warnings/rsc/WatchesResource.java | 3 + cots/org.junit/.classpath | 3 +- cots/org.junit/META-INF/MANIFEST.MF | 23 +- cots/org.junit/build.properties | 3 +- cots/org.junit/hamcrest-all-1.3-sources.jar | Bin 0 -> 87801 bytes cots/org.junit/hamcrest-all-1.3.jar | Bin 0 -> 306578 bytes cots/org.junit/junit-4.10-src.jar | Bin 141185 -> 0 bytes cots/org.junit/junit-4.10.jar | Bin 253160 -> 0 bytes cots/org.junit/junit-4.11-src.jar | Bin 0 -> 151329 bytes cots/org.junit/junit-dep-4.11.jar | Bin 0 -> 245039 bytes .../13.2.1/aggregateRecordGroupingLength.sh | 23 + .../convertAggregateRecordGroupToXml.sh | 23 + .../convertAggregateRecordGroupToXml.sql | 38 + .../increaseAggregateRecordGroupingLength.sql | 22 + edexOsgi/build.edex/edex/.gitignore | 1 + .../common_static/base/python/gfe/ParmID.py | 18 - .../gfe/cache/d2dparms/D2DParmIdCache.java | 174 +++-- .../gfe/cache/d2dparms/D2DParmIdFilter.java | 8 +- .../edex/plugin/gfe/db/dao/GFEDao.java | 202 ++--- .../notify/GfeIngestNotificationFilter.java | 73 +- .../GribDecoder.py | 14 +- .../edex/plugin/radar/RadarDecoder.java | 77 +- .../plugin/radar/level3/Level3BaseRadar.java | 37 +- ...tPrivilegedLocalizationRequestHandler.java | 119 +-- .../services/LocalizationStreamHandler.java | 3 +- .../services/PrivilegedUtilityHandler.java | 4 +- .../bandwidth/data/BandwidthGraphData.java | 32 +- .../systemManagement/rules/latencyRules.xml | 8 +- .../systemManagement/rules/priorityRules.xml} | 6 +- .../META-INF/MANIFEST.MF | 3 +- .../META-INF/MANIFEST.MF | 3 +- .../datadelivery/registry/DataLevelType.java | 10 +- .../datadelivery/registry/Ensemble.java | 196 +++-- .../datadelivery/registry/GriddedDataSet.java | 22 + .../registry/GriddedDataSetMetaData.java | 15 - .../GroupDefinitionServiceRequest.java | 85 +++ .../common/datadelivery/registry/Levels.java | 3 +- .../datadelivery/registry/Parameter.java | 13 - .../datadelivery/registry/Provider.java | 57 +- .../datadelivery/registry/Subscription.java | 90 ++- .../META-INF/MANIFEST.MF | 3 +- .../service/BaseDataDeliveryService.java | 69 ++ .../retrieval/util/DataSizeUtils.java | 27 +- .../retrieval/util/LookupManager.java | 46 +- .../retrieval/xml/RetrievalAttribute.java | 13 + .../.classpath | 8 + .../.project | 28 + .../.settings/org.eclipse.jdt.core.prefs | 8 + .../META-INF/MANIFEST.MF | 20 + .../build.properties | 6 + ...aytheon.uf.common.datadelivery.service.ecl | 0 .../res/spring/datadelivery-service.xml | 10 + ...endingSubscriptionNotificationRequest.java | 2 +- ...ndingSubscriptionNotificationResponse.java | 2 +- .../BaseSubscriptionNotificationRequest.java | 2 +- .../BaseSubscriptionNotificationResponse.java | 21 +- ...endingSubscriptionNotificationRequest.java | 2 +- ...ndingSubscriptionNotificationResponse.java | 2 +- .../service/GroupDefinitionService.java | 75 ++ .../service/IGroupDefinitionService.java | 44 +- .../ISubscriptionNotificationService.java | 2 +- ...endingSubscriptionNotificationRequest.java | 2 +- ...ndingSubscriptionNotificationResponse.java | 23 +- ...ServerSubscriptionNotificationService.java | 29 +- .../SubscriptionNotificationRequest.java | 2 +- .../SubscriptionNotificationResponse.java | 21 +- ...f.common.serialization.ISerializableObject | 8 +- .../dataplugin/ffmp/FFMPAggregateRecord.java | 104 +++ .../uf/common/dataplugin/ffmp/FFMPBasin.java | 87 ++- .../common/dataplugin/ffmp/FFMPBasinData.java | 35 +- .../dataplugin/ffmp/FFMPCacheRecord.java | 28 +- .../dataplugin/ffmp/FFMPDataContainer.java | 119 ++- .../uf/common/dataplugin/ffmp/FFMPGap.java | 39 +- .../dataplugin/ffmp/FFMPGuidanceBasin.java | 27 +- .../ffmp/FFMPGuidanceInterpolation.java | 4 +- .../uf/common/dataplugin/ffmp/FFMPRecord.java | 36 + .../dataplugin/ffmp/FFMPVirtualGageBasin.java | 26 +- .../uf/common/dataplugin/ffmp/SourceBin.java | 31 +- .../dataplugin/ffmp/SourceBinEntry.java | 43 +- .../common/dataplugin/ffmp/SourceBinList.java | 29 +- .../dataplugin/gfe/db/objects/DatabaseID.java | 37 +- .../dataplugin/gfe/db/objects/ParmID.java | 43 +- .../warning/gis/GeospatialFactory.java | 42 +- .../gis/PreparedGeometryCollection.java | 246 ++++++ .../dataplugin/warning/util/GeometryUtil.java | 112 ++- .../dataquery/responses/DbQueryResponse.java | 20 +- .../common/localization/LocalizationFile.java | 22 + .../META-INF/MANIFEST.MF | 3 +- .../plugin/nwsauth/xml/NwsRoleData.java | 17 + .../plugin/nwsauth/xml/PermissionXML.java | 12 + .../uf/common/plugin/nwsauth/xml/RoleXML.java | 15 + .../uf/common/plugin/nwsauth/xml/UserXML.java | 51 +- .../xsd/rim/v4/ExtensibleObjectType.java | 7 +- .../regrep/xsd/rim/v4/RegistryObjectType.java | 14 +- .../tc/ebxml/regrep/xsd/rim/v4/SlotType.java | 5 +- .../META-INF/MANIFEST.MF | 4 +- .../uf/common/stats/AggregateRecord.java | 12 +- .../uf/common/stats/GraphDataRequest.java | 5 + .../uf/common/stats/StatsGrouping.java | 101 +++ .../uf/common/stats/StatsGroupingColumn.java | 87 +++ .../uf/common/stats/data/DataPoint.java | 84 +- .../uf/common/stats/data/GraphData.java | 113 ++- .../uf/common/stats/data/StatsBin.java | 30 +- .../uf/common/stats/data/StatsData.java | 52 +- .../uf/common/stats/data/StatsEventData.java | 21 +- .../uf/common/stats/util/DataView.java | 77 ++ .../uf/common/stats/util/UnitUtils.java | 314 ++++---- .../META-INF/MANIFEST.MF | 2 + .../uf/common/time/domain/Duration.java | 165 ++++ .../uf/common/time/domain/Durations.java | 140 ++++ .../time/domain/IDurationTypeAdapter.java | 86 +++ .../time/domain/ITimeIntervalTypeAdapter.java | 93 +++ .../time/domain/ITimePointTypeAdapter.java | 83 ++ .../uf/common/time/domain/TimeInterval.java | 136 ++++ .../time/domain/TimeIntervalJaxbable.java | 91 +++ .../uf/common/time/domain/TimeIntervals.java | 69 ++ .../uf/common/time/domain/TimePoint.java | 148 ++++ .../uf/common/time/domain/TimePoints.java | 75 ++ .../uf/common/time/domain/api/IDuration.java | 138 ++++ .../common/time/domain/api/ITimeInterval.java | 75 ++ .../uf/common/time/domain/api/ITimePoint.java | 98 +++ .../uf/common/time/util/AbstractTimer.java | 44 +- .../raytheon/uf/common/time/util/ITimer.java | 10 + .../uf/common/time/util/TimeUtil.java | 34 +- .../uf/common/time/util/TimerImpl.java | 7 +- .../uf/common/units}/DataSizeUnit.java | 32 +- .../bandwidth/BandwidthGraphDataAdapter.java | 23 +- .../bandwidth/BandwidthManager.java | 213 +++--- .../bandwidth/dao/BandwidthAllocation.java | 12 + .../retrieval/PriorityRetrievalScheduler.java | 7 +- .../bandwidth/util/BandwidthUtil.java | 2 +- .../META-INF/MANIFEST.MF | 4 +- ...ery-request.xml => event-datadelivery.xml} | 8 +- .../SubscriptionNotificationHandler.java | 45 +- .../feature.xml | 7 + .../harvester/crawler/Crawler.java | 8 + .../crawler/MainSequenceCrawler.java | 6 +- .../datadelivery/OPENDAPServiceConfig.xml | 1 + .../harvester/NOMADS-harvester.xml | 8 +- .../lookups/cmcensLevelLookup.xml | 13 - .../datadelivery/lookups/fensLevelLookup.xml | 13 - .../datadelivery/lookups/gensLevelLookup.xml | 29 - .../lookups/gens_bcLevelLookup.xml | 10 - .../datadelivery/lookups/gfsLevelLookup.xml | 29 - .../lookups/gfs_2p5LevelLookup.xml | 29 - .../lookups/gfs_hdLevelLookup.xml | 50 -- .../lookups/hireswLevelLookup.xml | 13 - .../lookups/naefs_bcLevelLookup.xml | 10 - .../datadelivery/lookups/namLevelLookup.xml | 45 -- .../datadelivery/lookups/ofsLevelLookup.xml | 43 -- .../datadelivery/lookups/rapLevelLookup.xml | 40 - .../datadelivery/lookups/rucLevelLookup.xml | 40 - .../datadelivery/lookups/srefLevelLookup.xml | 42 - .../lookups/sref_bcLevelLookup.xml | 8 - .../adapters/GridMetadataAdapter.java | 37 +- .../opendap/OpenDAPMetaDataParser.java | 34 +- .../opendap/OpenDAPParseUtility.java | 69 +- .../opendap/OpenDAPRequestBuilder.java | 19 +- .../opendap/OpenDAPRetrievalGenerator.java | 59 +- .../retrieval/response/OpenDAPTranslator.java | 49 +- .../util/ResponseProcessingUtilities.java | 4 +- .../util/RetrievalGeneratorUtilities.java | 38 +- .../base/stats/retrievalProcessStats.xml | 29 + .../META-INF/MANIFEST.MF | 3 +- ....xml => datadelivery-service-handlers.xml} | 15 +- .../GroupDefinitionServiceHandler.java | 131 ++++ .../raytheon/uf/edex/log/EdexLogHandler.java | 83 +- .../uf/edex/ohd/pproc/ArealQpeGenSrv.java | 4 + .../uf/edex/ohd/pproc/MpeLightningSrv.java | 5 + .../edex/ohd/pproc/MpeRUCFreezingLevel.java | 38 +- .../edex_static/base/distribution/cwa.xml | 2 +- .../res/spring/ffmp-ingest.xml | 4 +- .../uf/edex/plugin/ffmp/FFMPGenerator.java | 294 +++---- .../edex/plugin/ffmp/common/FFMPConfig.java | 6 +- .../common/FFMPInterpolatedGuidanceDelay.java | 12 +- .../uf/edex/plugin/ffmp/common/FFTI.java | 33 +- .../META-INF/MANIFEST.MF | 3 +- .../uf/edex/plugin/nwsauth/FileManager.java | 82 +- .../common_static/base/roles/userRoles.xml | 3 + .../res/scripts/RegistryIndices.sql | 4 + .../uf/edex/registry/ebxml/dao/DbInit.java | 95 +++ .../base/stats/registryProcessStats.xml | 14 + .../uf/edex/stats/AggregateManager.java | 73 +- .../edex/stats/data/StatsDataAccumulator.java | 156 ++-- .../raytheon/uf/edex/stats/util/Archiver.java | 32 +- .../uf/edex/stats/util/ConfigLoader.java | 5 +- .../base/stats/edexProcessStats.xml | 2 + .../i386-pc-linux-gnu.tar.REMOVED.git-id | 2 +- .../awips/hydroapps/whfs/bin/run_alarm_whfs | 16 +- .../dataplugin/gfe/db/objects/ParmID.py | 24 +- tests/.classpath | 4 + .../AbstractBandwidthManagerIntTest.java | 8 + .../bandwidth/BandwidthManagerIntTest.java | 58 +- .../bandwidth/BandwidthServiceIntTest.java | 10 +- ...datadelivery.retrieval.util.LevelXmlWriter | 1 - ...delivery.retrieval.util.ParameterXmlWriter | 1 - .../registry/BaseSubscriptionFixture.java | 3 +- .../OpenDapGriddedDataSetFixture.java | 1 + .../registry/ParameterFixture.java | 1 - .../datadelivery/registry/ProviderTest.java | 38 +- .../registry/SubscriptionBuilder.java | 5 +- .../handlers/GroupDefinitionServiceTest.java | 135 ++++ .../common/localization/TestPathManager.java | 34 +- .../common/registry/RegistryManagerTest.java | 23 +- .../uf/common/stats/data/DataPointTest.java | 12 +- .../uf/common/stats/data/StatsDataTest.java | 10 +- .../uf/common/stats/util/UnitUtilsTest.java | 179 +++++ .../uf/common/time/domain/DurationTest.java | 302 ++++++++ .../uf/common/time/domain/DurationsTest.java | 94 +++ .../common/time/domain/TimeIntervalTest.java | 157 ++++ .../common/time/domain/TimeIntervalsTest.java | 48 ++ .../uf/common/time/domain/TimePointTest.java | 202 +++++ .../uf/common/time/domain/TimePointsTest.java | 70 ++ .../uf/common/time/domain/UsesDuration.java | 75 ++ .../common/time/domain/UsesTimeInterval.java | 75 ++ .../uf/common/time/domain/UsesTimePoint.java | 75 ++ .../datadelivery/harvester/CrawlerTest.java | 7 +- .../edex/plugin/nwsauth/FileManagerTest.java | 156 ++++ .../uf/edex/stats/AggregateManagerTest.java | 116 +++ .../com/raytheon/uf/edex/stats/MockEvent.java | 169 +++++ .../stats/data/StatsDataAccumulatorTest.java | 165 ++-- .../AbstractSubscriptionServiceTest.java | 1 + .../subscription/xml/LatencyRuleXMLTest.java | 86 +++ .../subscription/xml/OperatorAdapterTest.java | 75 ++ .../subscription/xml/RuleXMLTest.java | 25 +- .../utils/DataDeliveryUtilsTest.java | 119 +++ .../datadelivery/utils/DataSizeUtilTest.java | 5 +- .../uf/viz/stats/ui/SelectionEntryTest.java | 54 ++ .../site/OAX/roles/testUserAdminRoles.xml | 14 + .../edex_static/base/stats/mockStats.xml | 12 + 346 files changed, 11816 insertions(+), 6681 deletions(-) create mode 100644 cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedEnsembleSubsetTab.java rename edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/DataViewUtils.java => cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/IRulesUpdateListener.java (66%) create mode 100644 cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/HideDlg.java create mode 100644 cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/SelectionEntry.java create mode 100644 cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/BundleLoader.java create mode 100644 cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/BundleProductLoader.java delete mode 100644 cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/MenuLoader.java create mode 100644 cots/org.junit/hamcrest-all-1.3-sources.jar create mode 100644 cots/org.junit/hamcrest-all-1.3.jar delete mode 100644 cots/org.junit/junit-4.10-src.jar delete mode 100644 cots/org.junit/junit-4.10.jar create mode 100644 cots/org.junit/junit-4.11-src.jar create mode 100644 cots/org.junit/junit-dep-4.11.jar create mode 100644 deltaScripts/13.2.1/aggregateRecordGroupingLength.sh create mode 100644 deltaScripts/13.2.1/convertAggregateRecordGroupToXml.sh create mode 100644 deltaScripts/13.2.1/convertAggregateRecordGroupToXml.sql create mode 100644 deltaScripts/13.2.1/increaseAggregateRecordGroupingLength.sql create mode 100644 edexOsgi/build.edex/edex/.gitignore rename edexOsgi/{com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rtofsLevelLookup.xml => com.raytheon.uf.common.datadelivery.bandwidth/utility/common_static/base/datadelivery/systemManagement/rules/priorityRules.xml} (52%) create mode 100644 edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GroupDefinitionServiceRequest.java create mode 100644 edexOsgi/com.raytheon.uf.common.datadelivery.request/src/com/raytheon/uf/common/datadelivery/service/BaseDataDeliveryService.java create mode 100644 edexOsgi/com.raytheon.uf.common.datadelivery.service/.classpath create mode 100644 edexOsgi/com.raytheon.uf.common.datadelivery.service/.project create mode 100644 edexOsgi/com.raytheon.uf.common.datadelivery.service/.settings/org.eclipse.jdt.core.prefs create mode 100644 edexOsgi/com.raytheon.uf.common.datadelivery.service/META-INF/MANIFEST.MF create mode 100644 edexOsgi/com.raytheon.uf.common.datadelivery.service/build.properties create mode 100644 edexOsgi/com.raytheon.uf.common.datadelivery.service/com.raytheon.uf.common.datadelivery.service.ecl create mode 100644 edexOsgi/com.raytheon.uf.common.datadelivery.service/res/spring/datadelivery-service.xml rename edexOsgi/{com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification => com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/ApprovedPendingSubscriptionNotificationRequest.java (96%) rename edexOsgi/{com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification => com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/ApprovedPendingSubscriptionNotificationResponse.java (95%) rename edexOsgi/{com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification => com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/BaseSubscriptionNotificationRequest.java (97%) rename edexOsgi/{com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification => com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/BaseSubscriptionNotificationResponse.java (82%) rename edexOsgi/{com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification => com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/DeniedPendingSubscriptionNotificationRequest.java (96%) rename edexOsgi/{com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification => com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/DeniedPendingSubscriptionNotificationResponse.java (96%) create mode 100644 edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/GroupDefinitionService.java rename tests/unit/com/raytheon/uf/common/datadelivery/retrieval/util/NullXmlWriter.java => edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/IGroupDefinitionService.java (57%) rename {cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription => edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/ISubscriptionNotificationService.java (98%) rename edexOsgi/{com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification => com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/PendingSubscriptionNotificationRequest.java (96%) rename edexOsgi/{com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification => com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/PendingSubscriptionNotificationResponse.java (71%) rename {cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription => edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/SendToServerSubscriptionNotificationService.java (88%) rename edexOsgi/{com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification => com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/SubscriptionNotificationRequest.java (96%) rename edexOsgi/{com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification => com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service}/SubscriptionNotificationResponse.java (72%) create mode 100644 edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPAggregateRecord.java create mode 100644 edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/PreparedGeometryCollection.java create mode 100644 edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/StatsGrouping.java create mode 100644 edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/StatsGroupingColumn.java create mode 100644 edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/DataView.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/Duration.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/Durations.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/IDurationTypeAdapter.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/ITimeIntervalTypeAdapter.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/ITimePointTypeAdapter.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeInterval.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeIntervalJaxbable.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeIntervals.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimePoint.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimePoints.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/IDuration.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/ITimeInterval.java create mode 100644 edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/ITimePoint.java rename {cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils => edexOsgi/com.raytheon.uf.common.units/src/com/raytheon/uf/common/units}/DataSizeUnit.java (80%) rename edexOsgi/com.raytheon.uf.edex.datadelivery.event/res/spring/{event-datadelivery-request.xml => event-datadelivery.xml} (90%) delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/cmcensLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/fensLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gensLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gens_bcLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfsLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfs_2p5LevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfs_hdLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/hireswLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/naefs_bcLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/namLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/ofsLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rapLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rucLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/srefLevelLookup.xml delete mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/sref_bcLevelLookup.xml create mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/utility/edex_static/base/stats/retrievalProcessStats.xml rename edexOsgi/com.raytheon.uf.edex.datadelivery.service/res/spring/{datadelivery-request.xml => datadelivery-service-handlers.xml} (65%) create mode 100644 edexOsgi/com.raytheon.uf.edex.datadelivery.service/src/com/raytheon/uf/edex/datadelivery/service/services/GroupDefinitionServiceHandler.java create mode 100644 edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/scripts/RegistryIndices.sql create mode 100644 edexOsgi/com.raytheon.uf.edex.registry.ebxml/utility/edex_static/base/stats/registryProcessStats.xml delete mode 100644 tests/resources/META-INF/services/com.raytheon.uf.common.datadelivery.retrieval.util.LevelXmlWriter delete mode 100644 tests/resources/META-INF/services/com.raytheon.uf.common.datadelivery.retrieval.util.ParameterXmlWriter create mode 100644 tests/unit/com/raytheon/uf/common/datadelivery/registry/handlers/GroupDefinitionServiceTest.java create mode 100644 tests/unit/com/raytheon/uf/common/stats/util/UnitUtilsTest.java create mode 100644 tests/unit/com/raytheon/uf/common/time/domain/DurationTest.java create mode 100644 tests/unit/com/raytheon/uf/common/time/domain/DurationsTest.java create mode 100644 tests/unit/com/raytheon/uf/common/time/domain/TimeIntervalTest.java create mode 100644 tests/unit/com/raytheon/uf/common/time/domain/TimeIntervalsTest.java create mode 100644 tests/unit/com/raytheon/uf/common/time/domain/TimePointTest.java create mode 100644 tests/unit/com/raytheon/uf/common/time/domain/TimePointsTest.java create mode 100644 tests/unit/com/raytheon/uf/common/time/domain/UsesDuration.java create mode 100644 tests/unit/com/raytheon/uf/common/time/domain/UsesTimeInterval.java create mode 100644 tests/unit/com/raytheon/uf/common/time/domain/UsesTimePoint.java create mode 100644 tests/unit/com/raytheon/uf/edex/plugin/nwsauth/FileManagerTest.java create mode 100644 tests/unit/com/raytheon/uf/edex/stats/AggregateManagerTest.java create mode 100644 tests/unit/com/raytheon/uf/edex/stats/MockEvent.java create mode 100644 tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/LatencyRuleXMLTest.java create mode 100644 tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/OperatorAdapterTest.java create mode 100644 tests/unit/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryUtilsTest.java create mode 100644 tests/unit/com/raytheon/uf/viz/stats/ui/SelectionEntryTest.java create mode 100644 tests/utility/common_static/site/OAX/roles/testUserAdminRoles.xml create mode 100644 tests/utility/edex_static/base/stats/mockStats.xml diff --git a/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolBaseData.xml b/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolBaseData.xml index 411e9a2128..2d5266b6f2 100644 --- a/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolBaseData.xml +++ b/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolBaseData.xml @@ -60,9 +60,9 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -230,9 +94,9 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -352,9 +148,9 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -454,9 +182,9 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -639,8 +231,7 @@ - - + @@ -655,58 +246,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -718,8 +257,7 @@ - - + @@ -734,58 +272,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -812,8 +298,7 @@ - - + @@ -828,58 +313,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -891,8 +324,7 @@ - - + @@ -907,110 +339,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolFourPanelZHCML.xml b/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolFourPanelZHCML.xml index 9183ec178d..6250e381c8 100644 --- a/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolFourPanelZHCML.xml +++ b/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolFourPanelZHCML.xml @@ -6,10 +6,17 @@ Contractor_Address:_____6825_Pine_Street,_Suite_340 ________________________Mail_Stop_B8 ________________________Omaha,_NE_68106 ________________________402.291.0100 See_the_AWIPS_II_Master_Rights_File_("Master_Rights_File.pdf")_for further_licensing_information. --> - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -362,8 +165,7 @@ - - + @@ -378,116 +180,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -502,58 +199,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -605,8 +250,7 @@ - - + @@ -621,116 +265,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + > @@ -745,58 +284,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -848,8 +335,7 @@ - - + @@ -864,116 +350,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -988,58 +369,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolHCA.xml b/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolHCA.xml index 4f30e8980a..8f78c5c530 100644 --- a/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolHCA.xml +++ b/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolHCA.xml @@ -48,9 +48,8 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -214,9 +85,8 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -321,8 +127,7 @@ - - + @@ -337,58 +142,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -400,8 +153,7 @@ - - + @@ -416,58 +168,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -512,9 +212,8 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolPrecipAnalysis.xml b/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolPrecipAnalysis.xml index 615d7c65cc..0bc4f6d2b0 100644 --- a/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolPrecipAnalysis.xml +++ b/cave/build/static/common/cave/etc/bundles/DefaultRadarDualPolPrecipAnalysis.xml @@ -191,9 +191,9 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/RecordFactory.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/RecordFactory.java index 530ccb3231..1f1bf5ad41 100644 --- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/RecordFactory.java +++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/RecordFactory.java @@ -19,8 +19,10 @@ **/ package com.raytheon.uf.viz.core; +import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.TreeSet; import org.apache.commons.beanutils.ConstructorUtils; @@ -56,7 +58,7 @@ public class RecordFactory { private static RecordFactory instance = new RecordFactory(); /** Map containing the pluginName/Record class pairs */ - private Map> defMap; + private Map> defMap = new HashMap>(); public static final String WILDCARD = "%"; @@ -82,36 +84,39 @@ public class RecordFactory { } @SuppressWarnings("unchecked") - private synchronized void loadDefMap() throws VizException { - if (defMap == null) { - GetPluginRecordMapRequest req = new GetPluginRecordMapRequest(); - Map pluginRecordMap = (Map) ThriftClient - .sendRequest(req); - Map> newDefMap = new HashMap>( - pluginRecordMap.size()); - for (Map.Entry entry : pluginRecordMap.entrySet()) { - String pluginName = entry.getKey(); - String record = entry.getValue(); - if (record != null) { - try { - Class clazz = (Class) Class - .forName(record); - newDefMap.put(pluginName, clazz); - } catch (Exception e) { - statusHandler.handle(Priority.DEBUG, - "Can't find record class for " + pluginName - + " plugin", e); - System.out - .println("DEBUG: Can't find record class for " - + pluginName + " plugin - alerts on " - + pluginName + " data will be ignored"); - } + private void loadDefMap() throws VizException { + GetPluginRecordMapRequest req = new GetPluginRecordMapRequest(); + Map pluginRecordMap = (Map) ThriftClient + .sendRequest(req); + for (Map.Entry entry : pluginRecordMap.entrySet()) { + String pluginName = entry.getKey(); + String record = entry.getValue(); + if (record != null) { + try { + Class clazz = (Class) Class + .forName(record); + defMap.put(pluginName, clazz); + } catch (Exception e) { + statusHandler.handle(Priority.DEBUG, + "Can't find record class for " + pluginName + + " plugin", e); + System.out.println("DEBUG: Can't find record class for " + + pluginName + " plugin - alerts on " + pluginName + + " data will be ignored"); } } - defMap = newDefMap; } } + /** + * Returns a collection of all supported plugins + * + * @return + */ + public Collection getSupportedPlugins() { + return new TreeSet(defMap.keySet()); + } + /** * Creates a map of the fields and values that compose a given dataURI * @@ -123,7 +128,6 @@ public class RecordFactory { */ public Map loadMapFromUri(String dataURI) throws VizException { - // If no dataURI return if (dataURI == null) { return null; @@ -181,10 +185,10 @@ public class RecordFactory { */ public Class getPluginClass(String pluginName) throws VizException { - if (defMap == null) { - loadDefMap(); + Class retVal = null; + if (defMap != null) { + retVal = defMap.get(pluginName); } - Class retVal = defMap.get(pluginName); if (retVal == null) { throw new NoPluginException("Can't find record class for " + pluginName + " plugin"); diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/AbstractDescriptor.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/AbstractDescriptor.java index ab75b65d5f..307534ba69 100644 --- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/AbstractDescriptor.java +++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/drawables/AbstractDescriptor.java @@ -578,6 +578,8 @@ public abstract class AbstractDescriptor extends ResourceGroup implements } } synchronized (timeManager) { + DataTime[] oldTimes = timeManager.frames; + int oldIdx = this.frameIndex; if (info.setFrames) { if (info.frameTimes != null) { DataTime[] newTimes = Arrays.copyOf(info.frameTimes, @@ -594,6 +596,14 @@ public abstract class AbstractDescriptor extends ResourceGroup implements timeMatchingMap = new ConcurrentHashMap, DataTime[]>( info.timeMap); } + FramesInfo currInfo = getFramesInfo(); + FramesInfo oldInfo = new FramesInfo(oldTimes, oldIdx); + DataTime oldTime = oldInfo.getCurrentFrame(); + DataTime currTime = currInfo.getCurrentFrame(); + if ((oldTime != null && oldTime.equals(currTime) == false) + || (currTime != null && currTime.equals(oldTime) == false)) { + notifyFrameChanged(oldTime, currTime); + } } } @@ -624,20 +634,8 @@ public abstract class AbstractDescriptor extends ResourceGroup implements * @param frame */ private void setFrameInternal(int frame) { - FramesInfo currInfo = getFramesInfo(); - int frameIndex = currInfo.frameIndex; if (frame != frameIndex) { - DataTime[] times = currInfo.frameTimes; - DataTime oldTime = null, newTime = null; - // Get the old and new time - if (times != null && frameIndex >= 0 && frameIndex < times.length) { - oldTime = times[frameIndex]; - } - if (times != null && frame >= 0 && frame < times.length) { - newTime = times[frame]; - } this.frameIndex = frame; - notifyFrameChanged(oldTime, newTime); } } diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/localization/CAVELocalizationAdapter.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/localization/CAVELocalizationAdapter.java index d4962390be..cb22cd4fc8 100644 --- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/localization/CAVELocalizationAdapter.java +++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/localization/CAVELocalizationAdapter.java @@ -250,7 +250,7 @@ public class CAVELocalizationAdapter implements ILocalizationAdapter { return true; } catch (FileNotFoundException e) { throw new LocalizationOpFailedException( - "Error saving file, does not exist"); + "Error saving, file does not exist"); } finally { // Make sure to close input stream if (in != null) { diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/localization/LocalizationManager.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/localization/LocalizationManager.java index 43ca8f3a26..ba76881380 100644 --- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/localization/LocalizationManager.java +++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/localization/LocalizationManager.java @@ -777,7 +777,7 @@ public class LocalizationManager implements IPropertyChangeListener { } } catch (VizException e) { throw new LocalizationOpFailedException( - "Error storing file contents to server: " + "Error uploading file contents to localization server: " + e.getLocalizedMessage(), e); } diff --git a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/rsc/AbstractRequestableResourceData.java b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/rsc/AbstractRequestableResourceData.java index 7baa0495bd..e3090c49b3 100644 --- a/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/rsc/AbstractRequestableResourceData.java +++ b/cave/com.raytheon.uf.viz.core/src/com/raytheon/uf/viz/core/rsc/AbstractRequestableResourceData.java @@ -275,6 +275,20 @@ public abstract class AbstractRequestableResourceData extends Validate.isTrue(updateData instanceof Object[], "Update expected Object[]"); + if (updateData instanceof PluginDataObject[]) { + for (PluginDataObject pdo : (PluginDataObject[]) updateData) { + DataTime time = pdo.getDataTime(); + if (binOffset != null) { + time = binOffset.getNormalizedTime(time); + } + synchronized (cachedAvailableTimes) { + if (!cachedAvailableTimes.contains(time)) { + cachedAvailableTimes.add(time); + } + } + } + } + this.fireChangeListeners(ChangeType.DATA_UPDATE, updateData); } @@ -669,7 +683,6 @@ public abstract class AbstractRequestableResourceData extends int result = 1; result = prime * result + ((binOffset == null) ? 0 : binOffset.hashCode()); - result = prime * result + (isUpdatingOnMetadataOnly ? 1231 : 1237); result = prime * result + ((metadataMap == null) ? 0 : metadataMap.hashCode()); result = prime * result @@ -710,10 +723,6 @@ public abstract class AbstractRequestableResourceData extends return false; } - if (isUpdatingOnMetadataOnly != other.isUpdatingOnMetadataOnly) { - return false; - } - if (!isObjectsEqual(metadataMap, other.metadataMap)) { return false; } diff --git a/cave/com.raytheon.uf.viz.d2d.core/src/com/raytheon/uf/viz/d2d/core/time/D2DTimeMatcher.java b/cave/com.raytheon.uf.viz.d2d.core/src/com/raytheon/uf/viz/d2d/core/time/D2DTimeMatcher.java index b834e1d02b..b92da6d491 100644 --- a/cave/com.raytheon.uf.viz.d2d.core/src/com/raytheon/uf/viz/d2d/core/time/D2DTimeMatcher.java +++ b/cave/com.raytheon.uf.viz.d2d.core/src/com/raytheon/uf/viz/d2d/core/time/D2DTimeMatcher.java @@ -828,19 +828,23 @@ public class D2DTimeMatcher extends AbstractTimeMatcher { */ public void changeTimeMatchBasis(AbstractVizResource resource) { if (timeMatchBasis != resource) { - TimeMatchingConfiguration config = getConfiguration(resource - .getLoadProperties()); - TimeCache timeCache = getTimeCache(resource); if (timeMatchBasis != null) { + TimeMatchingConfiguration config = getConfiguration(timeMatchBasis + .getLoadProperties()); config.setTimeMatchBasis(false); + TimeCache timeCache = getTimeCache(timeMatchBasis); timeCache.setTimes(null, null); timeMatchBasis .unregisterListener(timeMatchBasisDisposeListener); } timeMatchBasis = resource; + if (timeMatchBasis != null) { + TimeMatchingConfiguration config = getConfiguration(timeMatchBasis + .getLoadProperties()); config.setTimeMatchBasis(true); + TimeCache timeCache = getTimeCache(timeMatchBasis); timeCache.setTimes(null, null); timeMatchBasis.registerListener(timeMatchBasisDisposeListener); } diff --git a/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/dialogs/procedures/HistoryListDlg.java b/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/dialogs/procedures/HistoryListDlg.java index eb1edf11b5..50cdc4fbc8 100644 --- a/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/dialogs/procedures/HistoryListDlg.java +++ b/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/dialogs/procedures/HistoryListDlg.java @@ -47,8 +47,6 @@ import com.raytheon.viz.ui.HistoryList; import com.raytheon.viz.ui.HistoryList.IHistoryListener; import com.raytheon.viz.ui.UiPlugin; import com.raytheon.viz.ui.UiUtil; -import com.raytheon.viz.ui.actions.LoadSerializedXml; -import com.raytheon.viz.ui.actions.SaveBundle; import com.raytheon.viz.ui.dialogs.CaveSWTDialog; import com.raytheon.viz.ui.dialogs.ICloseCallback; import com.raytheon.viz.ui.editor.AbstractEditor; @@ -331,28 +329,22 @@ public class HistoryListDlg extends CaveSWTDialog { } private void loadAlterBundle(Bundle b) { - try { - String editorName = null; + String editorName = null; - if (b.getDisplays().length > 0) { - editorName = DescriptorMap.getEditorId(b.getDisplays()[0] - .getDescriptor().getClass().getName()); - } - - AbstractEditor editor = UiUtil.createOrOpenEditor(editorName, - b.getDisplays()); - - for (IDisplayPane pane : editor.getDisplayPanes()) { - pane.getRenderableDisplay().getDescriptor().getResourceList() - .clear(); - } - - LoadSerializedXml.loadTo(editor, b); - HistoryList.getInstance().addBundle(b); - } catch (VizException e) { - final String err = "Error loading bundle"; - statusHandler.handle(Priority.PROBLEM, err, e); + if (b.getDisplays().length > 0) { + editorName = DescriptorMap.getEditorId(b.getDisplays()[0] + .getDescriptor().getClass().getName()); } + + AbstractEditor editor = UiUtil.createOrOpenEditor(editorName, + b.getDisplays()); + + for (IDisplayPane pane : editor.getDisplayPanes()) { + pane.getRenderableDisplay().getDescriptor().getResourceList() + .clear(); + } + + ProcedureLoadJob.getInstance().enqueue(b, editor); } /** @@ -378,10 +370,7 @@ public class HistoryListDlg extends CaveSWTDialog { return; } - LoadSerializedXml.loadTo(editor, b); - Bundle currBundle = SaveBundle.extractCurrentBundle(); - - HistoryList.getInstance().refreshLatestBundle(currBundle); + ProcedureLoadJob.getInstance().enqueue(b, editor); } catch (VizException e) { statusHandler.handle(Priority.SIGNIFICANT, "Error loading bundle", e); diff --git a/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/dialogs/procedures/ProcedureLoadJob.java b/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/dialogs/procedures/ProcedureLoadJob.java index 293636dae4..f4e9e2af89 100644 --- a/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/dialogs/procedures/ProcedureLoadJob.java +++ b/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/dialogs/procedures/ProcedureLoadJob.java @@ -28,12 +28,8 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; -import com.raytheon.uf.common.status.IUFStatusHandler; -import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.common.status.UFStatus.Priority; -import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.procedures.Bundle; -import com.raytheon.viz.ui.actions.LoadSerializedXml; +import com.raytheon.viz.ui.BundleLoader; import com.raytheon.viz.ui.editor.AbstractEditor; /** @@ -54,8 +50,6 @@ import com.raytheon.viz.ui.editor.AbstractEditor; */ public class ProcedureLoadJob { - private static final transient IUFStatusHandler statusHandler = UFStatus - .getHandler(ProcedureLoadJob.class); private static final ProcedureLoadJob instance = new ProcedureLoadJob(); @@ -79,12 +73,7 @@ public class ProcedureLoadJob { AbstractEditor editor = entry.getKey(); Bundle b = entry.getValue(); - try { - LoadSerializedXml.loadTo(editor, b); - } catch (VizException e) { - statusHandler.handle(Priority.PROBLEM, - "Error loading bundle", e); - } + new BundleLoader(editor, b).run(); } } diff --git a/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/map/SideView.java b/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/map/SideView.java index 8326b0ff29..de0c3c2f85 100644 --- a/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/map/SideView.java +++ b/cave/com.raytheon.uf.viz.d2d.ui/src/com/raytheon/uf/viz/d2d/ui/map/SideView.java @@ -63,10 +63,10 @@ import com.raytheon.uf.viz.d2d.core.legend.D2DLegendResource.LegendMode; import com.raytheon.uf.viz.d2d.core.map.MapScales; import com.raytheon.uf.viz.d2d.core.map.MapScales.MapScale; import com.raytheon.uf.viz.d2d.core.map.MapScales.PartId; +import com.raytheon.viz.ui.BundleLoader; import com.raytheon.viz.ui.EditorUtil; import com.raytheon.viz.ui.HistoryList; import com.raytheon.viz.ui.UiUtil; -import com.raytheon.viz.ui.actions.LoadSerializedXml; import com.raytheon.viz.ui.color.BackgroundColor; import com.raytheon.viz.ui.color.IBackgroundColorChangedListener; import com.raytheon.viz.ui.editor.AbstractEditor; @@ -207,12 +207,7 @@ public class SideView extends ViewPart implements IMultiPaneEditor, } if (bundleToLoad != null) { - try { - LoadSerializedXml.loadTo(this, bundleToLoad); - } catch (VizException e) { - statusHandler.handle(Priority.PROBLEM, - "Error loading bundle view", e); - } + new BundleLoader(this, bundleToLoad).run(); } } @@ -604,12 +599,12 @@ public class SideView extends ViewPart implements IMultiPaneEditor, if (editableResource != null) { EditableManager.makeEditable(editableResource, false); } - - this.editableResource = editableResource; + + this.editableResource = editableResource; if (this.editableResource != null) { EditableManager.makeEditable(this.editableResource, true); } - + theEditor.getBackgroundColor().setColor(BGColorMode.EDITOR, myRenderables[0].getBackgroundColor()); diff --git a/cave/com.raytheon.uf.viz.datadelivery.feature/feature.xml b/cave/com.raytheon.uf.viz.datadelivery.feature/feature.xml index d98a45b0ea..0cbd7f3762 100644 --- a/cave/com.raytheon.uf.viz.datadelivery.feature/feature.xml +++ b/cave/com.raytheon.uf.viz.datadelivery.feature/feature.xml @@ -99,6 +99,13 @@ version="0.0.0" unpack="false"/> + + + class="com.raytheon.uf.common.datadelivery.service.SendToServerSubscriptionNotificationService" /> + + @@ -28,6 +31,7 @@ + * @@ -886,6 +887,7 @@ public class BandwidthCanvasComp extends Composite implements IDialogClosed, MenuItem viewSubs = new MenuItem(m, SWT.NONE); viewSubs.setText("View Selected Subscriptions..."); + viewSubs.setEnabled(imageMgr.hasSubscriptionNameChecked()); viewSubs.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/BandwidthImageMgr.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/BandwidthImageMgr.java index dd24fb4e81..70a2b068ea 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/BandwidthImageMgr.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/BandwidthImageMgr.java @@ -20,6 +20,7 @@ package com.raytheon.uf.viz.datadelivery.bandwidth.ui; import java.util.Collection; +import java.util.EnumMap; import java.util.HashMap; import java.util.Map; @@ -30,7 +31,7 @@ import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import com.raytheon.uf.common.datadelivery.bandwidth.data.BandwidthGraphData; -import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils.SubscriptionPriority; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; /** * Bandwidth utilization graph image manager. @@ -42,7 +43,9 @@ import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils.SubscriptionP * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Nov 28, 2012 1269 lvenable Initial creation - * Dec 13, 2012 1269 lvenable Fixes and updates. + * Dec 13, 2012 1269 lvenable Fixes and updates. + * Jan 25, 2013 1528 djohnson Subscription priority is now an enum on subscriptions. + * Jan 28, 2013 1529 djohnson Add hasSubscriptionNameChecked(). * * * @@ -137,10 +140,11 @@ public class BandwidthImageMgr implements IGraphOptions { private void init(Composite parentComp, BandwidthGraphData graphData, Map canvasSettingsMap) { - priorityColorMap = new HashMap(); - for (SubscriptionPriority priority : SubscriptionPriority.values()) { - priorityColorMap.put(priority, priority.getColor()); - } + priorityColorMap = new EnumMap( + SubscriptionPriority.class); + priorityColorMap.put(SubscriptionPriority.LOW, new RGB(6, 122, 255)); + priorityColorMap.put(SubscriptionPriority.NORMAL, new RGB(0, 255, 0)); + priorityColorMap.put(SubscriptionPriority.HIGH, new RGB(255, 0, 0)); canvasImgMap = new HashMap(); populateCanvasMap(parentComp, graphData, canvasSettingsMap); @@ -488,4 +492,13 @@ public class BandwidthImageMgr implements IGraphOptions { regenerateImage(CanvasImages.X_HEADER); } -} \ No newline at end of file + + /** + * Check whether there is a checked subscription name. + * + * @return true if at least one subscription name is checked + */ + public boolean hasSubscriptionNameChecked() { + return checkMap.containsValue(Boolean.TRUE); + } +} diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/GraphImage.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/GraphImage.java index 463b077dcb..7b7e44fa96 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/GraphImage.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/GraphImage.java @@ -34,9 +34,9 @@ import org.eclipse.swt.widgets.Composite; import com.raytheon.uf.common.datadelivery.bandwidth.data.BandwidthGraphData; import com.raytheon.uf.common.datadelivery.bandwidth.data.TimeWindowData; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.viz.datadelivery.bandwidth.ui.BandwidthImageMgr.SortBy; -import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils.SubscriptionPriority; /** * The graph image class. @@ -51,6 +51,7 @@ import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils.SubscriptionP * Dec 13, 2012 1269 lvenable Fixes and updates. * Jan 07, 2013 1451 djohnson Use TimeUtil.newGmtCalendar(). * Jan 04, 2013 1420 mpduff Change default priority to normal priority. + * Jan 25, 2013 1528 djohnson Subscription priority is now an enum, remove incorrect use of ordinal values. * * * @@ -171,20 +172,17 @@ public class GraphImage extends AbstractCanvasImage { for (String subName : subscriptionList) { if (imageMgr.isColorByPriority()) { - if (graphData.getPriority(subName) == SubscriptionPriority.NORMAL - .ordinal()) { + if (graphData.getPriority(subName) == SubscriptionPriority.NORMAL) { c = new Color( display, imageMgr.getPriorityColor(SubscriptionPriority.NORMAL)); gc.setBackground(c); - } else if (graphData.getPriority(subName) == SubscriptionPriority.HIGH - .ordinal()) { + } else if (graphData.getPriority(subName) == SubscriptionPriority.HIGH) { c = new Color( display, imageMgr.getPriorityColor(SubscriptionPriority.HIGH)); gc.setBackground(c); - } else if (graphData.getPriority(subName) == SubscriptionPriority.LOW - .ordinal()) { + } else if (graphData.getPriority(subName) == SubscriptionPriority.LOW) { c = new Color(display, imageMgr.getPriorityColor(SubscriptionPriority.LOW)); gc.setBackground(c); diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/IGraphOptions.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/IGraphOptions.java index d5d16946a2..aaf84b96d3 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/IGraphOptions.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/IGraphOptions.java @@ -21,7 +21,7 @@ package com.raytheon.uf.viz.datadelivery.bandwidth.ui; import org.eclipse.swt.graphics.RGB; -import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils.SubscriptionPriority; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; /** * TODO Add Description diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/XHeaderImage.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/XHeaderImage.java index 912b8c2c5c..6e2b3d7156 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/XHeaderImage.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/bandwidth/ui/XHeaderImage.java @@ -32,7 +32,7 @@ import org.eclipse.swt.widgets.ColorDialog; import org.eclipse.swt.widgets.Composite; import com.raytheon.uf.common.datadelivery.bandwidth.data.BandwidthGraphData; -import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils.SubscriptionPriority; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; /** * Header image for X axis. @@ -45,6 +45,7 @@ import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils.SubscriptionP * ------------ ---------- ----------- -------------------------- * Nov 28, 2012 1269 lvenable Initial creation. * Dec 13, 2012 1269 lvenable Fixes and updates. + * Jan 25, 2013 1528 djohnson Subscription priority is now an enum. * * * @@ -75,7 +76,7 @@ public class XHeaderImage extends AbstractCanvasImage { private final String sortBy = "Sort by: "; /** Map of rectangles and subscription priorities. */ - private Map rectPriMap; + private final Map rectPriMap; /** * Constructor. diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/browser/DataBrowserDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/browser/DataBrowserDlg.java index d6c0ebe66e..69355e61c1 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/browser/DataBrowserDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/browser/DataBrowserDlg.java @@ -113,6 +113,7 @@ import com.vividsolutions.jts.geom.Coordinate; * Dec 10, 2012 1259 bsteffen Switch Data Delivery from LatLon to referenced envelopes. * Dec 12, 2012 1391 bgonzale Added job for dataset retrieval. * Jan 08, 2012 1436 bgonzale Fixed area text box display update check. + * Jan 14, 2012 1437 bgonzale Clear filters when creating a new configuration. * * * @@ -860,6 +861,7 @@ public class DataBrowserDlg extends CaveSWTDialog implements IDataTableUpdate, return; } + xml = new FilterSettingsXML(); setText(WINDOW_TITLE); // Clear the area. @@ -871,6 +873,8 @@ public class DataBrowserDlg extends CaveSWTDialog implements IDataTableUpdate, dataTypesDualList.clearSelection(); // Clear the filters. + updateFilters(); + filterExpandBar.updateFilters(dataTypesDualList.getSelectedListItems(), envelope); diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/common/ui/PriorityComp.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/common/ui/PriorityComp.java index dfeae92a25..180afac3f5 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/common/ui/PriorityComp.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/common/ui/PriorityComp.java @@ -20,6 +20,8 @@ package com.raytheon.uf.viz.datadelivery.common.ui; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Combo; @@ -28,7 +30,7 @@ import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; -import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils.SubscriptionPriority; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; /** * This is the priority group information composite. This class is intended to @@ -43,6 +45,7 @@ import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils.SubscriptionP * Jun 27, 2012 702 jpiatt Initial creation. * Aug 21, 2012 712 mpduff Default to Default, and allow for setting the combo box. * Jan 04, 2013 1420 mpduff Add latency. + * Jan 25, 2013 1528 djohnson Use priority enum instead of raw integers. * * * @@ -60,7 +63,7 @@ public class PriorityComp extends Composite { private final int latency; /** The priority value */ - private final int priority; + private SubscriptionPriority priority; /** * Constructor. @@ -70,10 +73,11 @@ public class PriorityComp extends Composite { * @param latency * @param priority */ - public PriorityComp(Composite parent, int latency, int priority) { + public PriorityComp(Composite parent, int latency, + SubscriptionPriority priority) { super(parent, SWT.NONE); this.latency = latency; - this.priority = priority - 1; + this.priority = priority; init(); } @@ -127,9 +131,16 @@ public class PriorityComp extends Composite { gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false); priorityCombo = new Combo(priorityComp, SWT.READ_ONLY); priorityCombo.setItems(priorities); - priorityCombo.select(this.priority); priorityCombo.setLayoutData(gd); priorityCombo.setToolTipText("Select a priority"); + priorityCombo.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + priority = SubscriptionPriority.fromPriorityName(priorityCombo + .getItem(priorityCombo.getSelectionIndex())); + } + }); + setPriority(priority); Composite latencyComp = new Composite(subPriorityGroup, SWT.NONE); gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false); @@ -153,8 +164,8 @@ public class PriorityComp extends Composite { * * @return priority */ - public int getPriorityIndex() { - return priorityCombo.getSelectionIndex(); + public SubscriptionPriority getPriority() { + return priority; } /** @@ -162,10 +173,9 @@ public class PriorityComp extends Composite { * * @param index */ - public void setPriorityIndex(int index) { - if (index <= priorityCombo.getItemCount()) { - priorityCombo.select(index); - } + public void setPriority(SubscriptionPriority priority) { + priorityCombo.select(priorityCombo.indexOf(priority.getPriorityName())); + this.priority = priority; } /** diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/common/ui/UserSelectComp.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/common/ui/UserSelectComp.java index a05d1b40f0..4c3f0b995c 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/common/ui/UserSelectComp.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/common/ui/UserSelectComp.java @@ -413,6 +413,7 @@ public class UserSelectComp extends Composite implements IUpdate, IDisplay, u.setEnvelope(groupDefinition.getEnvelope()); u.setNumFcstHours(subscription.getTime() .getSelectedTimeIndices().size()); + u.setNumEnsembleMembers(subscription.getEnsemble()); u.determineNumberRequestedGrids(subscription.getParameter()); Coverage cov = new GriddedCoverage(); diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/notification/NotificationDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/notification/NotificationDlg.java index 2342df35d2..602302293e 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/notification/NotificationDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/notification/NotificationDlg.java @@ -95,6 +95,7 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog; * Oct 22, 2012 1284 mpduff Code Cleanup. * Dec 03, 2012 1285 bgonzale Added implementation of the tableLock method. * Update title bar text when paused. + * Jan 22, 2013 1520 mpduff Change delete menus to hide. * * * @@ -272,7 +273,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, MenuItem setDefaultMI = new MenuItem(fileMenu, SWT.NONE); lockableMenuItems.add(setDefaultMI); - setDefaultMI.setText("&Set as Default"); + setDefaultMI.setText("Set as Default"); setDefaultMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -282,7 +283,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, MenuItem loadConfigMI = new MenuItem(fileMenu, SWT.NONE); lockableMenuItems.add(loadConfigMI); - loadConfigMI.setText("&Load Configuration..."); + loadConfigMI.setText("Load Configuration..."); loadConfigMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -298,7 +299,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, MenuItem saveConfigMI = new MenuItem(fileMenu, SWT.NONE); lockableMenuItems.add(saveConfigMI); - saveConfigMI.setText("&Save Configuration"); + saveConfigMI.setText("Save Configuration"); saveConfigMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -308,7 +309,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, MenuItem saveConfigAsMI = new MenuItem(fileMenu, SWT.NONE); lockableMenuItems.add(saveConfigAsMI); - saveConfigAsMI.setText("&Save Configuration As..."); + saveConfigAsMI.setText("Save Configuration As..."); saveConfigAsMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -318,7 +319,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, MenuItem deleteConfigMI = new MenuItem(fileMenu, SWT.NONE); lockableMenuItems.add(deleteConfigMI); - deleteConfigMI.setText("&Delete Configuration..."); + deleteConfigMI.setText("Delete Configuration..."); deleteConfigMI.addSelectionListener(new SelectionAdapter() { @Override @@ -330,7 +331,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, new MenuItem(fileMenu, SWT.SEPARATOR); MenuItem exitMI = new MenuItem(fileMenu, SWT.NONE); - exitMI.setText("&Exit"); + exitMI.setText("Exit"); exitMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -348,7 +349,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, // Find Menu MenuItem findMI = new MenuItem(editMenu, SWT.CASCADE); lockableMenuItems.add(findMI); - findMI.setText("&Find..."); + findMI.setText("Find..."); findMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -356,10 +357,10 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, } }); - MenuItem delPriorityMI = new MenuItem(editMenu, SWT.CASCADE); - lockableMenuItems.add(delPriorityMI); - delPriorityMI.setText("&Delete by Priority"); - delPriorityMI.addSelectionListener(new SelectionAdapter() { + MenuItem hidePriorityMI = new MenuItem(editMenu, SWT.CASCADE); + lockableMenuItems.add(hidePriorityMI); + hidePriorityMI.setText("Hide by Priority"); + hidePriorityMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -367,14 +368,14 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, }); Menu subMenu = new Menu(menuBar); - delPriorityMI.setMenu(subMenu); + hidePriorityMI.setMenu(subMenu); createPriorityMenus(subMenu); - MenuItem deleteOlderMI = new MenuItem(editMenu, SWT.NONE); - lockableMenuItems.add(deleteOlderMI); - deleteOlderMI.setText("&Delete Older Than Selected"); - deleteOlderMI.addSelectionListener(new SelectionAdapter() { + MenuItem hideOlderMI = new MenuItem(editMenu, SWT.NONE); + lockableMenuItems.add(hideOlderMI); + hideOlderMI.setText("Hide Older Than Selected"); + hideOlderMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { tableComp.handleDeleteOlderThan(); @@ -382,10 +383,10 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, }); - MenuItem deleteMI = new MenuItem(editMenu, SWT.NONE); - lockableMenuItems.add(deleteMI); - deleteMI.setText("&Delete Notification(s)"); - deleteMI.addSelectionListener(new SelectionAdapter() { + MenuItem hideMI = new MenuItem(editMenu, SWT.NONE); + lockableMenuItems.add(hideMI); + hideMI.setText("Hide Notification(s)"); + hideMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { tableComp.handleDeleteNotification(); @@ -401,7 +402,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, MenuItem configureMI = new MenuItem(settingsMenu, SWT.NONE); lockableMenuItems.add(configureMI); - configureMI.setText("&Configure Table..."); + configureMI.setText("Configure Table..."); configureMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -411,7 +412,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, MenuItem filterMI = new MenuItem(settingsMenu, SWT.NONE); lockableMenuItems.add(filterMI); - filterMI.setText("&Filter Table..."); + filterMI.setText("Filter Table..."); filterMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -420,7 +421,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, }); tooltipMI = new MenuItem(settingsMenu, SWT.CHECK); - tooltipMI.setText("&Tooltips"); + tooltipMI.setText("Tooltips"); tooltipMI.setSelection(false); tooltipMI.addSelectionListener(new SelectionAdapter() { @Override @@ -438,7 +439,7 @@ public class NotificationDlg extends CaveSWTDialog implements ITableChange, helpMenuItem.setMenu(helpMenu); MenuItem helpNotTableMI = new MenuItem(helpMenu, SWT.NONE); - helpNotTableMI.setText("&About Notification Center..."); + helpNotTableMI.setText("About Notification Center..."); helpNotTableMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/notification/NotificationTableComp.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/notification/NotificationTableComp.java index 20373b8bdc..2be48e7781 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/notification/NotificationTableComp.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/notification/NotificationTableComp.java @@ -75,7 +75,7 @@ import com.raytheon.uf.viz.datadelivery.utils.NotificationHandler; * Sep 06, 2012 687 mpduff Call the table selection method of the ITableChanged interface. * Oct 22, 2012 1284 mpduff Fix the start/end index for pagination of new records, code cleanup. * Nov 29, 2012 1285 bgonzale Added a refresh pause button to the Notification Center Dialog. - * + * Jan 22, 2013 1520 mpduff Update javadoc. * * * @author lvenable @@ -197,12 +197,12 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Constructor. - * + * * Note: For the super class we are passing in a false for the notification * flag. This is turned off because the notification dialog is using the * NotificationHandler and it contains the necessary code that needs to be * executed. - * + * * @param parent * @param tableConfig * @param callback @@ -287,6 +287,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { + " not refresh, re-sort, or allow user modification" + " until unchecked."); pauseButton.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { boolean isLocked = pauseButton.getSelection(); @@ -320,7 +321,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Get the entire table list. - * + * * @return TableDataManager obj */ public TableDataManager getMasterTableList() { @@ -329,7 +330,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Get the table list with filters applied. - * + * * @return TableDataManager obj */ public TableDataManager getFilteredTableList() { @@ -338,7 +339,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Get the table list for display. - * + * * @return TableDataManager obj */ public ArrayList getVisibleTableList() { @@ -347,7 +348,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Get the rows of data to display. - * + * * @return list of Notification Row Data objects */ private ArrayList getTableRows() { @@ -359,7 +360,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { // Recalculate start/end indices for visible page if (numRows > endIndex && endIndex - startIndex < pageConfig) { - endIndex = startIndex + pageConfig - 1;//numRows -1; + endIndex = startIndex + pageConfig - 1;// numRows -1; if (endIndex - startIndex > pageConfig - 1) { startIndex = ((pageConfig * selectedPage) - (pageConfig - 1)) - 1; } @@ -390,7 +391,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Delete table rows. - * + * * @param deleteRecordIds */ public void deleteTableDataRows(ArrayList deleteRecordIds) { @@ -408,7 +409,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Get the table obj. - * + * * @return the table obj. */ public Table getTable() { @@ -432,7 +433,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { } /** - * Action taken when deleting a notification. + * Action taken when deleting a notification from view. */ public void handleDeleteNotification() { @@ -472,7 +473,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Action taken when tool tip is selected. - * + * * @param showToolTips * true when tooltips are on */ @@ -612,7 +613,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { } /** - * Action taken when deleted notifications by time. + * Action taken when deleted notifications from view by time. */ public void handleDeleteOlderThan() { @@ -689,8 +690,8 @@ public class NotificationTableComp extends TableComp implements ITableFind { } /** - * Action taken to delete notifications by priority. - * + * Action taken to delete notifications from view by priority. + * * @param priority * priority indicator */ @@ -726,7 +727,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Get the start index. - * + * * @return start index */ public int getStartIndex() { @@ -735,7 +736,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Get the end index. - * + * * @return end index */ public int getEndIndex() { @@ -744,7 +745,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Get the selected index. - * + * * @return selected index */ public int getSelectedIndex() { @@ -753,7 +754,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Get the table cell text. - * + * * @param name * The column name * @param rd @@ -782,7 +783,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Populate the NotificationRowData objects - * + * * @param notificationRecords * list of notification records */ @@ -857,7 +858,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Pass filter information. - * + * * @param username * user name table data * @param priority @@ -915,11 +916,11 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Pass filter information. - * + * * @param records * Notification record * @return boolean true if passes filter - * + * */ public boolean passesFilter(List records) { for (NotificationRecord record : records) { @@ -933,10 +934,10 @@ public class NotificationTableComp extends TableComp implements ITableFind { /** * Get the column data. - * + * * @param colName * The column name of interest - * + * * @return The populated ColumnXML object */ private ColumnXML getColumnData(String colName) { @@ -1144,7 +1145,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /* * (non-Javadoc) - * + * * @see * com.raytheon.uf.viz.datadelivery.common.ui.TableComp#handleTableMouseClick * (org.eclipse.swt.events.MouseEvent) @@ -1156,7 +1157,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /* * (non-Javadoc) - * + * * @see com.raytheon.uf.viz.datadelivery.common.ui.TableComp# * handleTableSelectionChange(org.eclipse.swt.events.SelectionEvent) */ @@ -1169,7 +1170,7 @@ public class NotificationTableComp extends TableComp implements ITableFind { /* * (non-Javadoc) - * + * * @see com.raytheon.uf.viz.core.notification.INotificationObserver# * notificationArrived * (com.raytheon.uf.viz.core.notification.NotificationMessage[]) diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/services/DataDeliveryServices.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/services/DataDeliveryServices.java index 137df8d822..d872a54231 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/services/DataDeliveryServices.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/services/DataDeliveryServices.java @@ -20,8 +20,9 @@ package com.raytheon.uf.viz.datadelivery.services; import com.raytheon.uf.common.datadelivery.bandwidth.IBandwidthService; +import com.raytheon.uf.common.datadelivery.service.IGroupDefinitionService; +import com.raytheon.uf.common.datadelivery.service.ISubscriptionNotificationService; import com.raytheon.uf.viz.datadelivery.subscription.IPermissionsService; -import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionNotificationService; import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionService; /** @@ -55,6 +56,8 @@ public final class DataDeliveryServices { private IPermissionsService permissionsService; + private IGroupDefinitionService groupDefinitionService; + /** * Disabled constructor. */ @@ -147,4 +150,24 @@ public final class DataDeliveryServices { public void setPermissionsService(IPermissionsService permissionsService) { this.permissionsService = permissionsService; } + + /** + * Get the group definition service. + * + * @return the groupDefinitionService + */ + public static IGroupDefinitionService getGroupDefinitionService() { + return INSTANCE.groupDefinitionService; + } + + /** + * Set the group definition service. + * + * @param groupDefinitionService + * the groupDefinitionService to set + */ + public void setGroupDefinitionService( + IGroupDefinitionService groupDefinitionService) { + this.groupDefinitionService = groupDefinitionService; + } } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/CreateSubscriptionDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/CreateSubscriptionDlg.java index 72c8531627..16c3244d72 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/CreateSubscriptionDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/CreateSubscriptionDlg.java @@ -39,6 +39,7 @@ import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.uf.common.datadelivery.registry.ebxml.DataSetQuery; import com.raytheon.uf.viz.datadelivery.common.ui.ActivePeriodComp; import com.raytheon.uf.viz.datadelivery.common.ui.DeliveryOptionsComp; @@ -79,6 +80,7 @@ import com.raytheon.viz.ui.presenter.components.ComboBoxConf; * Dec 13, 2012 1391 bgonzale Added cancel/ok selection status. * Jan 02, 2013 1441 djohnson Add isGroupSelected(). * Jan 04, 2013 1420 mpduff Add latency. + * Jan 25, 2013 1528 djohnson Use priority enum instead of raw integers. * * * @@ -195,7 +197,8 @@ public class CreateSubscriptionDlg extends CaveSWTDialog implements // Get latency value SystemRuleManager ruleManager = SystemRuleManager.getInstance(); int latency = ruleManager.getLatency(this.subscription, cycleTimes); - int priority = ruleManager.getPriority(this.subscription, cycleTimes); + SubscriptionPriority priority = ruleManager.getPriority( + this.subscription, cycleTimes); priorityComp = new PriorityComp(mainComp, latency, priority); this.createCycleGroup(); @@ -517,16 +520,16 @@ public class CreateSubscriptionDlg extends CaveSWTDialog implements * {@inheritDoc} */ @Override - public int getPriority() { - return priorityComp.getPriorityIndex(); + public SubscriptionPriority getPriority() { + return priorityComp.getPriority(); } /** * {@inheritDoc} */ @Override - public void setPriority(int i) { - priorityComp.setPriorityIndex(i); + public void setPriority(SubscriptionPriority priority) { + priorityComp.setPriority(priority); } /** @@ -842,14 +845,6 @@ public class CreateSubscriptionDlg extends CaveSWTDialog implements this.subscription = subscription; } - /** - * {@inheritDoc} - */ - @Override - public int getPriorityValue() { - return priorityComp.getPriorityIndex(); - } - /** * {@inheritDoc} */ diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/DeleteGroupDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/DeleteGroupDlg.java index 51fc1a218b..1b1a40f50a 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/DeleteGroupDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/DeleteGroupDlg.java @@ -29,12 +29,14 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; +import com.raytheon.uf.common.datadelivery.service.IGroupDefinitionService; import com.raytheon.uf.common.registry.handler.RegistryHandlerException; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.viz.datadelivery.common.ui.GroupSelectComp; import com.raytheon.uf.viz.datadelivery.common.ui.IGroupAction; +import com.raytheon.uf.viz.datadelivery.services.DataDeliveryServices; import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryUtils; import com.raytheon.viz.ui.dialogs.CaveSWTDialog; @@ -47,7 +49,8 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Jan 2, 2013 1441 djohnson Initial creation + * Jan 2, 2013 1441 djohnson Initial creation + * Jan 18, 2013 1441 djohnson Use group definition service. * * * @@ -68,6 +71,9 @@ public class DeleteGroupDlg extends CaveSWTDialog { private final IUFStatusHandler statusHandler = UFStatus .getHandler(DeleteGroupDlg.class); + private final IGroupDefinitionService groupService = DataDeliveryServices + .getGroupDefinitionService(); + /** * @param shell * @param groupAction @@ -144,8 +150,11 @@ public class DeleteGroupDlg extends CaveSWTDialog { + groupName + "?")) { try { - DataDeliveryHandlers.getGroupDefinitionHandler() - .deleteByName(groupName); + groupService + .deleteGroupDefinition( + DataDeliveryHandlers + .getGroupDefinitionHandler() + .getByName(groupName)); groupAction.loadGroupNames(); return true; } catch (RegistryHandlerException e) { diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/GroupAddDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/GroupAddDlg.java index c3336c42c2..fa1c062988 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/GroupAddDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/GroupAddDlg.java @@ -34,6 +34,7 @@ import org.eclipse.swt.widgets.Shell; import com.raytheon.uf.common.datadelivery.registry.GroupDefinition; import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; +import com.raytheon.uf.common.datadelivery.service.ISubscriptionNotificationService; import com.raytheon.uf.common.registry.handler.RegistryHandlerException; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/RequestFromServerPermissionsService.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/RequestFromServerPermissionsService.java index 5876cde154..bd3426dc3f 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/RequestFromServerPermissionsService.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/RequestFromServerPermissionsService.java @@ -19,12 +19,14 @@ **/ package com.raytheon.uf.viz.datadelivery.subscription; +import com.raytheon.uf.common.auth.resp.SuccessfulExecution; import com.raytheon.uf.common.auth.user.IUser; import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.datadelivery.request.DataDeliveryAuthRequest; +import com.raytheon.uf.common.datadelivery.request.DataDeliveryConstants; import com.raytheon.uf.common.datadelivery.request.DataDeliveryPermission; +import com.raytheon.uf.common.serialization.comm.RequestRouter; import com.raytheon.uf.viz.core.exception.VizException; -import com.raytheon.uf.viz.core.requests.ThriftClient; /** * {@link IPermissionsService} implementation that requests permissions from the @@ -37,6 +39,7 @@ import com.raytheon.uf.viz.core.requests.ThriftClient; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Jan 04, 2013 1441 djohnson Initial creation + * Jan 21, 2013 1441 djohnson Use RequestRouter. * * * @@ -93,8 +96,13 @@ public class RequestFromServerPermissionsService implements IPermissionsService */ private DataDeliveryAuthRequest sendAuthorizationRequest( DataDeliveryAuthRequest request) throws VizException { - return (DataDeliveryAuthRequest) ThriftClient - .sendPrivilegedRequest(request); + try { + return (DataDeliveryAuthRequest) ((SuccessfulExecution) RequestRouter + .route(request, DataDeliveryConstants.DATA_DELIVERY_SERVER)) + .getResponse(); + } catch (Exception e) { + throw new VizException(e); + } } /** diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionManagerDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionManagerDlg.java index 773356ec39..d7ce4442f9 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionManagerDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionManagerDlg.java @@ -53,12 +53,12 @@ import com.raytheon.uf.common.auth.user.IUser; import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.datadelivery.registry.handlers.ISubscriptionHandler; import com.raytheon.uf.common.datadelivery.request.DataDeliveryPermission; +import com.raytheon.uf.common.datadelivery.service.ISubscriptionNotificationService; import com.raytheon.uf.common.registry.handler.RegistryHandlerException; import com.raytheon.uf.common.registry.handler.RegistryObjectHandlers; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; -import com.raytheon.uf.viz.core.VizApp; import com.raytheon.uf.viz.core.auth.UserController; import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.datadelivery.actions.DataBrowserAction; @@ -112,6 +112,9 @@ import com.raytheon.viz.ui.presenter.IDisplay; * Jan 02, 2013 1441 djohnson Add ability to delete groups. * Jan 03, 2013 1437 bgonzale Moved configuration file management code to SubscriptionManagerConfigDlg * and SubscriptionConfigurationManager. + * Jan 21, 2013 1501 djohnson Only send notification if subscription was actually activated/deactivated, + * remove race condition of GUI thread updating the table after notification. + * Jan 22, 2013 1520 mpduff Removed menu accelerators. * * * @author mpduff @@ -315,7 +318,7 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements fileMenuItem.setMenu(fileMenu); MenuItem newMI = new MenuItem(fileMenu, SWT.NONE); - newMI.setText("&New Subscription..."); + newMI.setText("New Subscription..."); newMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -324,7 +327,7 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements }); MenuItem groupMI = new MenuItem(fileMenu, SWT.NONE); - groupMI.setText("&New Group..."); + groupMI.setText("New Group..."); groupMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -356,7 +359,7 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements new MenuItem(fileMenu, SWT.SEPARATOR); MenuItem exitMI = new MenuItem(fileMenu, SWT.NONE); - exitMI.setText("&Exit"); + exitMI.setText("Exit"); exitMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -374,7 +377,7 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements settingsMenuItem.setMenu(settingsMenu); MenuItem configureMI = new MenuItem(settingsMenu, SWT.NONE); - configureMI.setText("&Configure Table..."); + configureMI.setText("Configure Table..."); configureMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -383,7 +386,7 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements }); tooltipMI = new MenuItem(settingsMenu, SWT.CHECK); - tooltipMI.setText("&Tooltips"); + tooltipMI.setText("Tooltips"); tooltipMI.setSelection(false); tooltipMI.addSelectionListener(new SelectionAdapter() { @Override @@ -401,7 +404,7 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements helpMenuItem.setMenu(helpMenu); MenuItem helpNotTableMI = new MenuItem(helpMenu, SWT.NONE); - helpNotTableMI.setText("&About Subscription Manager..."); + helpNotTableMI.setText("About Subscription Manager..."); helpNotTableMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -421,7 +424,7 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements editMenuItem.setMenu(editMenu); MenuItem editMI = new MenuItem(editMenu, SWT.NONE); - editMI.setText("&Edit Subscription..."); + editMI.setText("Edit Subscription..."); editMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -430,7 +433,7 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements }); MenuItem copyMI = new MenuItem(editMenu, SWT.NONE); - copyMI.setText("&Copy Subscription..."); + copyMI.setText("Copy Subscription..."); copyMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -439,7 +442,7 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements }); MenuItem deleteMI = new MenuItem(editMenu, SWT.NONE); - deleteMI.setText("&Delete Subscription"); + deleteMI.setText("Delete Subscription"); deleteMI.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { @@ -589,8 +592,8 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements String msg = user.uniqueId() + " is not authorized to create subscriptions"; try { - if (DataDeliveryServices.getPermissionsService().checkPermission(user, msg, permission) - .isAuthorized()) { + if (DataDeliveryServices.getPermissionsService() + .checkPermission(user, msg, permission).isAuthorized()) { DataBrowserAction action = new DataBrowserAction(); Map params = new HashMap(); ExecutionEvent ee = new ExecutionEvent(null, params, null, null); @@ -620,8 +623,8 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements + permission; try { - if (DataDeliveryServices.getPermissionsService().checkPermission(user, msg, permission) - .isAuthorized()) { + if (DataDeliveryServices.getPermissionsService() + .checkPermission(user, msg, permission).isAuthorized()) { if (create) { if (createGroupDlg == null) { createGroupDlg = new CreateGroupDefinitionDlg( @@ -742,8 +745,8 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements + permission; try { - if (DataDeliveryServices.getPermissionsService().checkPermission(user, msg, permission) - .isAuthorized()) { + if (DataDeliveryServices.getPermissionsService() + .checkPermission(user, msg, permission).isAuthorized()) { String message = null; if (selectionCount > 1) { @@ -829,8 +832,8 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements + " Subscriptions\nPermission: " + permission; try { - if (DataDeliveryServices.getPermissionsService().checkPermission(user, msg, permission) - .isAuthorized()) { + if (DataDeliveryServices.getPermissionsService() + .checkPermission(user, msg, permission).isAuthorized()) { final List updatedList = new ArrayList(); int count = tableComp.getTable().getSelectionCount(); @@ -864,34 +867,23 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements SWT.OK, sub.getName() + " Activated", response.getMessageToDisplay()); } - updatedList.add(sub); - - if (activate) { - subscriptionNotificationService - .sendSubscriptionActivatedNotification( - sub, - username); - - } else { - subscriptionNotificationService - .sendSubscriptionDeactivatedNotification( - sub, username); + if (!response.isAllowFurtherEditing()) { + if (activate) { + subscriptionNotificationService + .sendSubscriptionActivatedNotification( + sub, username); + } else { + subscriptionNotificationService + .sendSubscriptionDeactivatedNotification( + sub, username); + } } } catch (RegistryHandlerException e) { statusHandler.handle(Priority.PROBLEM, "Error processing request.", e); } } - - VizApp.runAsync(new Runnable() { - @Override - public void run() { - if (isDisposed() == false) { - tableComp.updateTable(updatedList); - } - } - }); } } } catch (VizException e) { @@ -1064,10 +1056,12 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements String msg = user.uniqueId() + " is not authorized to access Subscription Approval"; - return DataDeliveryServices.getPermissionsService().checkPermissions(user, msg, - DataDeliveryPermission.SUBSCRIPTION_APPROVE_SITE, - DataDeliveryPermission.SUBSCRIPTION_APPROVE_USER, - DataDeliveryPermission.SUBSCRIPTION_APPROVE_VIEW) + return DataDeliveryServices + .getPermissionsService() + .checkPermissions(user, msg, + DataDeliveryPermission.SUBSCRIPTION_APPROVE_SITE, + DataDeliveryPermission.SUBSCRIPTION_APPROVE_USER, + DataDeliveryPermission.SUBSCRIPTION_APPROVE_VIEW) .isAuthorized(); } catch (VizException e) { statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e); @@ -1097,8 +1091,8 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements for (Subscription subscription : subscriptions) { subscriptionNotificationService - .sendDeletedSubscriptionNotification( - subscription, username); + .sendDeletedSubscriptionNotification(subscription, + username); } } catch (RegistryHandlerException e) { exceptions.add(e); diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionManagerRowData.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionManagerRowData.java index 81a7724227..e417a43a43 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionManagerRowData.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionManagerRowData.java @@ -46,6 +46,7 @@ import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryUtils.TABLE_TYPE; * Aug 10, 2012 1002 mpduff Change dataset size from int to long. * Aug 21, 2012 712 mpduff Make priorities display as 1, 2, 3. * Oct 2, 2012 1103 jpiatt Remove unused methods, update enum, code clean up. + * Jan 25, 2012 1528 djohnson Priorities no longer need incrementing for display. * * * @author mpduff @@ -67,7 +68,7 @@ public class SubscriptionManagerRowData implements ITableData * @@ -357,6 +359,7 @@ public class SubscriptionService implements ISubscriptionService { final ServiceInteraction action = new ServiceInteraction() { @Override public String call() throws RegistryHandlerException { + subscription.setUnscheduled(false); DataDeliveryHandlers.getSubscriptionHandler().update( subscription); return successMessage; @@ -379,6 +382,7 @@ public class SubscriptionService implements ISubscriptionService { @Override public String call() throws RegistryHandlerException { for (Subscription sub : subs) { + sub.setUnscheduled(false); DataDeliveryHandlers.getSubscriptionHandler().update(sub); } return successMessage; @@ -438,6 +442,7 @@ public class SubscriptionService implements ISubscriptionService { subscription).isAuthorized(); try { if (authorized) { + subscription.setUnscheduled(false); DataDeliveryHandlers.getSubscriptionHandler() .update(subscription); } else { diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionTableComp.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionTableComp.java index 7611ac3fab..35e8503823 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionTableComp.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SubscriptionTableComp.java @@ -47,12 +47,12 @@ import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import com.raytheon.uf.common.auth.user.IUser; -import com.raytheon.uf.common.datadelivery.event.notification.SubscriptionNotificationResponse; import com.raytheon.uf.common.datadelivery.registry.PendingSubscription; import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; import com.raytheon.uf.common.datadelivery.registry.handlers.ISubscriptionHandler; import com.raytheon.uf.common.datadelivery.request.DataDeliveryPermission; +import com.raytheon.uf.common.datadelivery.service.SubscriptionNotificationResponse; import com.raytheon.uf.common.registry.handler.RegistryHandlerException; import com.raytheon.uf.common.registry.handler.RegistryObjectHandlers; import com.raytheon.uf.common.status.IUFStatusHandler; @@ -100,6 +100,7 @@ import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryUtils.TABLE_TYPE; * Dec 03, 2012 1279 mpduff Add ability to populate from a list of subscription names. * Dec 12, 2012 1391 bgonzale Added a job for subscription retrieves. * Jan 07, 2013 1437 bgonzale Added sort column direction updates. + * Jan 28, 2013 1529 djohnson Disable menu items if no subscriptions are selected. * * * @@ -120,7 +121,7 @@ public class SubscriptionTableComp extends TableComp implements IGroupAction { * Subscription action callback that is called when there is a table * selection. */ - private ISubscriptionAction subActionCallback; + private final ISubscriptionAction subActionCallback; /** TableDataManager object. */ private TableDataManager subManagerData; @@ -756,11 +757,14 @@ public class SubscriptionTableComp extends TableComp implements IGroupAction { popupMenu.dispose(); } + final boolean menuItemsEnabled = table.getSelectionIndices().length > 0; + // Detail popup menu popupMenu = new Menu(table); - MenuItem item1 = new MenuItem(popupMenu, SWT.PUSH); - item1.setText("Details... "); - item1.addSelectionListener(new SelectionAdapter() { + MenuItem detailsItem = new MenuItem(popupMenu, SWT.PUSH); + detailsItem.setText("Details... "); + detailsItem.setEnabled(menuItemsEnabled); + detailsItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { handleDetails(); @@ -770,6 +774,7 @@ public class SubscriptionTableComp extends TableComp implements IGroupAction { if (subType == SubscriptionType.MANAGER) { MenuItem editItem = new MenuItem(popupMenu, SWT.PUSH); editItem.setText("Edit..."); + editItem.setEnabled(menuItemsEnabled); editItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { @@ -780,6 +785,7 @@ public class SubscriptionTableComp extends TableComp implements IGroupAction { // Add the selected row to a subscription group MenuItem groupItem = new MenuItem(popupMenu, SWT.PUSH); groupItem.setText("Add to Group..."); + groupItem.setEnabled(menuItemsEnabled); groupItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubApprovalTableComp.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubApprovalTableComp.java index a30fca28e5..20b78e220a 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubApprovalTableComp.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubApprovalTableComp.java @@ -33,14 +33,14 @@ import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; -import com.raytheon.uf.common.datadelivery.event.notification.ApprovedPendingSubscriptionNotificationResponse; -import com.raytheon.uf.common.datadelivery.event.notification.BaseSubscriptionNotificationResponse; -import com.raytheon.uf.common.datadelivery.event.notification.DeniedPendingSubscriptionNotificationResponse; -import com.raytheon.uf.common.datadelivery.event.notification.PendingSubscriptionNotificationResponse; import com.raytheon.uf.common.datadelivery.registry.InitialPendingSubscription; import com.raytheon.uf.common.datadelivery.registry.PendingSubscription; import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; +import com.raytheon.uf.common.datadelivery.service.ApprovedPendingSubscriptionNotificationResponse; +import com.raytheon.uf.common.datadelivery.service.BaseSubscriptionNotificationResponse; +import com.raytheon.uf.common.datadelivery.service.DeniedPendingSubscriptionNotificationResponse; +import com.raytheon.uf.common.datadelivery.service.PendingSubscriptionNotificationResponse; import com.raytheon.uf.common.registry.handler.RegistryHandlerException; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubscriptionApprovalDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubscriptionApprovalDlg.java index 304d826ca4..49a2d98101 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubscriptionApprovalDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubscriptionApprovalDlg.java @@ -40,6 +40,7 @@ import com.raytheon.uf.common.datadelivery.registry.PendingSubscription; import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.datadelivery.registry.handlers.IPendingSubscriptionHandler; import com.raytheon.uf.common.datadelivery.request.DataDeliveryPermission; +import com.raytheon.uf.common.datadelivery.service.ISubscriptionNotificationService; import com.raytheon.uf.common.registry.handler.RegistryHandlerException; import com.raytheon.uf.common.registry.handler.RegistryObjectHandlers; import com.raytheon.uf.common.status.IUFStatusHandler; @@ -57,7 +58,6 @@ import com.raytheon.uf.viz.datadelivery.services.DataDeliveryServices; import com.raytheon.uf.viz.datadelivery.subscription.CancelForceApplyAndIncreaseLatencyDisplayText; import com.raytheon.uf.viz.datadelivery.subscription.IPermissionsService; import com.raytheon.uf.viz.datadelivery.subscription.IPermissionsService.IAuthorizedPermissionResponse; -import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionNotificationService; import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionService; import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionService.ISubscriptionServiceResult; import com.raytheon.uf.viz.datadelivery.subscription.SubscriptionService.ForceApplyPromptResponse; diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubscriptionDiff.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubscriptionDiff.java index 9b3a2de695..c798b52aee 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubscriptionDiff.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/approve/SubscriptionDiff.java @@ -52,6 +52,7 @@ import com.vividsolutions.jts.geom.Coordinate; * Jul 25, 2012 955 djohnson Use List instead of ArrayList. * Sep 24, 2012 1157 mpduff Use InitialPendingSubsription. * Dec 10, 2012 1259 bsteffen Switch Data Delivery from LatLon to referenced envelopes. + * Jan 25, 2013 1528 djohnson Compare priorities as primitive ints. * * * @@ -115,7 +116,7 @@ public class SubscriptionDiff { getMap(); - if (!(sub.getPriority().equals(pendingSub.getPriority()))) { + if (sub.getPriority() != pendingSub.getPriority()) { diffMap.put("priority", true); } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionDlgPresenter.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionDlgPresenter.java index ff508e7f9d..794c32f1fe 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionDlgPresenter.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/presenter/CreateSubscriptionDlgPresenter.java @@ -44,10 +44,12 @@ import com.raytheon.uf.common.datadelivery.registry.InitialPendingSubscription; import com.raytheon.uf.common.datadelivery.registry.OpenDapGriddedDataSet; import com.raytheon.uf.common.datadelivery.registry.PendingSubscription; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.uf.common.datadelivery.registry.Utils.SubscriptionStatus; import com.raytheon.uf.common.datadelivery.registry.handlers.IPendingSubscriptionHandler; import com.raytheon.uf.common.datadelivery.registry.handlers.ISubscriptionHandler; import com.raytheon.uf.common.datadelivery.request.DataDeliveryPermission; +import com.raytheon.uf.common.datadelivery.service.ISubscriptionNotificationService; import com.raytheon.uf.common.registry.ebxml.RegistryUtil; import com.raytheon.uf.common.registry.handler.RegistryHandlerException; import com.raytheon.uf.common.registry.handler.RegistryObjectHandlers; @@ -62,7 +64,6 @@ import com.raytheon.uf.viz.core.localization.LocalizationManager; import com.raytheon.uf.viz.datadelivery.services.DataDeliveryServices; import com.raytheon.uf.viz.datadelivery.subscription.CancelForceApplyAndIncreaseLatencyDisplayText; import com.raytheon.uf.viz.datadelivery.subscription.GroupDefinitionManager; -import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionNotificationService; import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionService; import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionService.ISubscriptionServiceResult; import com.raytheon.uf.viz.datadelivery.subscription.view.ICreateSubscriptionDlgView; @@ -100,6 +101,9 @@ import com.raytheon.viz.ui.presenter.components.WidgetConf; * Jan 02, 2013 1441 djohnson Access GroupDefinitionManager in a static fashion. * Jan 04, 2012 1420 mpduff Add Latency to PriorityComp. * Jan 11, 2013 1453 djohnson Sets cycle times on construction. + * Jan 14, 2013 1286 djohnson Check that message to display is not null or empty, and + * only send notification of subscription creation on OK status. + * Jan 25, 2013 1528 djohnson Use priority enum instead of raw integers, default to existing priority on edit. * * * @author mpduff @@ -371,6 +375,10 @@ public class CreateSubscriptionDlgPresenter { view.setActiveEndDateBtnEnabled(false); } + if (!create) { + view.setPriority(subscription.getPriority()); + } + List cycleTimes = subscription.getTime().getCycleTimes(); if (cycleTimes != null) { List cycleStrings = new ArrayList(); @@ -502,8 +510,8 @@ public class CreateSubscriptionDlgPresenter { } // priority - int priorityInd = view.getPriority(); - subscription.setPriority(priorityInd); + SubscriptionPriority priority = view.getPriority(); + subscription.setPriority(priority); subscription.setOfficeID(LocalizationManager.getInstance() .getCurrentSite()); @@ -557,17 +565,21 @@ public class CreateSubscriptionDlgPresenter { job.addJobChangeListener(new JobChangeAdapter() { @Override public void done(final IJobChangeEvent event) { - subscriptionNotificationService - .sendCreatedSubscriptionNotification( - subscription, username); final IStatus status = event.getResult(); - if (status.getMessage() != null) { + + final boolean subscriptionCreated = status.isOK(); + if (subscriptionCreated) { + sendSubscriptionNotification(subscription, + username); + } + + if (!Strings.isNullOrEmpty(status.getMessage())) { guiThreadTaskExecutor.runAsync(new Runnable() { @Override public void run() { if (!view.isDisposed()) { - if (status.isOK()) { + if (subscriptionCreated) { view.displayPopup( CREATED_TITLE, status.getMessage()); diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedEnsembleSubsetTab.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedEnsembleSubsetTab.java new file mode 100644 index 0000000000..3bd98c2bec --- /dev/null +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedEnsembleSubsetTab.java @@ -0,0 +1,177 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.datadelivery.subscription.subset; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; + +import com.raytheon.uf.common.datadelivery.registry.Ensemble; +import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.util.CollectionUtil; +import com.raytheon.uf.viz.datadelivery.subscription.subset.xml.SubsetXML; +import com.raytheon.viz.ui.widgets.duallist.DualList; +import com.raytheon.viz.ui.widgets.duallist.DualListConfig; +import com.raytheon.viz.ui.widgets.duallist.IUpdate; + +/** + * + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 3, 2013            bsteffen     Initial creation
+ * 
+ * 
+ * + * @author bsteffen + * @version 1.0 + */ +public class GriddedEnsembleSubsetTab { + + private static final String NAME = "Ensemble Members"; + + private final Set listeners = new HashSet(); + + private final Ensemble ensemble; + + private DualList dualList; + + private boolean modified; + + public GriddedEnsembleSubsetTab(Composite parentComp, Ensemble ensemble) { + this.ensemble = ensemble; + init(parentComp); + } + + private void init(Composite parentComp) { + GridLayout gl = new GridLayout(1, false); + GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + + gl.horizontalSpacing = 0; + gl.verticalSpacing = 0; + gl.marginWidth = 0; + gl.marginHeight = 0; + + Group group = new Group(parentComp, SWT.NONE); + group.setText(getName()); + group.setLayout(gl); + group.setLayoutData(gd); + + DualListConfig dualListConfig = new DualListConfig(); + dualListConfig.setAvailableListLabel("Available Members:"); + dualListConfig.setSelectedListLabel("Selected Memebers:"); + dualListConfig.setListHeight(125); + dualListConfig.setListWidth(175); + dualListConfig.setShowUpDownBtns(false); + dualListConfig.setFullList(ensemble.getMembers()); + dualList = new DualList(group, SWT.NONE, dualListConfig, + new IUpdate() { + + @Override + public void selectionChanged() { + modified = true; + notifyListeners(); + } + + @Override + public void hasEntries(boolean entries) { + + } + }); + } + + public String getName() { + return NAME; + } + + public Ensemble getEnsembleWithSelection() { + Ensemble ensemble = new Ensemble(this.ensemble); + ensemble.setSelectedMembers(Arrays.asList(dualList + .getSelectedListItems())); + return ensemble; + } + + private void loadFromEnsemble(Ensemble ensemble) { + dualList.clearSelection(); + if (ensemble != null && ensemble.getSelectedMembers() != null) { + dualList.selectItems(ensemble.getSelectedMembers().toArray( + new String[0])); + } + } + + public void populateSubscription(Subscription subscription) { + subscription.setEnsemble(getEnsembleWithSelection()); + } + + public void loadFromSubscription(Subscription subscription) { + loadFromEnsemble(subscription.getEnsemble()); + } + + public void populateSubsetXML(SubsetXML subsetXml) { + subsetXml.setEnsemble(getEnsembleWithSelection()); + } + + public void loadFromSubsetXML(SubsetXML subsetXml) { + loadFromEnsemble(subsetXml.getEnsemble()); + } + + public boolean isValid() { + return !CollectionUtil.isNullOrEmpty(dualList.getSelectedListItems()); + } + + public boolean isModified() { + return modified; + } + + public void setModified(boolean modified) { + this.modified = modified; + } + + public void addListener(IDataSize listener) { + synchronized (this.listeners) { + listeners.add(listener); + } + } + + protected void notifyListeners() { + Collection listeners; + synchronized (this.listeners) { + listeners = new ArrayList( + this.listeners); + } + for (IDataSize listener : listeners) { + listener.updateDataSize(); + } + } + +} diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedSubsetManagerDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedSubsetManagerDlg.java index 08310c7fdf..3d11bf9dd7 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedSubsetManagerDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedSubsetManagerDlg.java @@ -24,6 +24,7 @@ import java.io.StringWriter; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,13 +35,18 @@ import java.util.TreeSet; import javax.xml.bind.JAXBException; import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.TabItem; import org.geotools.geometry.jts.ReferencedEnvelope; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Ordering; import com.raytheon.uf.common.datadelivery.registry.DataSetMetaData; +import com.raytheon.uf.common.datadelivery.registry.Ensemble; import com.raytheon.uf.common.datadelivery.registry.GriddedDataSet; import com.raytheon.uf.common.datadelivery.registry.GriddedDataSetMetaData; import com.raytheon.uf.common.datadelivery.registry.Subscription; @@ -77,6 +83,8 @@ import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryUtils; * Dec 10, 2012 1259 bsteffen Switch Data Delivery from LatLon to referenced envelopes. * Jan 04, 2013 1299 djohnson Add logging of invalid forecast hour information if it occurs again. * Jan 04, 2013 1420 mpduff Pass cycles in for rules. + * Jan 18, 2013 1414 bsteffen Add ensemble tab. + * Jan 28, 2013 1533 djohnson Update the calculated dataset size after loading subset xml. * * * @@ -115,6 +123,8 @@ public class GriddedSubsetManagerDlg private DataSetMetaData metaData; + private GriddedEnsembleSubsetTab ensembleTab; + /** * Constructor. * @@ -150,6 +160,83 @@ public class GriddedSubsetManagerDlg super(shell, dataSet); } + @Override + protected void createGridTabs(TabFolder tabFolder) { + super.createGridTabs(tabFolder); + Ensemble e = dataSet.getEnsemble(); + if (e != null && e.getMembers() != null) { + TabItem ensembleTabItem = new TabItem(tabFolder, SWT.NONE, 2); + Composite ensembleComp = new Composite(tabFolder, SWT.NONE); + ensembleComp.setLayout(new GridLayout(1, false)); + ensembleComp.setLayoutData(new GridData(SWT.CENTER, SWT.DEFAULT, + true, false)); + ensembleTabItem.setControl(ensembleComp); + ensembleTab = new GriddedEnsembleSubsetTab(ensembleComp, + dataSet.getEnsemble()); + ensembleTab.addListener(this); + ensembleTabItem.setText(ensembleTab.getName()); + } + } + + @Override + protected Collection getInvalidTabs() { + Collection invalidTabs = super.getInvalidTabs(); + if (ensembleTab != null && !ensembleTab.isValid()) { + invalidTabs.add(ensembleTab.getName()); + } + return invalidTabs; + } + + @Override + protected void populateSubsetXML(SubsetXML subset) { + super.populateSubsetXML(subset); + if (ensembleTab != null) { + ensembleTab.populateSubsetXML(subset); + } + } + + @Override + protected void loadFromSubsetXML(SubsetXML subsetXml) { + super.loadFromSubsetXML(subsetXml); + if (ensembleTab != null) { + ensembleTab.loadFromSubsetXML(subsetXml); + } + updateDataSize(); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.viz.datadelivery.subscription.subset.SubsetManagerDlg + * #loadFromSubscription + * (com.raytheon.uf.common.datadelivery.registry.Subscription) + */ + @Override + protected void loadFromSubscription(Subscription subscription) { + super.loadFromSubscription(subscription); + if (ensembleTab != null) { + ensembleTab.loadFromSubscription(subscription); + } + } + + @Override + protected boolean isDirty() { + boolean modified = super.isDirty(); + if (!modified && ensembleTab != null) { + modified = ensembleTab.isModified(); + } + return modified; + } + + @Override + protected void setClean() { + super.setClean(); + if (ensembleTab != null) { + ensembleTab.setModified(false); + } + } + /** * {@inheritDoc} */ @@ -186,6 +273,11 @@ public class GriddedSubsetManagerDlg time.setSelectedTimeIndices(fcstIndices); subscription.setTime(time); + + if (ensembleTab != null) { + ensembleTab.populateSubscription(subscription); + } + return subscription; } @@ -193,7 +285,7 @@ public class GriddedSubsetManagerDlg * {@inheritDoc} */ @Override - protected SpecificDateTimeXML getTimeXml() { + protected SpecificDateTimeXML getTimeXmlFromSubscription() { SpecificDateTimeXML timeXml = new SpecificDateTimeXML(); Time time = this.subscription.getTime(); List cycleTimes = time.getCycleTimes(); @@ -270,7 +362,12 @@ public class GriddedSubsetManagerDlg // Get the temporal data int numFcstHours = this.timingTabControls.getSelectedFcstHours().length; dataSize.setNumFcstHours(numFcstHours); - + if (ensembleTab != null) { + dataSize.setNumEnsembleMembers(ensembleTab + .getEnsembleWithSelection()); + } else { + dataSize.setNumEnsembleMembers(dataSet.getEnsemble()); + } // Get the Areal data ReferencedEnvelope envelope = this.spatialTabControls.getEnvelope(); diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedTimingSelectionDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedTimingSelectionDlg.java index 473bd67b46..9624f13737 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedTimingSelectionDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/GriddedTimingSelectionDlg.java @@ -33,6 +33,7 @@ import org.eclipse.swt.widgets.List; import org.eclipse.swt.widgets.Shell; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.uf.viz.datadelivery.common.ui.PriorityComp; import com.raytheon.uf.viz.datadelivery.subscription.subset.presenter.IGriddedTimingSelectionDlgView; import com.raytheon.uf.viz.datadelivery.system.SystemRuleManager; @@ -55,6 +56,7 @@ import com.raytheon.viz.ui.presenter.components.ListConf; * Oct 11, 2012 1263 jpiatt Modified for cancel button * Nov 20, 2012 1286 djohnson Implement displayYesNoPopup. * Jan 04, 2013 1420 mpduff Add Priority Composite. + * Jan 25, 2013 1528 djohnson Subscription priority is now an enum. * * * @@ -137,7 +139,8 @@ public class GriddedTimingSelectionDlg extends CaveSWTDialog implements // Get latency value SystemRuleManager ruleManager = SystemRuleManager.getInstance(); int latency = ruleManager.getLatency(this.subscription, cycleTimes); - int priority = ruleManager.getPriority(this.subscription, cycleTimes); + SubscriptionPriority priority = ruleManager + .getPriority(this.subscription, cycleTimes); priorityComp = new PriorityComp(shell, latency, priority); gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false); @@ -337,7 +340,7 @@ public class GriddedTimingSelectionDlg extends CaveSWTDialog implements * {@inheritDoc} */ @Override - public int getPriority() { - return priorityComp.getPriorityIndex(); + public SubscriptionPriority getPriority() { + return priorityComp.getPriority(); } } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/SubsetManagerDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/SubsetManagerDlg.java index e9c6a9e22f..f4040cc45f 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/SubsetManagerDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/SubsetManagerDlg.java @@ -20,7 +20,9 @@ package com.raytheon.uf.viz.datadelivery.subscription.subset; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; @@ -50,6 +52,7 @@ import com.raytheon.uf.common.datadelivery.registry.DataSet; import com.raytheon.uf.common.datadelivery.registry.DataType; import com.raytheon.uf.common.datadelivery.registry.GriddedCoverage; import com.raytheon.uf.common.datadelivery.registry.GriddedDataSet; +import com.raytheon.uf.common.datadelivery.registry.Levels; import com.raytheon.uf.common.datadelivery.registry.Parameter; import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.datadelivery.registry.Time; @@ -122,6 +125,7 @@ import com.raytheon.viz.ui.presenter.IDisplay; * Jan 02, 2012 1345 djohnson Use gui thread task executor. * Jan 04, 2012 1420 mpduff Pass the subscription in to the GriddedTimingSelectionDlg. * Jan 10, 2013 1444 mpduff Fix the loading of saved subsets from the saved subset tab. + * Jan 28, 2013 1530 djohnson Break out long method chaining into local variables for debugging. * * * @author mpduff @@ -137,9 +141,6 @@ public abstract class SubsetManagerDlg tabTextMap = new HashMap(); - /** Subset Name text box */ private Text nameText; @@ -180,15 +181,6 @@ public abstract class SubsetManagerDlg tabsValidMap = new HashMap(); + Collection invalidTabs = getInvalidTabs(); + + if (!invalidTabs.isEmpty()) { + StringBuilder message = new StringBuilder( + "The following tabs do not have valid entries:\n\n"); + for (String tab : invalidTabs) { + message.append(tab + "\n"); + } + DataDeliveryUtils.showMessage(shell, getStyle(), "Invalid Entries", + message.toString()); + return false; + } + + return true; + } + + protected Collection getInvalidTabs() { + Collection invalidTabs = new ArrayList(3); // Get the tabs to validate // TODO Hardcoding the tabs for now, fix this later // Validate the vertical tab - tabsValidMap.put(VERTICAL_TAB, vTab.isValid()); + if (!vTab.isValid()) { + invalidTabs.add(VERTICAL_TAB); + } - tabsValidMap.put(TIMING_TAB, timingTabControls.isValid()); + if (!timingTabControls.isValid()) { + invalidTabs.add(TIMING_TAB); + } // Next is spatial subset tab - tabsValidMap.put(SPATIAL_TAB, spatialTabControls.isValid()); - - StringBuilder buf = new StringBuilder( - "The following tabs do not have valid entries:\n\n"); - boolean showMsg = false; - for (String tab : tabsValidMap.keySet()) { - if (!tabsValidMap.get(tab)) { - buf.append(tabTextMap.get(tab) + "\n"); - showMsg = true; - } + if (!spatialTabControls.isValid()) { + invalidTabs.add(SPATIAL_TAB); } - if (showMsg) { - DataDeliveryUtils.showMessage(shell, getStyle(), "Invalid Entries", - buf.toString()); - return false; - } - - return true; + return invalidTabs; } /** @@ -806,6 +796,15 @@ public abstract class SubsetManagerDlg subset = new SubsetXML(); + populateSubsetXML(subset); + + // Have all the info, now save the file + SubsetFileManager.getInstance().saveSubset(subset, this.shell); + setClean(); + subsetTab.enableButtons(nameText); + } + + protected void populateSubsetXML(SubsetXML subset) { subset.setBaseSubsetName(nameText.getText()); subset.setDatasetName(dataSet.getDataSetName()); subset.setProviderName(dataSet.getProviderName()); @@ -821,12 +820,6 @@ public abstract class SubsetManagerDlg loadedSubsetXml = (SubsetXML) SubsetFileManager .getInstance().loadSubset(subsetName); - updateSelections(loadedSubsetXml); + loadFromSubsetXML(loadedSubsetXml); } - /** - * Populate the dialog controls. - */ - private void populate() { - if (subsetXml == null) { - if (subscription == null) { - return; - } - populateSubset(); - } - - AreaXML area = subsetXml.getArea(); - spatialTabControls.setDataSet(this.dataSet); - spatialTabControls.populate(area); - + protected void loadFromSubsetXML(SubsetXML subsetXml) { ArrayList vertList = subsetXml.getVerticalList(); vTab.populate(vertList, dataSet); TIMEXML time = subsetXml.getTime(); this.timingTabControls.populate(time, dataSet); - this.nameText.setText(subsetXml.getBaseSubsetName()); + + if (this.subsetXml == subsetXml) { + // only populate area and name if subsetXml is loading from initial + // load, not from the saved subsets tab. + AreaXML area = subsetXml.getArea(); + spatialTabControls.setDataSet(this.dataSet); + spatialTabControls.populate(area); + + this.nameText.setText(subsetXml.getBaseSubsetName()); + } } - /** - * Update selections with from the loadedSubsetXML object. - */ - private void updateSelections(SubsetXML loadedSubsetXml) { - ArrayList vertList = loadedSubsetXml.getVerticalList(); - vTab.updateSettings(vertList); - - TIMEXML time = loadedSubsetXml.getTime(); - timingTabControls.updateSettings(time); - } - - /** - * Populate the subset object. - */ - private void populateSubset() { - subsetXml = new SubsetXML(); - subsetXml.setDatasetName(this.dataSet.getDataSetName()); - subsetXml.setProviderName(this.dataSet.getProviderName()); - subsetXml.setSubsetName(this.subscription.getName()); + protected void loadFromSubscription(Subscription subscription) { + this.nameText.setText(this.subscription.getName()); // Cycle time - TIMEXML timeXml = getTimeXml(); + TIMEXML timeXml = getTimeXmlFromSubscription(); timeXml.setLatestData(true); - subsetXml.setTime(timeXml); + this.timingTabControls.populate(timeXml, dataSet); // Area AreaXML area = new AreaXML(); @@ -911,7 +882,8 @@ public abstract class SubsetManagerDlg levelMap = new HashMap(); @@ -938,17 +910,20 @@ public abstract class SubsetManagerDlg selectedLevelIndices = levels + .getSelectedLevelIndices(); + for (int index : selectedLevelIndices) { + v.addLevel(String.valueOf(levels.getLevel() .get(index))); } } } } - for (VerticalXML v : levelMap.values()) { - subsetXml.addVertical(v); - } + ArrayList vertList = new ArrayList( + levelMap.values()); + vTab.populate(vertList, dataSet); } /** @@ -956,25 +931,22 @@ public abstract class SubsetManagerDlg vertList, DataSet dataSet) { + public void populate(List vertList, DataSet dataSet) { this.dataSet = dataSet; createExpandBarItems(); diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/presenter/GriddedTimingSelectionPresenter.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/presenter/GriddedTimingSelectionPresenter.java index 29cefc9159..e7ab74b795 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/presenter/GriddedTimingSelectionPresenter.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/presenter/GriddedTimingSelectionPresenter.java @@ -19,8 +19,8 @@ **/ package com.raytheon.uf.viz.datadelivery.subscription.subset.presenter; -import java.util.ArrayList; -import java.util.Collections; +import static com.raytheon.uf.viz.datadelivery.utils.DataDeliveryUtils.getMaxLatency; + import java.util.List; import com.google.common.annotations.VisibleForTesting; @@ -44,6 +44,7 @@ import com.raytheon.viz.ui.presenter.components.ListConf; * Sep 27, 2012 1202 bgonzale Set selectionDate to date and cycle. * Oct 11, 2012 1263 jpiatt Modified for cancel flag. * Jan 04, 2013 1420 mpduff Add the dataset object. + * Jan 22, 2013 1519 djohnson Use DataDeliveryUtils.getMaxLatency(). * * * @@ -173,7 +174,7 @@ public class GriddedTimingSelectionPresenter { } DataDeliveryGUIUtils.latencyValidChk(view.getLatency(), - getMaxLatency()); + getMaxLatency(dataSet)); // parse off the date/cycle time selected String[] parts = selection.split(" - "); @@ -188,29 +189,6 @@ public class GriddedTimingSelectionPresenter { return true; } - /** - * Max latency value in minutes. - * - * @return - */ - private int getMaxLatency() { - List cycleList = new ArrayList(dataSet.getCycles()); - Collections.sort(cycleList); - - int max = 0; - - for (int i = 0; i < cycleList.size(); i++) { - if (i + 1 <= cycleList.size()) { - int tempMax = cycleList.get(i + 1) - cycleList.get(i); - if (tempMax > max) { - max = tempMax; - } - } - } - - return max * 60; - } - /** * This method is called via the "Use Latest Data" checkbox being * selected/unselected. diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/presenter/IGriddedTimingSelectionDlgView.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/presenter/IGriddedTimingSelectionDlgView.java index 6d1dd48a5f..7b5670d2a2 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/presenter/IGriddedTimingSelectionDlgView.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/presenter/IGriddedTimingSelectionDlgView.java @@ -19,6 +19,7 @@ **/ package com.raytheon.uf.viz.datadelivery.subscription.subset.presenter; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.viz.ui.presenter.IPresenterView; import com.raytheon.viz.ui.presenter.components.ButtonConf; import com.raytheon.viz.ui.presenter.components.CheckBoxConf; @@ -119,9 +120,9 @@ public interface IGriddedTimingSelectionDlgView extends IPresenterView { int getLatency(); /** - * Get the priority value. + * Get the priority. * - * @return priority value + * @return priority */ - int getPriority(); + SubscriptionPriority getPriority(); } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/xml/SubsetXML.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/xml/SubsetXML.java index bc23703671..afd773276f 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/xml/SubsetXML.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/subset/xml/SubsetXML.java @@ -29,6 +29,7 @@ import javax.xml.bind.annotation.XmlElements; import javax.xml.bind.annotation.XmlRootElement; import com.raytheon.edex.util.Util; +import com.raytheon.uf.common.datadelivery.registry.Ensemble; import com.raytheon.uf.viz.datadelivery.common.xml.AreaXML; import com.raytheon.uf.viz.datadelivery.common.xml.IDisplayXml; @@ -65,6 +66,9 @@ public class SubsetXML implements IDisplayXml { @XmlElement(name = "area", type = AreaXML.class) protected AreaXML area; + + @XmlElement + protected Ensemble ensemble; @XmlElements({ @XmlElement(name = "vertical", type = VerticalXML.class) }) protected ArrayList verticalList = new ArrayList(); @@ -86,6 +90,21 @@ public class SubsetXML implements IDisplayXml { this.subsetName = subsetName; } + /** + * @return the ensemble + */ + public Ensemble getEnsemble() { + return ensemble; + } + + /** + * @param ensemble + * the ensemble to set + */ + public void setEnsemble(Ensemble ensemble) { + this.ensemble = ensemble; + } + /** * @return the area */ diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/view/ICreateSubscriptionDlgView.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/view/ICreateSubscriptionDlgView.java index 8787035a5b..ce32c9c679 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/view/ICreateSubscriptionDlgView.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/view/ICreateSubscriptionDlgView.java @@ -26,6 +26,7 @@ import java.util.Set; import org.eclipse.swt.widgets.Shell; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.viz.ui.presenter.IPresenterView; import com.raytheon.viz.ui.presenter.components.ButtonConf; import com.raytheon.viz.ui.presenter.components.CheckBoxConf; @@ -44,6 +45,7 @@ import com.raytheon.viz.ui.presenter.components.ComboBoxConf; * Dec 13, 2012 1391 bgonzale Added status methods. * Jan 02, 2013 1441 djohnson Add isGroupSelected. * Jan 04, 2013 1420 mpduff Added getters for latency and priority. + * Jan 25, 2013 1528 djohnson Subscription priority is now an enum. * * * @@ -210,14 +212,14 @@ public interface ICreateSubscriptionDlgView extends IPresenterView { * * @return */ - int getPriority(); + SubscriptionPriority getPriority(); /** * Set the priority selection * - * @param i + * @param subscriptionPriority */ - void setPriority(int i); + void setPriority(SubscriptionPriority subscriptionPriority); /** * Open the dialog @@ -406,13 +408,6 @@ public interface ICreateSubscriptionDlgView extends IPresenterView { */ int getLatencyValue(); - /** - * Get the priority value. - * - * @return - */ - int getPriorityValue(); - /** * Set Subscription. * diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/OperatorAdapter.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/OperatorAdapter.java index f30006ca1c..8130e8536d 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/OperatorAdapter.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/OperatorAdapter.java @@ -19,8 +19,12 @@ **/ package com.raytheon.uf.viz.datadelivery.subscription.xml; +import java.util.Collections; +import java.util.Map; + import javax.xml.bind.annotation.adapters.XmlAdapter; +import com.google.common.collect.Maps; import com.raytheon.uf.viz.datadelivery.system.Operator; import com.raytheon.uf.viz.datadelivery.system.OperatorTypes; import com.raytheon.uf.viz.datadelivery.utils.NameOperationItems; @@ -35,7 +39,8 @@ import com.raytheon.uf.viz.datadelivery.utils.TypeOperationItems; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Jan 7, 2013 1420 mpduff Initial creation. + * Jan 07, 2013 1420 mpduff Initial creation. + * Jan 14, 2013 1286 djohnson Add static versions of the conversion methods. * * * @@ -44,32 +49,61 @@ import com.raytheon.uf.viz.datadelivery.utils.TypeOperationItems; */ public class OperatorAdapter extends XmlAdapter> { - @Override - public Operator unmarshal(String v) throws Exception { - for (OperatorTypes ot : OperatorTypes.values()) { - if (ot.toString().equals(v)) { - return ot; - } - } - for (NameOperationItems noi : NameOperationItems.values()) { - if (noi.toString().equals(v)) { - return noi; - } + private static final Map> OPERATOR_MAP; + static { + Map> map = Maps.newHashMap(); + for (Operator operator : NameOperationItems.values()) { + map.put(toString(operator), operator); } - - for (TypeOperationItems toi : TypeOperationItems.values()) { - if (toi.toString().equals(v)) { - return toi; - } + for (Operator operator : OperatorTypes.values()) { + map.put(toString(operator), operator); } - - return null; + for (Operator operator : TypeOperationItems.values()) { + map.put(toString(operator), operator); + } + OPERATOR_MAP = Collections.unmodifiableMap(map); } + /** + * + * {@inheritDoc} + */ + @Override + public Operator unmarshal(String v) throws Exception { + return fromString(v); + } + + /** + * + * {@inheritDoc} + */ @Override public String marshal(Operator v) throws Exception { - return v.toString(); + return toString(v); + } + + /** + * Retrieve an {@link Operator} from its {@link String} representation. + * + * @param asString + * the string representation + * @return + */ + public static Operator fromString(String asString) { + return OPERATOR_MAP.get(asString); + } + + /** + * Retrieve the {@link String} representation of an {@link Operator} + * instance. + * + * @param operator + * the operator + * @return the {@link String} representation + */ + public static String toString(Operator operator) { + return operator.toString(); } } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/PriorityRuleXML.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/PriorityRuleXML.java index 542d7efa88..f420df3ac7 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/PriorityRuleXML.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/PriorityRuleXML.java @@ -24,6 +24,8 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; + /** * Priority rule xml object. * @@ -34,6 +36,7 @@ import javax.xml.bind.annotation.XmlRootElement; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Dec 19, 2012 1420 mpduff Initial creation. + * Jan 25, 2013 1528 djohnson Subscription priority is now an enum. * * * @@ -44,20 +47,20 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class PriorityRuleXML extends RuleXML { @XmlElement(name = "priority") - private Integer priority; + private SubscriptionPriority priority; /** * @param priority * the priority to set */ - public void setPriority(Integer priority) { + public void setPriority(SubscriptionPriority priority) { this.priority = priority; } /** * @return the priority */ - public Integer getPriority() { + public SubscriptionPriority getPriority() { return priority; } } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/RuleXML.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/RuleXML.java index 767178c76a..8ee0d441a1 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/RuleXML.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/xml/RuleXML.java @@ -27,12 +27,10 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import com.raytheon.uf.common.datadelivery.registry.Subscription; -import com.raytheon.uf.common.status.IUFStatusHandler; -import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.units.DataSizeUnit; +import com.raytheon.uf.viz.datadelivery.system.CreateEditRuleDlg.FreqUnitOptions; import com.raytheon.uf.viz.datadelivery.system.Operator; import com.raytheon.uf.viz.datadelivery.system.OpsNetFieldNames; -import com.raytheon.uf.viz.datadelivery.utils.DataSizeUnit; /** * Parent Rules xml class @@ -44,6 +42,8 @@ import com.raytheon.uf.viz.datadelivery.utils.DataSizeUnit; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Dec 19, 2012 1420 mpduff Initial creation. + * Jan 14, 2013 1286 djohnson Correct string conversion of units and use {@link Operator}. + * Jan 17, 2013 1357 mpduff Moved DataSizeUnit. * * * @@ -53,11 +53,6 @@ import com.raytheon.uf.viz.datadelivery.utils.DataSizeUnit; @SuppressWarnings({ "unchecked", "rawtypes" }) @XmlAccessorType(XmlAccessType.NONE) public abstract class RuleXML { - - /** Status Handler */ - private final IUFStatusHandler statusHandler = UFStatus - .getHandler(RuleXML.class); - /** Rule name */ @XmlElement protected String ruleName; @@ -68,7 +63,7 @@ public abstract class RuleXML { /** Rule operator */ @XmlElement - protected String ruleOperator; + protected Operator ruleOperator; /** Rule value */ @XmlElement @@ -121,7 +116,7 @@ public abstract class RuleXML { * * @return the ruleOperator */ - public String getRuleOperator() { + public Operator getRuleOperator() { return ruleOperator; } @@ -131,7 +126,7 @@ public abstract class RuleXML { * @param ruleOperator * The operator value of the rule */ - public void setRuleOperator(String ruleOperator) { + public void setRuleOperator(Operator ruleOperator) { this.ruleOperator = ruleOperator; } @@ -192,38 +187,29 @@ public abstract class RuleXML { unit = getRuleUnit(); } - OperatorAdapter oa = new OperatorAdapter(); - Operator oper = null; - try { - oper = oa.unmarshal(ruleOperator); - } catch (Exception e) { - statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e); - return false; - } - // If Data Name if (OpsNetFieldNames.NAME.toString().equals(ruleField)) { String dsName = sub.getDataSetName(); - return oper.evaluate(dsName, ruleValue); + return ruleOperator.evaluate(dsName, ruleValue); } // If Data Type if (OpsNetFieldNames.TYPE.toString().equals(ruleField)) { String dsType = sub.getDataSetType().toString(); - return oper.evaluate(ruleValue, dsType); + return ruleOperator.evaluate(ruleValue, dsType); } // If Data Size if (OpsNetFieldNames.SIZE.toString().equals(ruleField)) { long dsSizeKb = sub.getDataSetSize(); // Size in KB long ruleValueInt = Integer.parseInt(ruleValue); - DataSizeUnit dsUnit = DataSizeUnit.valueOf(unit); + DataSizeUnit dsUnit = DataSizeUnit.fromString(ruleUnit); ruleValueInt = dsUnit.toKB(ruleValueInt); - return oper.evaluate(Long.valueOf(dsSizeKb), + return ruleOperator.evaluate(Long.valueOf(dsSizeKb), Long.valueOf(ruleValueInt)); } @@ -231,7 +217,7 @@ public abstract class RuleXML { if (OpsNetFieldNames.FREQUENCY.toString().equals(ruleField)) { // Calculate frequency int ruleValueInt = Integer.parseInt(this.ruleValue); - if (unit.equalsIgnoreCase("Mins")) { + if (FreqUnitOptions.MIN.getOperation().equalsIgnoreCase(unit)) { ruleValueInt /= 60; } int freq = 0; @@ -246,7 +232,8 @@ public abstract class RuleXML { freq = val - tmp; } - if (oper.evaluate(Long.valueOf(freq), Long.valueOf(ruleValueInt))) { + if (ruleOperator.evaluate(Long.valueOf(freq), + Long.valueOf(ruleValueInt))) { return true; } } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/CreateEditRuleDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/CreateEditRuleDlg.java index 6afc805872..228c42ea07 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/CreateEditRuleDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/CreateEditRuleDlg.java @@ -19,6 +19,7 @@ **/ package com.raytheon.uf.viz.datadelivery.system; +import java.util.List; import java.util.regex.Pattern; import org.eclipse.swt.SWT; @@ -35,15 +36,16 @@ import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.units.DataSizeUnit; import com.raytheon.uf.viz.datadelivery.subscription.xml.LatencyRuleXML; +import com.raytheon.uf.viz.datadelivery.subscription.xml.OperatorAdapter; import com.raytheon.uf.viz.datadelivery.subscription.xml.PriorityRuleXML; import com.raytheon.uf.viz.datadelivery.subscription.xml.RuleXML; import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils; -import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryGUIUtils.SubscriptionPriority; import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryUtils; -import com.raytheon.uf.viz.datadelivery.utils.DataSizeUnit; import com.raytheon.uf.viz.datadelivery.utils.NameOperationItems; import com.raytheon.uf.viz.datadelivery.utils.TypeOperationItems; import com.raytheon.viz.ui.dialogs.CaveSWTDialog; @@ -65,6 +67,9 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog; * Dec 18, 2012 1417 bgonzale Changed value initialization in handleSave(). * Jan 04, 2013 1420 mpduff Remove code to apply rules changes to existing subscription, * rules are only for future subscriptions. + * Jan 14, 2013 1286 djohnson Rule operators are now used as objects. + * Jan 17, 2013 1357 mpduff Moved DataSizeUnit. + * Jan 25, 2013 1528 djohnson Subscription priority is now an enum. * * * @@ -225,6 +230,9 @@ public class CreateEditRuleDlg extends CaveSWTDialog { this(parent, create, null, ruleType); } + /** + * Create the rule header. + */ private void createRuleHeader() { if (create) { if (PRIORITY_TYPE.equals(ruleType)) { @@ -267,9 +275,9 @@ public class CreateEditRuleDlg extends CaveSWTDialog { protected void initializeComponents(Shell shell) { if (!create) { if (PRIORITY_TYPE.equals(ruleType)) { - ruleXml = srm.loadPriorityRule(ruleName); + ruleXml = srm.getPriorityRule(ruleName); } else { - ruleXml = srm.loadLatencyRule(ruleName); + ruleXml = srm.getLatencyRule(ruleName); } if (DATASET_SIZE.equals(ruleXml.getRuleField())) { @@ -409,7 +417,6 @@ public class CreateEditRuleDlg extends CaveSWTDialog { String item = fieldCombo.getItem(index); updateSelectionFields(item); } - }); OpsNetFieldNames[] fieldItems = OpsNetFieldNames.values(); @@ -448,7 +455,6 @@ public class CreateEditRuleDlg extends CaveSWTDialog { createFreqUnitItems(); } unitsCombo.select(0); - } if (PRIORITY_TYPE.equals(ruleType)) { @@ -479,7 +485,6 @@ public class CreateEditRuleDlg extends CaveSWTDialog { } priorityCombo.select(0); - } else { gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false); gl = new GridLayout(3, false); @@ -505,19 +510,16 @@ public class CreateEditRuleDlg extends CaveSWTDialog { Label minutesLbl = new Label(latencySelectionComp, SWT.NONE); minutesLbl.setLayoutData(gd); minutesLbl.setText("Minutes"); - } populateFields(); ruleDefinitionGroup.pack(); - } /** * Upon edit, populate the fields. */ private void populateFields() { - if (!create) { String field = ruleXml.getRuleField(); if (!field.isEmpty()) { @@ -528,8 +530,8 @@ public class CreateEditRuleDlg extends CaveSWTDialog { updateSelectionFields(field); - String operator = ruleXml.getRuleOperator(); - operationCombo.select(operationCombo.indexOf(operator)); + operationCombo.select(operationCombo.indexOf(OperatorAdapter + .toString(ruleXml.getRuleOperator()))); String value = ruleXml.getRuleValue(); if (!value.isEmpty()) { @@ -542,17 +544,17 @@ public class CreateEditRuleDlg extends CaveSWTDialog { } if (PRIORITY_TYPE.equals(ruleType)) { - Integer priority = ((PriorityRuleXML) ruleXml).getPriority(); + SubscriptionPriority priority = ((PriorityRuleXML) ruleXml) + .getPriority(); - int o = 0; SubscriptionPriority[] priorityOptions = SubscriptionPriority .values(); for (SubscriptionPriority item : priorityOptions) { - if (priority == item.getPriorityValue()) { - priorityCombo.select(o); + if (priority == item) { + priorityCombo.select(priorityCombo.indexOf(priority + .getPriorityName())); break; } - o++; } } else { Integer latency = ((LatencyRuleXML) ruleXml).getLatency(); @@ -600,7 +602,6 @@ public class CreateEditRuleDlg extends CaveSWTDialog { close(); } }); - } /** @@ -646,8 +647,15 @@ public class CreateEditRuleDlg extends CaveSWTDialog { boolean valid = false; String fieldName = fieldCombo.getItem(fieldCombo.getSelectionIndex()); - String operator = operationCombo.getItem(operationCombo - .getSelectionIndex()); + Operator operator = OperatorAdapter.fromString(operationCombo + .getItem(operationCombo.getSelectionIndex())); + + List ruleNames = null; + if (PRIORITY_TYPE.equals(ruleType)) { + ruleNames = srm.getPriorityRuleNames(); + } else { + ruleNames = srm.getLatencyRuleNames(); + } if (create) { valid = DataDeliveryGUIUtils.hasText(ruleNameText); @@ -661,13 +669,29 @@ public class CreateEditRuleDlg extends CaveSWTDialog { } ruleName = ruleNameText.getText(); + + if (INVALID_PATTERN.matcher(ruleName.trim()).find()) { + DataDeliveryUtils.showMessage(getShell(), SWT.ERROR, + INVALID_CHARS_TITLE, INVALID_CHARS_MESSAGE); + return false; + } + + // Check for duplicate rule name + if (ruleNames.contains(ruleName)) { + DataDeliveryUtils + .showMessage( + shell, + SWT.ERROR, + "Duplicate Rule", + "A rule titled " + + ruleName + + " already exists.\n\nPlease select a different name."); + ruleNameText.selectAll(); + + return false; + } } - if (INVALID_PATTERN.matcher(ruleName.trim()).find()) { - DataDeliveryUtils.showMessage(getShell(), SWT.ERROR, - INVALID_CHARS_TITLE, INVALID_CHARS_MESSAGE); - return false; - } String value = null; if (DataDeliveryGUIUtils.hasText(ruleValue)) { value = ruleValue.getText(); @@ -709,12 +733,11 @@ public class CreateEditRuleDlg extends CaveSWTDialog { if (PRIORITY_TYPE.equals(ruleType)) { PriorityRuleXML rule = new PriorityRuleXML(); - priorityVal = SubscriptionPriority.valueOf(priorityCombo.getText() - .toUpperCase()); + priorityVal = SubscriptionPriority.fromPriorityName(priorityCombo + .getText()); for (SubscriptionPriority pri : SubscriptionPriority.values()) { if (pri.equals(priorityVal)) { - priority = pri.getPriorityValue(); - (rule).setPriority(priority); + rule.setPriority(pri); break; } } @@ -768,21 +791,12 @@ public class CreateEditRuleDlg extends CaveSWTDialog { } setReturnValue(saved); - - if (!saved) { - DataDeliveryUtils - .showMessage( - getShell(), - SWT.OK, - "Duplicate Name", - "A rule named " - + ruleName - + " already exists\n\nPlease select a different name."); - ruleNameText.selectAll(); - } return saved; } + /** + * Populate the units combo. + */ private void createSizeUnitItems() { unitsCombo.removeAll(); DataSizeUnit[] sizeUnits = DataSizeUnit.values(); @@ -791,6 +805,9 @@ public class CreateEditRuleDlg extends CaveSWTDialog { } } + /** + * Populate the operation combo. + */ private void createSizeOpItems() { operationCombo.removeAll(); OperatorTypes[] sizeOps = OperatorTypes.values(); @@ -799,6 +816,9 @@ public class CreateEditRuleDlg extends CaveSWTDialog { } } + /** + * Populate the frequency units combo. + */ private void createFreqUnitItems() { FreqUnitOptions[] freqUnits = FreqUnitOptions.values(); for (FreqUnitOptions fuo : freqUnits) { @@ -806,6 +826,9 @@ public class CreateEditRuleDlg extends CaveSWTDialog { } } + /** + * populate the operation combo. + */ private void createNameOpItems() { operationCombo.removeAll(); NameOperationItems[] nameOperation = NameOperationItems.values(); diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/DataViewUtils.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/IRulesUpdateListener.java similarity index 66% rename from edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/DataViewUtils.java rename to cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/IRulesUpdateListener.java index a9566df815..f393c815b7 100644 --- a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/DataViewUtils.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/IRulesUpdateListener.java @@ -1,54 +1,44 @@ /** * This software was developed and / or modified by Raytheon Company, * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * + * * U.S. EXPORT CONTROLLED TECHNICAL DATA * This software product contains export-restricted data whose * export/transfer/disclosure is restricted by U.S. law. Dissemination * to non-U.S. persons whether in the United States or abroad requires * an export license or other authorization. - * + * * Contractor Name: Raytheon Company * Contractor Address: 6825 Pine Street, Suite 340 * Mail Stop B8 * Omaha, NE 68106 * 402.291.0100 - * + * * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.stats.util; +package com.raytheon.uf.viz.datadelivery.system; /** - * TODO Add Description - * + * Rules file update notifier interface. + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Nov 27, 2012            mpduff     Initial creation
- *
+ * Jan 16, 2013   1420     mpduff      Initial creation
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ -public class DataViewUtils { - public enum DataView { - AVG("Average"), MIN("Minimum"), MAX("Maximum"), - SUM("Sum"), COUNT("Count"); - - private final String view; - - private DataView(String view) { - this.view = view; - } - - public String getView() { - return view; - } - } +public interface IRulesUpdateListener { + /** + * Update rules. + */ + void update(); } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/Operator.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/Operator.java index 24a18be939..b365c06110 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/Operator.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/Operator.java @@ -19,6 +19,10 @@ **/ package com.raytheon.uf.viz.datadelivery.system; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import com.raytheon.uf.viz.datadelivery.subscription.xml.OperatorAdapter; + /** * Operator interface. * @@ -28,14 +32,15 @@ package com.raytheon.uf.viz.datadelivery.system; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Jan 7, 2013 mpduff Initial creation + * Jan 07, 2013 mpduff Initial creation + * Jan 14, 2013 djohnson Specify JAXB adapter on the interface. * * * * @author mpduff * @version 1.0 */ - +@XmlJavaTypeAdapter(value = OperatorAdapter.class) public interface Operator { /** * Evaluate whether the operator would return true when comparing operandOne diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemLatencyTab.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemLatencyTab.java index c5a8aa5fa0..1e2a94f8b6 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemLatencyTab.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemLatencyTab.java @@ -52,6 +52,7 @@ import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryUtils; * Sep 17, 2012 730 jpiatt Initial creation. * Oct 03, 2012 1241 djohnson Use {@link DataDeliveryPermission} and registry handlers. * Jan 04, 2012 1420 mpduff Add delete rule function. + * Jan 14, 2013 1286 djohnson Rule list is single item selectable. * * * @@ -134,7 +135,7 @@ public class SystemLatencyTab { gd.heightHint = 200; latencyList = new List(latencyComp, SWT.BORDER | SWT.MULTI - | SWT.V_SCROLL | SWT.H_SCROLL); + | SWT.V_SCROLL | SWT.H_SCROLL | SWT.SINGLE); latencyList.setLayoutData(gd); latencyList.addSelectionListener(new SelectionAdapter() { @Override @@ -262,10 +263,7 @@ public class SystemLatencyTab { ruleDlg = new CreateEditRuleDlg(parentComp.getShell(), create, ruleName, LATENCY_TYPE); } - boolean reloadFlag = (Boolean) ruleDlg.open(); - if (reloadFlag) { - loadList(); - } + ruleDlg.open(); } else { ruleDlg.bringToTop(); } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemManagementDlg.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemManagementDlg.java index 441f9eb9fa..bd45484a53 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemManagementDlg.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemManagementDlg.java @@ -45,6 +45,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.util.StringUtil; +import com.raytheon.uf.viz.core.VizApp; import com.raytheon.uf.viz.datadelivery.subscription.SubscriptionService.ForceApplyPromptResponse; import com.raytheon.uf.viz.datadelivery.subscription.SubscriptionService.IForceApplyPromptDisplayText; import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryUtils; @@ -64,6 +65,8 @@ import com.raytheon.viz.ui.presenter.IDisplay; * Oct 23, 2012 1286 djohnson Hook into bandwidth management. * Nov 20, 2012 1286 djohnson Implement IDisplay. * Jan 04, 2013 1420 mpduff Remove applying of rules. + * Jan 17, 2013 1501 djohnson Close the dialog when force apply occurs, + * and check whether changes have already been applied when OK is pressed. * * * @@ -71,7 +74,7 @@ import com.raytheon.viz.ui.presenter.IDisplay; * @version 1.0 */ public class SystemManagementDlg extends CaveSWTDialog implements IDisplay, - IForceApplyPromptDisplayText { + IForceApplyPromptDisplayText, IRulesUpdateListener { /** Status Handler */ private final IUFStatusHandler statusHandler = UFStatus @@ -128,10 +131,18 @@ public class SystemManagementDlg extends CaveSWTDialog implements IDisplay, /** OK button */ private Button okBtn; + /** Available bandwidth modified flag */ private boolean availableBandwidthModified; + /** Available bandwidth spinner widget */ private Spinner availBandwidthSpinner; + /** The system latency tab */ + private SystemLatencyTab lTab; + + /** The system priority tab */ + private SystemPriorityTab pTab; + /** * Constructor. * @@ -141,6 +152,7 @@ public class SystemManagementDlg extends CaveSWTDialog implements IDisplay, public SystemManagementDlg(Shell parent) { super(parent, SWT.DIALOG_TRIM, CAVE.NONE); setText("Data Delivery System Management"); + SystemRuleManager.getInstance().registerAsListener(this); } @@ -181,6 +193,17 @@ public class SystemManagementDlg extends CaveSWTDialog implements IDisplay, } + /* + * (non-Javadoc) + * + * @see com.raytheon.viz.ui.dialogs.CaveSWTDialogBase#disposed() + */ + @Override + protected void disposed() { + super.disposed(); + SystemRuleManager.getInstance().deregisterAsListener(this); + } + /** * Create top bar route information. */ @@ -283,7 +306,7 @@ public class SystemManagementDlg extends CaveSWTDialog implements IDisplay, priorityComp.setLayout(gl); priorityComp.setLayoutData(gd); priorityTab.setControl(priorityComp); - SystemPriorityTab pTab = new SystemPriorityTab(priorityComp); + pTab = new SystemPriorityTab(priorityComp); gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false); gl = new GridLayout(1, false); @@ -296,7 +319,7 @@ public class SystemManagementDlg extends CaveSWTDialog implements IDisplay, latencyComp.setLayout(gl); latencyComp.setLayoutData(gd); latencyTab.setControl(latencyComp); - SystemLatencyTab lTab = new SystemLatencyTab(latencyComp); + lTab = new SystemLatencyTab(latencyComp); gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false); gl = new GridLayout(1, false); @@ -309,6 +332,9 @@ public class SystemManagementDlg extends CaveSWTDialog implements IDisplay, routingComp.setLayoutData(gd); routingTab.setControl(routingComp); SystemRoutingTab rTab = new SystemRoutingTab(routingComp); + + lTab.loadList(); + pTab.loadList(); } /** @@ -413,21 +439,26 @@ public class SystemManagementDlg extends CaveSWTDialog implements IDisplay, sb.append("Would you like to change the bandwidth anyways?."); int response = DataDeliveryUtils.showMessage(getShell(), SWT.YES | SWT.NO, "Bandwidth Amount", sb.toString()); + boolean forceApplied = false; if (response == SWT.YES) { - boolean forceApplied = SystemRuleManager + forceApplied = SystemRuleManager .forceSetAvailableBandwidth(Network.OPSNET, bandwidth); - if (!forceApplied) { + if (forceApplied) { + availableBandwidthModified = false; + } else { statusHandler .handle(Priority.ERROR, "Bandwidth Change", "Unable to change the bandwidth for network " + Network.OPSNET + ". Please check the server for details."); - return false; + } } - return false; + return forceApplied; + } else { + availableBandwidthModified = false; } } @@ -466,4 +497,17 @@ public class SystemManagementDlg extends CaveSWTDialog implements IDisplay, "Don't know how to handle option [" + option + "]"); } } + + @Override + public void update() { + VizApp.runAsync(new Runnable() { + @Override + public void run() { + if (!shell.isDisposed()) { + lTab.loadList(); + pTab.loadList(); + } + } + }); + } } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemPriorityTab.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemPriorityTab.java index f39ce7daae..1d4635fd11 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemPriorityTab.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemPriorityTab.java @@ -268,10 +268,7 @@ public class SystemPriorityTab { create, ruleName, PRIORITY_TYPE); } - boolean reloadFlag = (Boolean) ruleDlg.open(); - if (reloadFlag) { - loadList(); - } + ruleDlg.open(); } else { ruleDlg.bringToTop(); } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemRuleManager.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemRuleManager.java index 5f1dc81a0b..66b08a0e95 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemRuleManager.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/system/SystemRuleManager.java @@ -32,6 +32,9 @@ import javax.xml.bind.Unmarshaller; import com.raytheon.uf.common.datadelivery.bandwidth.IBandwidthService; import com.raytheon.uf.common.datadelivery.registry.Network; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; +import com.raytheon.uf.common.localization.FileUpdatedMessage; +import com.raytheon.uf.common.localization.ILocalizationFileObserver; import com.raytheon.uf.common.localization.IPathManager; import com.raytheon.uf.common.localization.LocalizationContext; import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel; @@ -64,6 +67,7 @@ import com.raytheon.uf.viz.datadelivery.utils.TypeOperationItems; * Sep 17, 2012 730 jpiatt Initial creation. * Oct 23, 2012 1286 djohnson Hook into bandwidth management. * Jan 04, 2013 1420 mpduff Move rules into a single file. + * Jan 25, 2013 1528 djohnson Subscription priority is now an enum. * * * @@ -89,6 +93,12 @@ public class SystemRuleManager { private final IUFStatusHandler statusHandler = UFStatus .getHandler(SystemRuleManager.class); + /** Latency Rules Localization File */ + private LocalizationFile latencyRulesLocFile; + + /** Priority Rules Localization File */ + private LocalizationFile priorityRulesLocFile; + /** JAXB context */ private JAXBContext jax; @@ -101,11 +111,21 @@ public class SystemRuleManager { /** Bandwidth service */ private IBandwidthService bandwidthService; + /** Latency Rules XML object */ + private LatencyRulesXML latencyRules; + + /** Priority Rules XML object */ + private PriorityRulesXML priorityRules; + + private final List listeners = new ArrayList(); + /** * Constructor. */ private SystemRuleManager() { createContext(); + loadLatencyRules(); + loadPriorityRules(); } /** @@ -144,7 +164,7 @@ public class SystemRuleManager { * @throws JAXBException */ public List getPriorityRuleNames() { - return getPriorityRules().getRuleNames(); + return getPriorityRules(false).getRuleNames(); } /** @@ -154,8 +174,8 @@ public class SystemRuleManager { * the name of the rule * @return the PriorityRuleXML object */ - public PriorityRuleXML loadPriorityRule(String name) { - PriorityRulesXML priorityRules = getPriorityRules(); + public PriorityRuleXML getPriorityRule(String name) { + PriorityRulesXML priorityRules = getPriorityRules(false); for (PriorityRuleXML rule : priorityRules.getRules()) { if (rule.getRuleName().equals(name)) { return rule; @@ -172,8 +192,8 @@ public class SystemRuleManager { * the name of the rule * @return the LatencyRuleXML object */ - public LatencyRuleXML loadLatencyRule(String name) { - LatencyRulesXML latencyRules = getLatencyRules(); + public LatencyRuleXML getLatencyRule(String name) { + LatencyRulesXML latencyRules = getLatencyRules(false); for (LatencyRuleXML rule : latencyRules.getRules()) { if (rule.getRuleName().equals(name)) { return rule; @@ -190,7 +210,7 @@ public class SystemRuleManager { * @throws JAXBException */ public List getLatencyRuleNames() { - return getLatencyRules().getRuleNames(); + return getLatencyRules(false).getRuleNames(); } /** @@ -203,15 +223,22 @@ public class SystemRuleManager { public boolean savePriorityRules(PriorityRulesXML xmlObj) { IPathManager pm = PathManagerFactory.getPathManager(); - LocalizationContext context = pm.getContext( - LocalizationType.COMMON_STATIC, LocalizationLevel.SITE); - LocalizationFile priorityRulesLocFile = pm.getLocalizationFile(context, - this.PRIORITY_RULE_FILE); - try { - marshaller.marshal(xmlObj, priorityRulesLocFile.getFile()); - priorityRulesLocFile.save(); - return true; + // If site, then write out, otherwise save it as site. + if (priorityRulesLocFile.getContext().getLocalizationLevel() + .equals(LocalizationLevel.SITE)) { + marshaller.marshal(xmlObj, priorityRulesLocFile.getFile()); + return priorityRulesLocFile.save(); + } else { + LocalizationContext context = pm.getContext( + LocalizationType.COMMON_STATIC, LocalizationLevel.SITE); + + priorityRulesLocFile = pm.getLocalizationFile(context, + this.PRIORITY_RULE_FILE); + addPriorityRulesFileObserver(); + marshaller.marshal(xmlObj, priorityRulesLocFile.getFile()); + return priorityRulesLocFile.save(); + } } catch (JAXBException e) { statusHandler.handle(Priority.ERROR, e.getLocalizedMessage(), e); } catch (LocalizationOpFailedException e) { @@ -231,15 +258,22 @@ public class SystemRuleManager { public boolean saveLatencyRules(LatencyRulesXML xmlObj) { IPathManager pm = PathManagerFactory.getPathManager(); - LocalizationContext context = pm.getContext( - LocalizationType.COMMON_STATIC, LocalizationLevel.SITE); - LocalizationFile latencyRulesLocFile = pm.getLocalizationFile(context, - this.LATENCY_RULE_FILE); - try { - marshaller.marshal(xmlObj, latencyRulesLocFile.getFile()); - latencyRulesLocFile.save(); - return true; + // If site, then write out, otherwise save it as site. + if (latencyRulesLocFile.getContext().getLocalizationLevel() + .equals(LocalizationLevel.SITE)) { + marshaller.marshal(xmlObj, latencyRulesLocFile.getFile()); + return latencyRulesLocFile.save(); + } else { + LocalizationContext context = pm.getContext( + LocalizationType.COMMON_STATIC, LocalizationLevel.SITE); + + latencyRulesLocFile = pm.getLocalizationFile(context, + this.LATENCY_RULE_FILE); + addLatencyRulesFileObserver(); + marshaller.marshal(xmlObj, latencyRulesLocFile.getFile()); + return latencyRulesLocFile.save(); + } } catch (JAXBException e) { statusHandler.handle(Priority.ERROR, e.getLocalizedMessage(), e); } catch (LocalizationOpFailedException e) { @@ -256,7 +290,7 @@ public class SystemRuleManager { * the rule name to delete */ public void deleteLatencyRule(String ruleName) { - LatencyRulesXML latencyRules = getLatencyRules(); + LatencyRulesXML latencyRules = getLatencyRules(false); for (LatencyRuleXML rule : latencyRules.getRules()) { if (rule.getRuleName().equals(ruleName)) { @@ -274,7 +308,7 @@ public class SystemRuleManager { * the rule name to delete */ public void deletePriorityRule(String ruleName) { - PriorityRulesXML priorityRules = getPriorityRules(); + PriorityRulesXML priorityRules = getPriorityRules(false); for (PriorityRuleXML rule : priorityRules.getRules()) { if (rule.getRuleName().equals(ruleName)) { @@ -293,7 +327,7 @@ public class SystemRuleManager { * @return true if updated */ public boolean updateRule(LatencyRuleXML rule) { - LatencyRulesXML rulesXml = getLatencyRules(); + LatencyRulesXML rulesXml = getLatencyRules(false); boolean saved = rulesXml.updateRule(rule); if (saved) { return saveLatencyRules(rulesXml); @@ -310,7 +344,7 @@ public class SystemRuleManager { * @return true if updated */ public boolean updateRule(PriorityRuleXML rule) { - PriorityRulesXML rulesXml = getPriorityRules(); + PriorityRulesXML rulesXml = getPriorityRules(false); boolean saved = rulesXml.updateRule(rule); if (saved) { saved = savePriorityRules(rulesXml); @@ -331,7 +365,7 @@ public class SystemRuleManager { * @return true if updated */ public boolean saveRule(PriorityRuleXML rule) { - PriorityRulesXML rulesXml = getPriorityRules(); + PriorityRulesXML rulesXml = getPriorityRules(false); boolean saved = rulesXml.addRule(rule); if (saved) { saved = savePriorityRules(rulesXml); @@ -352,7 +386,7 @@ public class SystemRuleManager { * @return true if updated */ public boolean saveRule(LatencyRuleXML rule) { - LatencyRulesXML rulesXml = getLatencyRules(); + LatencyRulesXML rulesXml = getLatencyRules(false); boolean saved = rulesXml.addRule(rule); if (saved) { saved = saveLatencyRules(rulesXml); @@ -368,19 +402,23 @@ public class SystemRuleManager { /** * Get the latency rules. * + * @param reread + * true to reread the file from disk + * * @return The latency rules xml object */ - private LatencyRulesXML getLatencyRules() { - LocalizationFile lfile = getRules(this.LATENCY_RULE_FILE); - - LatencyRulesXML latencyRules = new LatencyRulesXML(); - if (lfile != null && lfile.exists()) { - try { - latencyRules = (LatencyRulesXML) unmarshaller.unmarshal(lfile - .getFile()); - } catch (JAXBException e) { - statusHandler - .handle(Priority.ERROR, e.getLocalizedMessage(), e); + private LatencyRulesXML getLatencyRules(boolean reread) { + if (latencyRules == null || reread) { + if (this.latencyRulesLocFile != null + && latencyRulesLocFile.exists()) { + try { + latencyRules = (LatencyRulesXML) unmarshaller + .unmarshal(latencyRulesLocFile.getFile()); + } catch (JAXBException e) { + statusHandler.handle(Priority.ERROR, + e.getLocalizedMessage(), e); + latencyRules = new LatencyRulesXML(); + } } } @@ -390,34 +428,26 @@ public class SystemRuleManager { /** * Get the priority rules * + * @param reread + * true to reread the file from disk + * * @return The priority rules xml object */ - private PriorityRulesXML getPriorityRules() { - LocalizationFile lfile = getRules(this.PRIORITY_RULE_FILE); - - PriorityRulesXML priorityRules = new PriorityRulesXML(); - if (lfile != null && lfile.exists()) { - try { - priorityRules = (PriorityRulesXML) unmarshaller.unmarshal(lfile - .getFile()); - } catch (JAXBException e) { - statusHandler - .handle(Priority.ERROR, e.getLocalizedMessage(), e); + private PriorityRulesXML getPriorityRules(boolean reread) { + if (priorityRules == null || reread) + if (this.priorityRulesLocFile != null + && priorityRulesLocFile.exists()) { + try { + priorityRules = (PriorityRulesXML) unmarshaller + .unmarshal(priorityRulesLocFile.getFile()); + } catch (JAXBException e) { + statusHandler.handle(Priority.ERROR, + e.getLocalizedMessage(), e); + priorityRules = new PriorityRulesXML(); + } } - } - return priorityRules; - } - /** - * Get the rules files - * - * @param name - * Rules file name to get - * @return The localization file - */ - private LocalizationFile getRules(String name) { - IPathManager pm = PathManagerFactory.getPathManager(); - return pm.getStaticLocalizationFile(name); + return priorityRules; } /** @@ -442,7 +472,7 @@ public class SystemRuleManager { * @return */ public int getLatency(Subscription sub, Set cycleTimes) { - LatencyRulesXML rulesXml = this.getLatencyRules(); + LatencyRulesXML rulesXml = this.getLatencyRules(false); int latency = 999; boolean found = false; for (LatencyRuleXML rule : rulesXml.getRules()) { @@ -470,22 +500,23 @@ public class SystemRuleManager { * @param cycleTimes * @return */ - public int getPriority(Subscription sub, Set cycleTimes) { - PriorityRulesXML rulesXml = this.getPriorityRules(); - int priority = 3; - boolean found = false; + public SubscriptionPriority getPriority(Subscription sub, + Set cycleTimes) { + PriorityRulesXML rulesXml = this.getPriorityRules(false); + SubscriptionPriority priority = null; for (PriorityRuleXML rule : rulesXml.getRules()) { if (rule.matches(sub, cycleTimes)) { - if (rule.getPriority() < priority) { + if (priority == null + || rule.getPriority().getPriorityValue() < priority + .getPriorityValue()) { priority = rule.getPriority(); - found = true; } } } // Default to normal priority - if (!found) { - priority = 2; + if (priority == null) { + priority = SubscriptionPriority.NORMAL; } return priority; @@ -546,4 +577,87 @@ public class SystemRuleManager { return getInstance().bandwidthService .setBandwidthForNetworkInKilobytes(network, bandwidth); } + + /** + * Read the latency rules file. + */ + private void loadLatencyRules() { + IPathManager pm = PathManagerFactory.getPathManager(); + this.latencyRulesLocFile = pm + .getStaticLocalizationFile(this.LATENCY_RULE_FILE); + addLatencyRulesFileObserver(); + getLatencyRules(true); + } + + /** + * Load the priority rules file. + */ + private void loadPriorityRules() { + IPathManager pm = PathManagerFactory.getPathManager(); + this.priorityRulesLocFile = pm + .getStaticLocalizationFile(this.PRIORITY_RULE_FILE); + addPriorityRulesFileObserver(); + getPriorityRules(true); + } + + /** + * Add a file observer to the latency rules file to get notified when the + * file changes. + */ + private void addLatencyRulesFileObserver() { + latencyRulesLocFile + .addFileUpdatedObserver(new ILocalizationFileObserver() { + @Override + public void fileUpdated(FileUpdatedMessage message) { + loadLatencyRules(); + fireUpdates(); + } + }); + } + + /** + * Add a file observer to the priority rules file to get notified when the + * file changes. + */ + private void addPriorityRulesFileObserver() { + priorityRulesLocFile + .addFileUpdatedObserver(new ILocalizationFileObserver() { + @Override + public void fileUpdated(FileUpdatedMessage message) { + loadPriorityRules(); + fireUpdates(); + } + }); + } + + /** + * Notify the listeners the files changed. + */ + private void fireUpdates() { + for (IRulesUpdateListener listener : listeners) { + listener.update(); + } + } + + /** + * Register as a listener for rules file changes. + * + * @param listener + */ + public void registerAsListener(IRulesUpdateListener listener) { + if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + + /** + * Unregister as a listener for rules files changed. + * + * @param listener + */ + public void deregisterAsListener(IRulesUpdateListener listener) { + if (listeners.contains(listener)) { + listeners.remove(listener); + } + } } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryGUIUtils.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryGUIUtils.java index 516e1f0b59..0d0b1c6bed 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryGUIUtils.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryGUIUtils.java @@ -25,10 +25,7 @@ import java.util.Date; import java.util.TimeZone; import java.util.regex.Pattern; -import javax.xml.bind.annotation.XmlEnumValue; - import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; @@ -55,6 +52,7 @@ import com.raytheon.uf.viz.core.VizApp; * Dec 17, 2012 1435 mpduff Fix ThreadLocal implementation. * Dec 18, 2012 1439 mpduff Change Regex to match invalid chars. * Jan 04, 2013 1420 mpduff Change default priority to normal priority. + * Jan 25, 2013 1528 djohnson Subscription priority has moved up in the world to the Subscription class. * * * @@ -108,67 +106,6 @@ public class DataDeliveryGUIUtils { /** Name Required Message */ public static final String NAME_REQUIRED_MESSAGE = "Name required.\nA Subscription Name must be entered."; - /** Enumeration to use for subscription priorities */ - public static enum SubscriptionPriority { - /** High Priority */ - @XmlEnumValue("High") - HIGH("High", 1, new RGB(255, 0, 0)), - /** Default Priority */ - @XmlEnumValue("Normal") - NORMAL("Normal", 2, new RGB(0, 255, 0)), - /** Low Priority */ - @XmlEnumValue("Low") - LOW("Low", 3, new RGB(6, 122, 255)); - - /** Priority Setting */ - private final String priorityName; - - /** Numeric Value of the priority */ - private Integer priorityValue; - - /** Priority color for ui */ - private RGB color; - - private SubscriptionPriority(String priorityName, - Integer priorityValue, RGB color) { - this.priorityName = priorityName; - this.priorityValue = priorityValue; - this.color = color; - } - - /** - * Get column name. - * - * @return Priority Name - */ - public String getPriorityName() { - return priorityName; - } - - /** - * Get the integer value of the priority - * - * @return The integer value of the priority. - */ - public Integer getPriorityValue() { - return priorityValue; - } - - @Override - public String toString() { - return priorityName; - } - - /** - * Get the color. - * - * @return the color - */ - public RGB getColor() { - return color; - } - } - /** * Constructor. */ diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryUtils.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryUtils.java index 929c03c1ce..2dc2e22296 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryUtils.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryUtils.java @@ -32,6 +32,7 @@ import org.eclipse.swt.widgets.Shell; import com.raytheon.uf.common.datadelivery.registry.Coverage; import com.raytheon.uf.common.datadelivery.registry.DataLevelType; +import com.raytheon.uf.common.datadelivery.registry.GriddedDataSet; import com.raytheon.uf.common.datadelivery.registry.Parameter; import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.datadelivery.registry.Time; @@ -57,9 +58,11 @@ import com.vividsolutions.jts.geom.Coordinate; * Jul 25, 2012 955 djohnson Use List instead of ArrayList, thread-safe access to DecimalFormat. * Aug 29, 2012 223 mpduff Add cycles to the subscription details. * Oct 31, 2012 1278 mpduff Moved spatial methods to SpatialUtils. - * Nov 20, 2012 1286 djohnson Add showYesNoMessage. - * Dec 20, 2012 1413 bgonzale Added PendingSubColumnNames.valueOfColumnName(String). - * Jan 10, 2013 1420 mdpuff Added getMaxLatency(). + * Nov 20, 2012 1286 djohnson Add showYesNoMessage. + * Dec 20, 2012 1413 bgonzale Added PendingSubColumnNames.valueOfColumnName(String). + * Jan 10, 2013 1420 mdpuff Added getMaxLatency(). + * Jan 14, 2013 1286 djohnson Fix IndexOutOfBounds exception from getMaxLatency. + * Jan 22, 2013 1519 djohnson Correct getMaxLatency() calculations. * * * @author mpduff @@ -68,6 +71,18 @@ import com.vividsolutions.jts.geom.Coordinate; public class DataDeliveryUtils { + /** + * Default latency applied to hourly datasets. + */ + public static final int HOURLY_DATASET_LATENCY_IN_MINUTES = 40; + + /** + * Default latency applied non-hourly datasets. + */ + public static final int NON_HOURLY_DATASET_LATENCY_IN_MINUTES = 75; + + private static final int UNSET = -1; + /** Decimal format */ private final static ThreadLocal format = new ThreadLocal() { @@ -438,7 +453,8 @@ public class DataDeliveryUtils { .append(newline); fmtStr.append("Provider : ").append(sub.getProvider()).append(newline); fmtStr.append("Office ID: ").append(sub.getOfficeID()).append(newline); - fmtStr.append("Priority : ").append(sub.getPriority()).append(newline); + fmtStr.append("Priority : ") + .append(sub.getPriority().getPriorityValue()).append(newline); fmtStr.append("Coverage: ").append(newline); final Coverage coverage = sub.getCoverage(); @@ -550,18 +566,48 @@ public class DataDeliveryUtils { * @return the maximum latency in minutes */ public static int getMaxLatency(Subscription subscription) { - List cycles = subscription.getTime().getCycleTimes(); - Collections.sort(cycles); - int max = TimeUtil.HOURS_PER_DAY * TimeUtil.MINUTES_PER_HOUR; + return getMaxLatency(subscription.getTime().getCycleTimes()); + } - for (int i = 0; i < cycles.size(); i++) { - if (i + 1 <= cycles.size()) { - int tempMax = cycles.get(i + 1) - cycles.get(i); - if (tempMax > max) { - max = tempMax; - } + /** + * Get the maximum latency for the provided cycles. Calculated as the + * maximum cyclic difference. + * + * @param cycles + * The list of cycles + * @return the maximum latency in minutes + */ + public static int getMaxLatency(List cycles) { + Collections.sort(cycles); + int maximumTimeBetweenCycles = UNSET; + + final int size = cycles.size(); + for (int i = 0; i < size; i++) { + final int nextIndex = i + 1; + if (nextIndex < size) { + int tempMax = cycles.get(nextIndex) - cycles.get(i); + maximumTimeBetweenCycles = Math.max(maximumTimeBetweenCycles, tempMax); } } - return max; + + // If there was only one cycle, then default to the number of minutes in + // the day + if (maximumTimeBetweenCycles == UNSET) { + maximumTimeBetweenCycles = TimeUtil.HOURS_PER_DAY; + } + + return maximumTimeBetweenCycles * TimeUtil.MINUTES_PER_HOUR; + } + + /** + * Get the maximum latency for the provided dataSet. Calculated as the + * maximum cyclic difference. + * + * @param dataSet + * the dataset + * @return the maximum latency in minutes + */ + public static int getMaxLatency(GriddedDataSet dataSet) { + return getMaxLatency(new ArrayList(dataSet.getCycles())); } } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataSetFrequency.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataSetFrequency.java index e655eec99e..70d49d782c 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataSetFrequency.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataSetFrequency.java @@ -21,6 +21,8 @@ package com.raytheon.uf.viz.datadelivery.utils; import java.util.List; +import com.raytheon.uf.common.time.util.TimeUtil; + /** * Data Set Frequency Enumeration. * @@ -30,7 +32,8 @@ import java.util.List; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Jan 8, 2013 1420 mpduff Initial creation. + * Jan 08, 2013 1420 mpduff Initial creation. + * Jan 22, 2013 1519 djohnson Correct the non-hourly default latency to match requirements. * * * @@ -39,8 +42,11 @@ import java.util.List; */ public enum DataSetFrequency { - HOURLY(40), SIX_HOURLY(115), TWELVE_HOURLY(115), DAILY(115); - + HOURLY(DataDeliveryUtils.HOURLY_DATASET_LATENCY_IN_MINUTES), SIX_HOURLY( + DataDeliveryUtils.NON_HOURLY_DATASET_LATENCY_IN_MINUTES), TWELVE_HOURLY( + DataDeliveryUtils.NON_HOURLY_DATASET_LATENCY_IN_MINUTES), DAILY( + DataDeliveryUtils.NON_HOURLY_DATASET_LATENCY_IN_MINUTES); + private int defaultLatency; private DataSetFrequency(int defaultLatency) { @@ -49,13 +55,14 @@ public enum DataSetFrequency { public static DataSetFrequency fromCycleTimes(List cycleTimes) { if (cycleTimes.size() > 1) { - if ((cycleTimes.get(1) - cycleTimes.get(0)) == 1) { + final int hoursBetweenCycles = cycleTimes.get(1) - cycleTimes.get(0); + if (hoursBetweenCycles == 1) { return DataSetFrequency.HOURLY; - } else if ((cycleTimes.get(1) - cycleTimes.get(0)) == 6) { + } else if (hoursBetweenCycles == TimeUtil.HOURS_PER_QUARTER_DAY) { return DataSetFrequency.SIX_HOURLY; - } else if ((cycleTimes.get(1) - cycleTimes.get(0)) == 12) { + } else if (hoursBetweenCycles == TimeUtil.HOURS_PER_HALF_DAY) { return DataSetFrequency.TWELVE_HOURLY; - } else if ((cycleTimes.get(1) - cycleTimes.get(0)) == 24) { + } else if (hoursBetweenCycles == TimeUtil.HOURS_PER_DAY) { return DataSetFrequency.DAILY; } } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/NotificationHandler.java b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/NotificationHandler.java index 73d72c9391..2e1d7a5bfd 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/NotificationHandler.java +++ b/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/NotificationHandler.java @@ -9,13 +9,13 @@ import com.raytheon.uf.common.datadelivery.event.notification.DeleteNotification import com.raytheon.uf.common.datadelivery.event.notification.DeleteNotificationResponse; import com.raytheon.uf.common.datadelivery.event.notification.GetNotificationRequest; import com.raytheon.uf.common.datadelivery.event.notification.NotificationRecord; +import com.raytheon.uf.common.datadelivery.request.DataDeliveryConstants; +import com.raytheon.uf.common.serialization.comm.RequestRouter; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.notification.INotificationObserver; import com.raytheon.uf.viz.core.notification.NotificationException; import com.raytheon.uf.viz.core.notification.NotificationMessage; -import com.raytheon.uf.viz.core.requests.ThriftClient; import com.raytheon.uf.viz.datadelivery.notification.xml.MessageLoadXML; /** @@ -29,6 +29,7 @@ import com.raytheon.uf.viz.datadelivery.notification.xml.MessageLoadXML; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Mar 12, 2012 jsanchez Initial creation + * Jan 22, 2013 1501 djohnson Route requests to datadelivery. * * * @@ -115,10 +116,10 @@ public class NotificationHandler implements INotificationObserver { request.setUsername(username); request.setHours(hours); request.setMaxResults(maxResults); - ArrayList response = (ArrayList) ThriftClient - .sendRequest(request); + ArrayList response = (ArrayList) RequestRouter + .route(request, DataDeliveryConstants.DATA_DELIVERY_SERVER); return response; - } catch (VizException e) { + } catch (Exception e) { statusHandler.error( "Error trying to retrieve notifications from database", e); } @@ -139,10 +140,10 @@ public class NotificationHandler implements INotificationObserver { try { DeleteNotificationRequest request = new DeleteNotificationRequest(); request.setIds(ids); - DeleteNotificationResponse response = (DeleteNotificationResponse) ThriftClient - .sendRequest(request); + DeleteNotificationResponse response = (DeleteNotificationResponse) RequestRouter + .route(request, DataDeliveryConstants.DATA_DELIVERY_SERVER); rowsDeleted = response.getRowsDeleted(); - } catch (VizException e) { + } catch (Exception e) { statusHandler.error( "Error trying to delete notification(s) from database", e); } diff --git a/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/FFMPMonitor.java b/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/FFMPMonitor.java index 2f3aac8815..d6b222114a 100644 --- a/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/FFMPMonitor.java +++ b/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/FFMPMonitor.java @@ -28,6 +28,7 @@ import org.eclipse.ui.PlatformUI; import com.raytheon.uf.common.dataplugin.ffmp.FFMPBasin; import com.raytheon.uf.common.dataplugin.ffmp.FFMPBasinData; +import com.raytheon.uf.common.dataplugin.ffmp.FFMPAggregateRecord; import com.raytheon.uf.common.dataplugin.ffmp.FFMPCacheRecord; import com.raytheon.uf.common.dataplugin.ffmp.FFMPGuidanceBasin; import com.raytheon.uf.common.dataplugin.ffmp.FFMPGuidanceInterpolation; @@ -53,6 +54,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.viz.core.HDF5Util; import com.raytheon.uf.viz.core.VizApp; import com.raytheon.uf.viz.core.catalog.DirectDbQuery; @@ -88,6 +90,8 @@ import com.raytheon.uf.viz.monitor.listeners.IMonitorListener; * ------------ ---------- ----------- -------------------------- * 04/03/10 4494 D. Hladky Initial release * 12/07/12 1353 rferrel Changes for non-blocking FFMPSplash. + * 01/10/13 1475 D. Hladky Cleaned up some logging. + * 01/27/13 1478 D. Hladky revamped cache file format, removed duplicate times * * * @@ -473,28 +477,21 @@ public class FFMPMonitor extends ResourceMonitor { * @param siteKey * @param dataKey * @param source - * @param huc */ - public void insertFFMPData(FFMPBasinData data, String siteKey, - String source, String huc) { + public void insertFFMPData(FFMPAggregateRecord data, String siteKey, + String source) { - final String fsiteKey = siteKey; - final FFMPBasinData fdata = data; - final String fsource = source; - final String fhuc = huc; - - VizApp.runAsync(new Runnable() { - @Override - public void run() { - - if (ffmpData.containsKey(fsiteKey)) { - if (ffmpData.get(fsiteKey).containsKey(fsource)) { - ffmpData.get(fsiteKey).get(fsource) - .setBasinBuddyData(fdata, fhuc); - } + if (ffmpData.containsKey(siteKey)) { + if (ffmpData.get(siteKey).containsKey(source)) { + for (Entry entry : data.getBasinsMap() + .entrySet()) { + FFMPBasinData basinData = entry.getValue(); + basinData.populate(data.getTimes()); + ffmpData.get(siteKey).get(source) + .setCacheData(basinData, basinData.getHucLevel()); } } - }); + } } /** @@ -528,54 +525,35 @@ public class FFMPMonitor extends ResourceMonitor { public void populateFFMPBasin(String dataUri, String siteKey, String source, String phuc, FFMPBasin basin) throws VizException { - final String fdataUri = dataUri; - final String fsiteKey = siteKey; - final String fhuc = phuc; - final String fsource = source; - final FFMPBasin fbasin = basin; + if (dataUri != null) { + ConcurrentMap uris = getUriMap(siteKey, source, + phuc); + if (!uris.containsKey(dataUri)) { + try { + SourceXML sourceXML = fscm.getSource(source); + FFMPCacheRecord ffmpRec = populateFFMPRecord(true, dataUri, + siteKey, source, phuc); + File loc = HDF5Util.findHDF5Location(ffmpRec); + IDataStore dataStore = DataStoreFactory.getDataStore(loc); - VizApp.runAsync(new Runnable() { - @Override - public void run() { - - if (fdataUri != null) { - ConcurrentMap uris = getUriMap(fsiteKey, - fsource, fhuc); - if (!uris.containsKey(fdataUri)) { - try { - SourceXML sourceXML = fscm.getSource(fsource); - FFMPCacheRecord ffmpRec = populateFFMPRecord(true, - fdataUri, fsiteKey, fsource, fhuc); - // FFMPRecord ffmpRec = - // loadRecordFromDatabase(fdataUri); - File loc = HDF5Util.findHDF5Location(ffmpRec); - IDataStore dataStore = DataStoreFactory - .getDataStore(loc); - - if (sourceXML.getSourceType().equals( - SOURCE_TYPE.GAGE.getSourceType()) - && fhuc.equals("ALL")) { - ffmpRec.retrieveVirtualBasinFromDataStore( - dataStore, fdataUri, - getTemplates(fsiteKey), ffmpRec - .getDataTime().getRefTime(), - fbasin); - } else { - ffmpRec.retrieveBasinFromDataStore(dataStore, - fdataUri, getTemplates(fsiteKey), fhuc, - ffmpRec.getDataTime().getRefTime(), - ffmpRec.getSourceName(), fbasin); - } - } catch (Throwable e) { - statusHandler - .handle(Priority.PROBLEM, - "FFMP Can't retrieve FFMP URI, " - + fdataUri, e); - } + if (sourceXML.getSourceType().equals( + SOURCE_TYPE.GAGE.getSourceType()) + && phuc.equals("ALL")) { + ffmpRec.retrieveVirtualBasinFromDataStore(dataStore, + dataUri, getTemplates(siteKey), ffmpRec + .getDataTime().getRefTime(), basin); + } else { + ffmpRec.retrieveBasinFromDataStore(dataStore, dataUri, + getTemplates(siteKey), phuc, ffmpRec + .getDataTime().getRefTime(), ffmpRec + .getSourceName(), basin); } + } catch (Throwable e) { + statusHandler.handle(Priority.PROBLEM, + "FFMP Can't retrieve FFMP URI, " + dataUri, e); } } - }); + } } /** @@ -694,7 +672,7 @@ public class FFMPMonitor extends ResourceMonitor { if (source.getSourceType().equals( SOURCE_TYPE.GUIDANCE.getSourceType())) { - long timeOffset = source.getExpirationMinutes(siteKey) * 1000 * 60; + long timeOffset = source.getExpirationMinutes(siteKey) * TimeUtil.MILLIS_PER_MINUTE; earliestTime = new Date(time.getTime() - timeOffset); } @@ -977,7 +955,7 @@ public class FFMPMonitor extends ResourceMonitor { hucsToLoad.clear(); hucsToLoad.add("ALL"); timeBack = new Date(resource.getMostRecentTime().getTime() - - (3600 * 1000 * 24)); + - (TimeUtil.MILLIS_PER_HOUR * 24)); } frd.floader = new FFMPDataLoader(frd, timeBack, startTime, loadType, @@ -1149,10 +1127,13 @@ public class FFMPMonitor extends ResourceMonitor { res.getResourceData().floader = null; int val = siteCount.get(res.getSiteKey()); - // clear out the cache - for (Entry entry : ffmpData.get( - res.getSiteKey()).entrySet()) { - entry.getValue().closeCache(); + // never opened a cache + if (ffmpData.get(res.getSiteKey()) != null) { + // clear out the cache + for (Entry entry : ffmpData.get( + res.getSiteKey()).entrySet()) { + entry.getValue().closeCache(); + } } if ((val == 1) && (siteCount.size() > 1)) { @@ -2426,9 +2407,11 @@ public class FFMPMonitor extends ResourceMonitor { } } else { try { - statusHandler.handle(Priority.INFO, + if (statusHandler.isPriorityEnabled(Priority.DEBUG)) { + statusHandler.handle(Priority.DEBUG, "Retrieving and Populating URI: , " + dataUri); + } curRecord.retrieveMapFromDataStore(dataStore, dataUri, getTemplates(fffmpRec.getSiteKey()), fhuc, diff --git a/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPDataLoader.java b/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPDataLoader.java index e6650e9e25..7ce491a4f9 100644 --- a/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPDataLoader.java +++ b/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPDataLoader.java @@ -29,8 +29,9 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.NavigableMap; +import java.util.zip.GZIPInputStream; -import com.raytheon.uf.common.dataplugin.ffmp.FFMPBasinData; +import com.raytheon.uf.common.dataplugin.ffmp.FFMPAggregateRecord; import com.raytheon.uf.common.monitor.config.FFMPRunConfigurationManager; import com.raytheon.uf.common.monitor.xml.FFMPRunXML; import com.raytheon.uf.common.monitor.xml.ProductRunXML; @@ -40,6 +41,10 @@ import com.raytheon.uf.common.ohd.AppsDefaults; import com.raytheon.uf.common.serialization.DynamicSerializationManager; import com.raytheon.uf.common.serialization.DynamicSerializationManager.SerializationType; import com.raytheon.uf.common.serialization.SerializationException; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.viz.core.VizApp; import com.raytheon.uf.viz.monitor.ffmp.FFMPMonitor; import com.raytheon.uf.viz.monitor.ffmp.ui.dialogs.FFMPConfig; @@ -57,6 +62,7 @@ import com.raytheon.uf.viz.monitor.ffmp.ui.listeners.FFMPLoaderEvent; * ------------ ---------- ----------- -------------------------- * 28 Feb, 2011 7587 dhladky Initial creation * 25 Jan, 2012 DR13839 gzhang Handle Uris and Huc processing + * 01/27/13 1478 D. Hladky revamped the cache file format to help NAS overloading * * * @author dhladky @@ -64,8 +70,7 @@ import com.raytheon.uf.viz.monitor.ffmp.ui.listeners.FFMPLoaderEvent; */ public class FFMPDataLoader extends Thread { - // private static final transient IUFStatusHandler statusHandler = UFStatus - // .getHandler(FFMPDataLoader.class); + private static final IUFStatusHandler statusHandler = UFStatus.getHandler(FFMPDataLoader.class); private String sharePath = null; @@ -154,7 +159,7 @@ public class FFMPDataLoader extends Thread { ProductRunXML productRun = runner.getProduct(siteKey); ArrayList qpfSources = new ArrayList(); - + String layer = config.getFFMPConfigData().getLayer(); boolean isProductLoad = true; String rateURI = null; @@ -225,179 +230,159 @@ public class FFMPDataLoader extends Thread { hucsToLoad.add("ALL"); } - for (String phuc : hucsToLoad) { + if (isDone) { + return; + } - if (isDone) { - return; + // rate + if (rateURI != null) { + fireLoaderEvent(loadType, "Processing " + product.getRate(), + isDone); + for (String phuc : hucsToLoad) { + getMonitor().processUri(isProductLoad, rateURI, siteKey, + product.getRate(), timeBack, phuc); } + fireLoaderEvent(loadType, product.getRate(), isDone); + } - if (phuc.equals("VIRTUAL")) { - // we don't do the virtuals like this - continue; - } else { - // rate - if (rateURI != null) { - fireLoaderEvent(loadType, - "Processing " + product.getRate() + "/" + phuc, - isDone); + // qpes + fireLoaderEvent(loadType, "Processing " + product.getQpe(), isDone); + FFMPAggregateRecord qpeCache = null; - getMonitor().processUri(isProductLoad, rateURI, - siteKey, product.getRate(), timeBack, phuc); - fireLoaderEvent(loadType, product.getRate() + "/" - + phuc, isDone); + if (loadType == LOADER_TYPE.INITIAL) { + + SourceXML source = getMonitor().getSourceConfig().getSource( + product.getQpe()); + + qpeCache = readCacheFile(source, dataKey, wfo); + + if (qpeCache != null) { + getMonitor().insertFFMPData(qpeCache, siteKey, + product.getQpe()); + } + } + + // Use this method of QPE data retrieval if you don't have cache files + if (!qpeURIs.isEmpty() && qpeCache == null) { + for (String phuc : hucsToLoad) { + if (phuc.equals(layer) + || phuc.equals("ALL")) { + getMonitor().processUris(qpeURIs, isProductLoad, + siteKey, product.getQpe(), timeBack, phuc); } + } + } - // qpes - fireLoaderEvent(loadType, "Processing " + product.getQpe() - + "/" + phuc, isDone); - FFMPBasinData qpeData = null; + fireLoaderEvent(loadType, product.getQpe(), isDone); - if (loadType == LOADER_TYPE.INITIAL) { + int i = 0; + for (NavigableMap> qpfURIs : qpfs) { + // qpf + fireLoaderEvent(loadType, "Processing " + product.getQpf(i), + isDone); + FFMPAggregateRecord qpfCache = null; - SourceXML source = getMonitor().getSourceConfig() - .getSource(product.getQpe()); + if (loadType == LOADER_TYPE.INITIAL) { - qpeData = readLoaderBuddyFile(source, phuc, dataKey, - wfo); + SourceXML source = getMonitor().getSourceConfig() + .getSource(qpfSources.get(i)); - if (qpeData != null) { + String pdataKey = findQPFHomeDataKey(source); + qpfCache = readCacheFile(source, pdataKey, wfo); - getMonitor().insertFFMPData(qpeData, siteKey, - product.getQpe(), phuc); - } - } + if (qpfCache != null) { + for (String phuc : hucsToLoad) { + if ((phuc.equals(layer) || phuc.equals("ALL")) + && loadType == LOADER_TYPE.INITIAL + && source.getSourceName().equals( + config.getFFMPConfigData() + .getIncludedQPF())) { + if (!qpfURIs.isEmpty()) { - if (!qpeURIs.isEmpty() && qpeData == null) { - if (phuc.equals(config.getFFMPConfigData().getLayer()) - || phuc.equals("ALL")) { - getMonitor().processUris(qpeURIs, isProductLoad, - siteKey, product.getQpe(), timeBack, phuc); - } - } - - fireLoaderEvent(loadType, product.getQpe() + "/" + phuc, - isDone); - - int i = 0; - for (NavigableMap> qpfURIs : qpfs) { - // qpf - fireLoaderEvent(loadType, - "Processing " + product.getQpf(i) + "/" + phuc, - isDone); - FFMPBasinData qpfData = null; - if (loadType == LOADER_TYPE.INITIAL) { - - SourceXML source = getMonitor().getSourceConfig() - .getSource(qpfSources.get(i)); - - String pdataKey = findQPFHomeDataKey(source); - qpfData = readLoaderBuddyFile(source, phuc, - pdataKey, wfo); - - if (qpfData != null) { - - if ((phuc.equals(config.getFFMPConfigData() - .getLayer()) || phuc.equals("ALL")) - && loadType == LOADER_TYPE.INITIAL - && source.getSourceName().equals( - config.getFFMPConfigData() - .getIncludedQPF())) { - if (!qpfURIs.isEmpty()) { - - getMonitor().processUris(qpfURIs, - isProductLoad, siteKey, - source.getSourceName(), - timeBack, phuc); - } + getMonitor().processUris(qpfURIs, + isProductLoad, siteKey, + source.getSourceName(), timeBack, + phuc); } - - getMonitor().insertFFMPData(qpfData, siteKey, - source.getSourceName(), phuc); - } - } - // if (isUrisProcessNeeded(qpfData,qpfURIs)) - // {/*DR13839*/ - if ((qpfData == null) && !qpfURIs.isEmpty()) { - if (phuc.equals(config.getFFMPConfigData() - .getLayer()) || phuc.equals("ALL")) { // old - // code: - // keep - // for - // reference*/ - // if (isHucProcessNeeded(phuc)) {/*DR13839*/ - getMonitor().processUris(qpfURIs, - isProductLoad, siteKey, - product.getQpf(i), timeBack, phuc); } } - fireLoaderEvent(loadType, product.getQpf(i) + "/" - + phuc, isDone); - - i++; + getMonitor().insertFFMPData(qpfCache, siteKey, + source.getSourceName()); } - } - // virtuals only have data for ALL - if (phuc.equals("ALL")) { + // if (isUrisProcessNeeded(qpfData,qpfURIs)) + // {/*DR13839*/ + // Use this method of QPF data retrieval if you don't have cache files + if ((qpfCache == null) && !qpfURIs.isEmpty()) { + for (String phuc : hucsToLoad) { + if (phuc.equals(layer) + || phuc.equals("ALL")) { // old + // code: + // keep + // for + // reference*/ + // if (isHucProcessNeeded(phuc)) {/*DR13839*/ + getMonitor().processUris(qpfURIs, isProductLoad, + siteKey, product.getQpf(i), timeBack, phuc); + } + } + } + + fireLoaderEvent(loadType, product.getQpf(i), isDone); + + i++; + } + + fireLoaderEvent(loadType, "Processing " + product.getVirtual(), + isDone); + FFMPAggregateRecord vgbCache = null; + + if (loadType == LOADER_TYPE.INITIAL) { + + SourceXML source = getMonitor().getSourceConfig().getSource( + product.getVirtual()); + + vgbCache = readCacheFile(source, dataKey, wfo); + + if (vgbCache != null) { + + getMonitor().insertFFMPData(vgbCache, siteKey, + product.getVirtual()); + } + } + + // Use this method of Virtual data retrieval if you don't have cache files + if ((vgbCache == null) && !virtualURIs.isEmpty()) { + getMonitor().processUris(virtualURIs, isProductLoad, siteKey, + product.getVirtual(), timeBack, "ALL"); + } + + fireLoaderEvent(loadType, product.getVirtual(), isDone); + + // process guidance all for all only, never uses cache files + for (String type : productRun.getGuidanceTypes(product)) { + + ArrayList guidSources = productRun + .getGuidanceSources(product, type); + for (SourceXML guidSource : guidSources) { + + NavigableMap> iguidURIs = guids + .get(guidSource.getSourceName()); + fireLoaderEvent(loadType, - "Processing " + product.getVirtual() + "/" + phuc, + "Processing " + guidSource.getSourceName(), isDone); + + getMonitor().processUris(iguidURIs, isProductLoad, siteKey, + guidSource.getSourceName(), timeBack, "ALL"); + + fireLoaderEvent(loadType, guidSource.getSourceName(), isDone); - FFMPBasinData vgbData = null; - if (loadType == LOADER_TYPE.INITIAL) { - - SourceXML source = getMonitor().getSourceConfig() - .getSource(product.getVirtual()); - - vgbData = readLoaderBuddyFile(source, phuc, dataKey, - wfo); - - if (vgbData != null) { - - getMonitor().insertFFMPData(vgbData, siteKey, - product.getVirtual(), phuc); - } - } - - if ((vgbData == null) && !virtualURIs.isEmpty()) { - getMonitor().processUris(virtualURIs, isProductLoad, - siteKey, product.getVirtual(), timeBack, phuc); - } - - fireLoaderEvent(loadType, - product.getVirtual() + "/" + phuc, isDone); } - - // process guidance all at once - for (String type : productRun.getGuidanceTypes(product)) { - - ArrayList guidSources = productRun - .getGuidanceSources(product, type); - for (SourceXML guidSource : guidSources) { - - NavigableMap> iguidURIs = guids - .get(guidSource.getSourceName()); - - fireLoaderEvent(loadType, - "Processing " + guidSource.getSourceName() - + "/" + phuc, isDone); - - getMonitor().processUris(iguidURIs, isProductLoad, - siteKey, guidSource.getSourceName(), timeBack, - phuc); - - fireLoaderEvent(loadType, guidSource.getSourceName() - + "/" + phuc, isDone); - - } - } - - fireLoaderEvent(loadType, phuc + " Load complete", isDone); } } catch (Exception e) { - System.err.println("FFMP Data Loader terminated...." - + e.getMessage()); + statusHandler.handle(Priority.PROBLEM,"General Problem in Loading FFMP Data", e); } finally { isDone = true; } @@ -410,7 +395,7 @@ public class FFMPDataLoader extends Thread { } long endTime = (System.currentTimeMillis()) - time; - System.out.println("Loader took: " + endTime / 1000 + " seconds"); + System.out.println(loadType.loaderType + " Loader took: " + endTime / 1000 + " seconds"); fireLoaderEvent(loadType, message, isDone); } @@ -467,19 +452,19 @@ public class FFMPDataLoader extends Thread { }; /** - * Loads the loader buddy files + * Loads the Cache files * * @param sourceName * @param huc * @param wfo * @return */ - private FFMPBasinData readLoaderBuddyFile(SourceXML source, String huc, - String pdataKey, String wfo) { + private FFMPAggregateRecord readCacheFile(SourceXML source, String pdataKey, String wfo) { + long time = System.currentTimeMillis(); String sourceName = source.getSourceName(); File file = new File(sharePath + wfo + File.separator + sourceName - + "-" + siteKey + "-" + pdataKey + "-" + huc + ".bin"); + + "-" + siteKey + "-" + pdataKey + ".bin"); File lockFile = new File(sharePath + wfo + File.separator + sourceName + "-" + siteKey + "-" + pdataKey + ".lock"); @@ -489,22 +474,22 @@ public class FFMPDataLoader extends Thread { sleep(100); i++; } catch (InterruptedException e) { - e.printStackTrace(); + statusHandler.handle(Priority.ERROR,"Took to long to load Cache Record", e); } } break; } - System.out.println("Buddy File expected path: " + System.out.println("Cache File expected path: " + file.getAbsolutePath()); - FFMPBasinData basinData = null; + FFMPAggregateRecord cacheRecord = null; if (file.exists()) { System.out.println("Last mod: " + new Date(file.lastModified())); - if (file.lastModified() > (System.currentTimeMillis() - (6 * 1000 * 3600))) { + if (file.lastModified() > (System.currentTimeMillis() - (6 * TimeUtil.MILLIS_PER_HOUR))) { while (lockFile.exists()) { for (int i = 0; i < 4; i++) { @@ -514,39 +499,42 @@ public class FFMPDataLoader extends Thread { sleep(100); i++; } catch (InterruptedException e) { - e.printStackTrace(); + statusHandler.handle(Priority.ERROR,"ERROR in Loading Cache Record", e); } } break; } - BufferedInputStream is = null; + GZIPInputStream gis = null; try { System.out.println("Loading file: " + file.getName()); - is = new BufferedInputStream(new FileInputStream(file)); + gis = new GZIPInputStream(new BufferedInputStream(new FileInputStream(file))); DynamicSerializationManager dsm = DynamicSerializationManager .getManager(SerializationType.Thrift); - basinData = (FFMPBasinData) dsm.deserialize(is); + cacheRecord = (FFMPAggregateRecord) dsm.deserialize(gis); } catch (SerializationException e) { - e.printStackTrace(); + statusHandler.handle(Priority.ERROR,"Serialization ERROR in Loading Cache Record", e); } catch (IOException e) { - e.printStackTrace(); + statusHandler.handle(Priority.ERROR,"IO ERROR in Loading Cache Record", e); } finally { - if (is != null) { + if (gis != null) { try { - is.close(); + gis.close(); } catch (IOException e) { - e.printStackTrace(); + statusHandler.handle(Priority.ERROR,"GENRAL ERROR in Loading Cache Record", e); } } } } } + + long time2 = System.currentTimeMillis(); + System.out.println("FFMP Cache file Load took: "+ (time2 - time) + " ms"); - return basinData; + return cacheRecord; } @@ -564,7 +552,7 @@ public class FFMPDataLoader extends Thread { for (ProductRunXML product : runManager.getProducts()) { File file = new File(sharePath + wfo + File.separator + source.getSourceName() + "-" + siteKey + "-" - + product.getProductKey() + "-ALL.bin"); + + product.getProductKey() + ".bin"); if (file.exists()) { return product.getProductKey(); @@ -572,7 +560,6 @@ public class FFMPDataLoader extends Thread { } return siteKey; - } } \ No newline at end of file diff --git a/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPResource.java b/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPResource.java index df28dcb877..f768f9d520 100644 --- a/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPResource.java +++ b/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPResource.java @@ -81,6 +81,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.viz.core.DrawableString; import com.raytheon.uf.viz.core.IDisplayPaneContainer; import com.raytheon.uf.viz.core.IGraphicsTarget; @@ -152,7 +153,8 @@ import com.vividsolutions.jts.geom.Point; * 31 July 2012 14517 mpduff Fix for blanking map on update. * 14 Sep 2012 1048 njensen Code cleanup * 07 Dec 2012 1353 rferrel Changes for non-blocking FFMPSplash dialog. - * + * 10 Jan 2013 1475 dhladky Some cleanup + * 27 Jan 2013 1478 dhladky Changed gap collection to a generic list insted of Arraylist * * * @author dhladky @@ -2070,6 +2072,7 @@ public class FFMPResource extends private void drawSquare(PixelCoverage pc, IGraphicsTarget target) throws VizException { + //target.drawLine(lines) target.drawLine(pc.getLl().x, pc.getLl().y, 0.0, pc.getUl().x, pc .getUl().y, 0.0, getCapability(ColorableCapability.class) .getColor(), getCapability(OutlineCapability.class) @@ -2455,10 +2458,6 @@ public class FFMPResource extends cwaBasins.clear(); try { - // String aggrHuc = "HUC0"; - // if (phuc.equals("COUNTY")) { - // aggrHuc = phuc; - // } // use the envelopes from HUC0 to speed processing // if necessary Map envMap = hucGeomFactory.getEnvelopes( @@ -2472,7 +2471,7 @@ public class FFMPResource extends } } } catch (Exception e) { - statusHandler.handle(Priority.WARN, "Domain: " + cwa + statusHandler.handle(Priority.DEBUG, "Domain: " + cwa + " Outside of site: " + getSiteKey() + " area..."); } } @@ -2901,7 +2900,7 @@ public class FFMPResource extends descriptor, 0.0f); if (req.shaded) { localShadedShape = req.target.createShadedShape(false, - descriptor, true); + descriptor.getGridGeometry(), true); } JTSCompiler jtsCompiler2 = new JTSCompiler(localShadedShape, @@ -3550,7 +3549,7 @@ public class FFMPResource extends synchronized (tableTime) { Date recentTime = getMostRecentTime(); - long time = new Double(recentTime.getTime() - (1000 * 3600) + long time = new Double(recentTime.getTime() - (TimeUtil.MILLIS_PER_HOUR) * getTime()).longValue(); Date date = new Date(); date.setTime(time); @@ -3724,7 +3723,7 @@ public class FFMPResource extends Date oldestCurrentTime = getResourceData().getAvailableTimes()[0] .getRefTime(); Date oldestTime = new Date(oldestCurrentTime.getTime() - - (1000 * 3600 * 24)); + - (TimeUtil.MILLIS_PER_HOUR * 24)); SortedSet keys = monitor.getAvailableUris(getSiteKey(), getDataKey(), getPrimarySource(), oldestTime).keySet(); @@ -3771,7 +3770,7 @@ public class FFMPResource extends - getTableTime().getTime(); sliderTime = Math - .floor(4 * (offset.doubleValue() / (1000 * 3600)) + .25) / 4; + .floor(4 * (offset.doubleValue() / (TimeUtil.MILLIS_PER_HOUR)) + .25) / 4; // sliderTime = Math.floor(((offset.doubleValue() / (1000 * 3600)) + // .005) * 100) / 100; setTime(sliderTime); @@ -3941,7 +3940,7 @@ public class FFMPResource extends * * @return Array of Gap data */ - public ArrayList getGaps() { + public List getGaps() { synchronized (timeOrderedKeys) { return FFMPGap.getGaps(getTimeOrderedKeys(), getResourceData() .getPrimarySourceXML().getExpirationMinutes(getSiteKey()), @@ -4010,7 +4009,7 @@ public class FFMPResource extends this.qpeSourceExpiration = monitor.getSourceConfig() .getSource(resourceData.getPrimarySource()) - .getExpirationMinutes(getSiteKey()) * 60 * 1000; + .getExpirationMinutes(getSiteKey()) * TimeUtil.MILLIS_PER_MINUTE; } return qpeSourceExpiration; } @@ -4033,7 +4032,7 @@ public class FFMPResource extends source = FFMPSourceConfigurationManager.getInstance() .getSource(getResourceData().sourceName); } - qpfSourceExpiration = source.getExpirationMinutes(getSiteKey()) * 60 * 1000; + qpfSourceExpiration = source.getExpirationMinutes(getSiteKey()) * TimeUtil.MILLIS_PER_MINUTE; } return qpfSourceExpiration; } @@ -4056,12 +4055,12 @@ public class FFMPResource extends SourceXML source = getProduct().getGuidanceSourcesByType( guidSrc).get(0); guidSourceExpiration = source - .getExpirationMinutes(getSiteKey()) * 60 * 1000; + .getExpirationMinutes(getSiteKey()) * TimeUtil.MILLIS_PER_MINUTE; } else { guidSourceExpiration = monitor.getSourceConfig() .getSource(resourceData.getPrimarySource()) - .getExpirationMinutes(getSiteKey()) * 60 * 1000; + .getExpirationMinutes(getSiteKey()) * TimeUtil.MILLIS_PER_MINUTE; } } @@ -4266,7 +4265,7 @@ public class FFMPResource extends } - return 3600 * 24 * 1000; + return 24 * TimeUtil.MILLIS_PER_HOUR; } /** @@ -4281,7 +4280,7 @@ public class FFMPResource extends if (status.isDone() && !this.getResourceData().isTertiaryLoad) { try { Date startDate = new Date(getMostRecentTime().getTime() - - (6 * 3600 * 1000)); + - (6 * TimeUtil.MILLIS_PER_HOUR)); FFMPMonitor.getInstance().startLoad(this, startDate, LOADER_TYPE.TERTIARY); } catch (VizException e) { diff --git a/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPResourceData.java b/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPResourceData.java index 98b9db188b..8d9b0ea1d0 100644 --- a/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPResourceData.java +++ b/cave/com.raytheon.uf.viz.monitor.ffmp/src/com/raytheon/uf/viz/monitor/ffmp/ui/rsc/FFMPResourceData.java @@ -50,6 +50,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.rsc.AbstractNameGenerator; import com.raytheon.uf.viz.core.rsc.AbstractRequestableResourceData; @@ -230,11 +231,8 @@ public class FFMPResourceData extends AbstractRequestableResourceData { DataTime mostRecentTime = availableTimes[availableTimes.length - 1]; this.timeBack = new Date( (long) (mostRecentTime.getRefTime().getTime() - (cfgBasinXML - .getTimeFrame() * 3600 * 1000))); + .getTimeFrame() * TimeUtil.MILLIS_PER_HOUR))); ArrayList hucsToLoad = monitor.getTemplates(siteKey).getTemplateMgr().getHucLevels(); - //ArrayList hucsToLoad = new ArrayList(); - //hucsToLoad.add(cfgBasinXML.getLayer()); - //hucsToLoad.add("ALL"); // goes back X hours and pre populates the Data Hashes FFMPDataLoader loader = new FFMPDataLoader(this, timeBack, mostRecentTime.getRefTime(), LOADER_TYPE.INITIAL, @@ -275,18 +273,28 @@ public class FFMPResourceData extends AbstractRequestableResourceData { this.domains = monitor.getRunConfig().getDomains(); SourceXML source = monitor.getSourceConfig().getSource( sourceName); + Date standAloneTime = null; if (source != null) { + // Special Loading for guidance sources, as mentioned in the comment + if (source.getDataType().equals(SOURCE_TYPE.GUIDANCE.getSourceType())) { + long oldestTime = availableTimes[0].getRefTime() + .getTime(); + long expirationTime = source + .getExpirationMinutes(siteKey) * TimeUtil.MILLIS_PER_MINUTE; + standAloneTime = new Date(oldestTime + - expirationTime); + } else { + // Only load current frames time + standAloneTime = availableTimes[availableTimes.length - 1] + .getRefTime(); + } - long oldestTime = availableTimes[0].getRefTime().getTime(); - long expirationTime = source.getExpirationMinutes(siteKey) * 60 * 1000; - Date standAloneTime = new Date(oldestTime - expirationTime); - NavigableMap> sourceURIs = getMonitor() - .getAvailableUris(siteKey, dataKey, sourceName, - standAloneTime); + .getAvailableUris(siteKey, dataKey, sourceName, + standAloneTime); getMonitor().processUris(sourceURIs, false, siteKey, - sourceName, standAloneTime, "ALL"); + sourceName, standAloneTime, "ALL"); } } } diff --git a/cave/com.raytheon.uf.viz.npp.crimss/src/com/raytheon/uf/viz/npp/crimss/map/CrimssMapResource.java b/cave/com.raytheon.uf.viz.npp.crimss/src/com/raytheon/uf/viz/npp/crimss/map/CrimssMapResource.java index cdf715f959..ee7def0588 100644 --- a/cave/com.raytheon.uf.viz.npp.crimss/src/com/raytheon/uf/viz/npp/crimss/map/CrimssMapResource.java +++ b/cave/com.raytheon.uf.viz.npp.crimss/src/com/raytheon/uf/viz/npp/crimss/map/CrimssMapResource.java @@ -54,7 +54,7 @@ import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability; import com.raytheon.uf.viz.core.rsc.capabilities.EditableCapability; import com.raytheon.uf.viz.core.rsc.capabilities.MagnificationCapability; import com.raytheon.uf.viz.npp.crimss.CrimssNSharpResourceData; -import com.raytheon.viz.ui.MenuLoader; +import com.raytheon.viz.ui.BundleProductLoader; import com.raytheon.viz.ui.UiUtil; import com.raytheon.viz.ui.editor.AbstractEditor; import com.raytheon.viz.ui.input.EditableManager; @@ -218,7 +218,7 @@ public class CrimssMapResource extends display.cloneDisplay()); Bundle b = new Bundle(); b.setDisplays(new AbstractRenderableDisplay[] { display }); - Job j = new MenuLoader(b, editor); + Job j = new BundleProductLoader(editor, b); j.schedule(); } diff --git a/cave/com.raytheon.uf.viz.plugin.nwsauth/src/com/raytheon/uf/viz/plugin/nwsauth/NwsNotAuthHandler.java b/cave/com.raytheon.uf.viz.plugin.nwsauth/src/com/raytheon/uf/viz/plugin/nwsauth/NwsNotAuthHandler.java index 646a9bdbbc..cbf3c3616d 100644 --- a/cave/com.raytheon.uf.viz.plugin.nwsauth/src/com/raytheon/uf/viz/plugin/nwsauth/NwsNotAuthHandler.java +++ b/cave/com.raytheon.uf.viz.plugin.nwsauth/src/com/raytheon/uf/viz/plugin/nwsauth/NwsNotAuthHandler.java @@ -63,7 +63,7 @@ public class NwsNotAuthHandler implements INotAuthHandler { + request.getClass(); UFStatus.getHandler(NwsNotAuthHandler.class).handle(Priority.PROBLEM, message); - return null; + throw new VizException(message); } /* @@ -82,7 +82,7 @@ public class NwsNotAuthHandler implements INotAuthHandler { } UFStatus.getHandler(NwsNotAuthHandler.class).handle(Priority.PROBLEM, message); - return null; + throw new VizException(message); } } diff --git a/cave/com.raytheon.uf.viz.productbrowser/src/com/raytheon/uf/viz/productbrowser/AbstractRequestableProductBrowserDataDefinition.java b/cave/com.raytheon.uf.viz.productbrowser/src/com/raytheon/uf/viz/productbrowser/AbstractRequestableProductBrowserDataDefinition.java index d89159bf80..074c8de473 100644 --- a/cave/com.raytheon.uf.viz.productbrowser/src/com/raytheon/uf/viz/productbrowser/AbstractRequestableProductBrowserDataDefinition.java +++ b/cave/com.raytheon.uf.viz.productbrowser/src/com/raytheon/uf/viz/productbrowser/AbstractRequestableProductBrowserDataDefinition.java @@ -20,6 +20,7 @@ package com.raytheon.uf.viz.productbrowser; * further licensing information. **/ +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -50,7 +51,7 @@ import com.raytheon.uf.viz.core.rsc.ResourceProperties; import com.raytheon.uf.viz.core.rsc.ResourceType; import com.raytheon.uf.viz.productbrowser.ProductBrowserPreference.PreferenceType; import com.raytheon.viz.ui.EditorUtil; -import com.raytheon.viz.ui.MenuLoader; +import com.raytheon.viz.ui.BundleProductLoader; import com.raytheon.viz.ui.VizWorkbenchManager; import com.raytheon.viz.ui.editor.AbstractEditor; import com.raytheon.viz.ui.perspectives.AbstractVizPerspectiveManager; @@ -198,12 +199,15 @@ public abstract class AbstractRequestableProductBrowserDataDefinition pairs) { // retrieves the correct editor getEditor(); IDisplayPaneContainer container = getEditor(); @@ -213,11 +217,12 @@ public abstract class AbstractRequestableProductBrowserDataDefinition * @@ -38,133 +41,162 @@ import org.osgi.framework.Constants; */ public class Activator implements BundleActivator { - // The plug-in ID - public static final String PLUGIN_ID = "com.raytheon.uf.viz.spring.dm"; + // The plug-in ID + public static final String PLUGIN_ID = "com.raytheon.uf.viz.spring.dm"; - private static final String SPRING_PATH = "res" + IPath.SEPARATOR - + "spring"; + private static final String SPRING_PATH = "res" + IPath.SEPARATOR + + "spring"; - private static final String SPRING_FILE_EXT = "*.xml"; + private static final String SPRING_FILE_EXT = "*.xml"; - // The shared instance - private static Activator plugin; + // The shared instance + private static Activator plugin; - /** - * The constructor - */ - public Activator() { - } + /** + * The constructor + */ + public Activator() { + } - /* - * (non-Javadoc) - * - * @see - * org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext) - */ - public void start(BundleContext context) throws Exception { - plugin = this; + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + if (this.isInstallOperation()) { + return; + } + plugin = this; - Map contextMap = new HashMap(); - Set processing = new HashSet(); - Bundle[] bundles = context.getBundles(); - Map bundleMap = new HashMap(); - for (Bundle b : bundles) { - bundleMap.put(b.getSymbolicName(), b); - } - for (Bundle b : bundles) { - createContext(bundleMap, contextMap, b, processing); - } - } + Map contextMap = new HashMap(); + Set processing = new HashSet(); + Bundle[] bundles = context.getBundles(); + Map bundleMap = new HashMap(); + for (Bundle b : bundles) { + bundleMap.put(b.getSymbolicName(), b); + } + for (Bundle b : bundles) { + createContext(bundleMap, contextMap, b, processing); + } + } - private OSGIXmlApplicationContext createContext( - Map bundles, - Map contextMap, Bundle bundle, - Set processing) { - String bundleName = bundle.getSymbolicName(); - OSGIXmlApplicationContext appCtx = contextMap.get(bundleName); - if (contextMap.containsKey(bundleName) == false - && bundleName.contains(".edex.") == false) { - if (processing.contains(bundleName)) { - throw new RuntimeException( - "Found recursive spring dependency while processing plugins: " - + bundleName); - } - processing.add(bundleName); + private OSGIXmlApplicationContext createContext( + Map bundles, + Map contextMap, Bundle bundle, + Set processing) { + String bundleName = bundle.getSymbolicName(); + OSGIXmlApplicationContext appCtx = contextMap.get(bundleName); + if (contextMap.containsKey(bundleName) == false + && bundleName.contains(".edex.") == false) { + if (processing.contains(bundleName)) { + throw new RuntimeException( + "Found recursive spring dependency while processing plugins: " + + bundleName); + } + processing.add(bundleName); - // No context created yet and not edex project, check for files - Enumeration entries = bundle.findEntries(SPRING_PATH, - SPRING_FILE_EXT, true); - if (entries != null) { - List files = new ArrayList(); - while (entries.hasMoreElements()) { - URL url = (URL) entries.nextElement(); - try { - url = FileLocator.toFileURL(url); - files.add(url.toString()); - } catch (IOException e) { - throw new RuntimeException( - "Error resolving spring file: " + url, e); - } - } - if (files.size() > 0) { - // Files found, check for dependencies - String requiredBundlesHeader = (String) bundle.getHeaders() - .get(Constants.REQUIRE_BUNDLE); - // Split comma separated string from MANIFEST - String[] requiredBundles = requiredBundlesHeader - .split("[,]"); - List parentContexts = new ArrayList(); - for (String requiredBndl : requiredBundles) { - // Extract bundle name which is first item in - // semicolon - // split list - String[] bndlParts = requiredBndl.split("[;]"); - Bundle reqBndl = bundles.get(bndlParts[0]); - if (reqBndl != null) { - // Found bundle, process context for bundle - OSGIXmlApplicationContext parent = createContext( - bundles, contextMap, reqBndl, processing); - if (parent != null) { - // Context found, add to list - parentContexts.add(parent); - } - } - } + // No context created yet and not edex project, check for files + Enumeration entries = bundle.findEntries(SPRING_PATH, + SPRING_FILE_EXT, true); + if (entries != null) { + List files = new ArrayList(); + while (entries.hasMoreElements()) { + URL url = (URL) entries.nextElement(); + try { + url = FileLocator.toFileURL(url); + files.add(url.toString()); + } catch (IOException e) { + throw new RuntimeException( + "Error resolving spring file: " + url, e); + } + } + if (files.size() > 0) { + // Files found, check for dependencies + String requiredBundlesHeader = (String) bundle.getHeaders() + .get(Constants.REQUIRE_BUNDLE); + // Split comma separated string from MANIFEST + String[] requiredBundles = requiredBundlesHeader + .split("[,]"); + List parentContexts = new ArrayList(); + for (String requiredBndl : requiredBundles) { + // Extract bundle name which is first item in + // semicolon + // split list + String[] bndlParts = requiredBndl.split("[;]"); + Bundle reqBndl = bundles.get(bndlParts[0]); + if (reqBndl != null) { + // Found bundle, process context for bundle + OSGIXmlApplicationContext parent = createContext( + bundles, contextMap, reqBndl, processing); + if (parent != null) { + // Context found, add to list + parentContexts.add(parent); + } + } + } - if (parentContexts.size() > 0) { - // Context with parent context - appCtx = new OSGIXmlApplicationContext( - new OSGIGroupApplicationContext(parentContexts), - files.toArray(new String[0]), bundle); - } else { - // No parent context required - appCtx = new OSGIXmlApplicationContext( - files.toArray(new String[0]), bundle); - } - } - } - contextMap.put(bundleName, appCtx); - } - processing.remove(bundleName); - return appCtx; - } + if (parentContexts.size() > 0) { + // Context with parent context + appCtx = new OSGIXmlApplicationContext( + new OSGIGroupApplicationContext(parentContexts), + files.toArray(new String[0]), bundle); + } else { + // No parent context required + appCtx = new OSGIXmlApplicationContext( + files.toArray(new String[0]), bundle); + } + } + } + contextMap.put(bundleName, appCtx); + } + processing.remove(bundleName); + return appCtx; + } - /* - * (non-Javadoc) - * - * @see - * org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) - */ - public void stop(BundleContext context) throws Exception { - plugin = null; - } + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + } - /** - * Returns the shared instance - * - * @return the shared instance - */ - public static Activator getDefault() { - return plugin; - } + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Based on the command line arguments, determine whether or not an Eclipse + * p2 repository will be installed + * + * @return true if an Eclipse p2 repository is going to be installed, false + * otherwise + */ + private boolean isInstallOperation() { + final String P2_DIRECTOR = "org.eclipse.equinox.p2.director"; + + /** + * We look at the command line arguments instead of the program + * arguments (com.raytheon.uf.viz.application.ProgramArguments) because + * the command line arguments include almost everything that was passed + * as an argument to the Eclipse executable instead of just what CAVE is + * interested in. + */ + for (String argument : Platform.getCommandLineArgs()) { + if (P2_DIRECTOR.equals(argument)) { + return Boolean.TRUE; + } + } + + return Boolean.FALSE; + } } diff --git a/cave/com.raytheon.uf.viz.stats/META-INF/MANIFEST.MF b/cave/com.raytheon.uf.viz.stats/META-INF/MANIFEST.MF index bbc9e9368e..87e75da1c0 100644 --- a/cave/com.raytheon.uf.viz.stats/META-INF/MANIFEST.MF +++ b/cave/com.raytheon.uf.viz.stats/META-INF/MANIFEST.MF @@ -12,7 +12,8 @@ Require-Bundle: org.eclipse.ui, com.raytheon.uf.common.stats;bundle-version="1.0.0", com.raytheon.uf.common.time;bundle-version="1.12.1174", com.raytheon.uf.common.util;bundle-version="1.12.1174", - com.google.guava;bundle-version="1.0.0" + com.google.guava;bundle-version="1.0.0", + com.raytheon.uf.common.units;bundle-version="1.0.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: com.raytheon.uf.viz.stats, diff --git a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/GroupingComp.java b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/GroupingComp.java index 3f9e39259b..61bb2f5ae4 100644 --- a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/GroupingComp.java +++ b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/GroupingComp.java @@ -20,7 +20,7 @@ package com.raytheon.uf.viz.stats.ui; /** - * TODO Add Description + * Grouping Composite for the Stats Graph. * *
  *
@@ -36,10 +36,13 @@ package com.raytheon.uf.viz.stats.ui;
  * @version 1.0
  */
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Pattern;
 
 import org.eclipse.swt.SWT;
@@ -59,22 +62,25 @@ import org.eclipse.swt.widgets.ColorDialog;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Label;
 
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
 import com.raytheon.uf.common.stats.data.GraphData;
 
 /**
  * Composites that contains the controls to change colors and to determine what
  * is displayed.
- *
+ * 
  * 
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Oct 16, 2012            lvenable     Initial creation
- *
+ * Oct 16, 2012            lvenable    Initial creation
+ * Jan 11, 2013   1357     mpduff      Implement.
+ * 
  * 
- * + * * @author lvenable * @version 1.0 */ @@ -106,9 +112,11 @@ public class GroupingComp extends Composite implements IGroupSelection { /** Grouping callback */ private final IStatsGroup callback; + private final List selectionEntries = new ArrayList(); + /** * Constructor. - * + * * @param parentComp * Parent composite. * @param swtStyle @@ -191,12 +199,26 @@ public class GroupingComp extends Composite implements IGroupSelection { */ private void createControls() { List keyArray = graphData.getKeysWithData(); + Map> grpNameMap = graphData.getGroupAndNamesMap(); + // Create the Selection Entry objects for (String key : keyArray) { + SelectionEntry se = new SelectionEntry(); + String[] parts = colonPattern.split(key); + + Set grpNames = grpNameMap.keySet(); + Iterator iter = grpNames.iterator(); + for (int i = 0; i < grpNames.size(); i++) { + se.addPair(iter.next(), parts[i]); + } + this.selectionEntries.add(se); + } + + for (SelectionEntry se : selectionEntries) { GridData gd = new GridData(20, 10); Label lbl = new Label(controlComp, SWT.BORDER); lbl.setLayoutData(gd); - lbl.setData(key); + lbl.setData(se); lbl.addMouseListener(new MouseAdapter() { @Override public void mouseDown(MouseEvent e) { @@ -206,8 +228,9 @@ public class GroupingComp extends Composite implements IGroupSelection { }); Button btn = new Button(controlComp, SWT.CHECK); - btn.setText(key); + btn.setText(se.toString()); btn.setSelection(true); + btn.setData(se); btn.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { @@ -216,8 +239,8 @@ public class GroupingComp extends Composite implements IGroupSelection { } }); - labelMap.put(key, lbl); - checkBtnMap.put(key, btn); + labelMap.put(se.toString(), lbl); + checkBtnMap.put(se.toString(), btn); } } @@ -245,22 +268,22 @@ public class GroupingComp extends Composite implements IGroupSelection { displaySelectionMgrDlg(); } }); -// Not including this functionality in the branch. -// gd = new GridData(buttonWidth, SWT.DEFAULT); -// Button colorMgrBtn = new Button(buttonComp, SWT.PUSH); -// colorMgrBtn.setText("Color Manager..."); -// colorMgrBtn.setLayoutData(gd); -// colorMgrBtn.addSelectionListener(new SelectionAdapter() { -// @Override -// public void widgetSelected(SelectionEvent e) { -// displayColorMgrDlg(); -// } -// }); + // Not including this functionality in the branch. + // gd = new GridData(buttonWidth, SWT.DEFAULT); + // Button colorMgrBtn = new Button(buttonComp, SWT.PUSH); + // colorMgrBtn.setText("Color Manager..."); + // colorMgrBtn.setLayoutData(gd); + // colorMgrBtn.addSelectionListener(new SelectionAdapter() { + // @Override + // public void widgetSelected(SelectionEvent e) { + // displayColorMgrDlg(); + // } + // }); } /** * Handle the check button event. - * + * * @param btn * Check box being checked/unchecked. */ @@ -278,13 +301,13 @@ public class GroupingComp extends Composite implements IGroupSelection { /** * Handle the color label that is being clicked. - * + * * @param lbl * Label that was clicked. */ private void handleLabelClickEvent(Label lbl) { RGB rgb = lbl.getBackground().getRGB(); - String key = (String) lbl.getData(); + String key = ((SelectionEntry) lbl.getData()).toString(); ColorDialog colorDlg = new ColorDialog(this.getShell()); colorDlg.setRGB(rgb); @@ -343,36 +366,30 @@ public class GroupingComp extends Composite implements IGroupSelection { if (selectionMangerDlg == null || selectionMangerDlg.isDisposed()) { selectionMangerDlg = new SelectionManagerDlg(getShell(), graphData, this); - selectionMangerDlg.open(); - } else { - selectionMangerDlg.bringToTop(); } + + selectionMangerDlg.open(); } /** * Display the Color Manager dialog. */ // Implementing in the next release. -// private void displayColorMgrDlg() { -// ColorManagerDlg dlg = new ColorManagerDlg(getShell(), graphData, this); -// dlg.open(); -// } + // private void displayColorMgrDlg() { + // ColorManagerDlg dlg = new ColorManagerDlg(getShell(), graphData, this); + // dlg.open(); + // } /** * {@inheritDoc} */ @Override public void setSelections(Map> selectionMap) { - List keySequence = graphData.getKeySequence(); - - Map> offMap = new HashMap>(); + Multimap offMap = ArrayListMultimap.create(); for (String key : selectionMap.keySet()) { for (String selection : selectionMap.get(key).keySet()) { if (!selectionMap.get(key).get(selection)) { - if (!offMap.containsKey(key)) { - offMap.put(key, new ArrayList()); - } - offMap.get(key).add(selection); + offMap.put(key, selection); } } } @@ -385,19 +402,18 @@ public class GroupingComp extends Composite implements IGroupSelection { } } else { for (String btnKey : checkBtnMap.keySet()) { - String[] parts = colonPattern.split(btnKey); + Button b = checkBtnMap.get(btnKey); + SelectionEntry se = (SelectionEntry) b.getData(); - for (String group : offMap.keySet()) { - for (String part : parts) { - int idx = keySequence.indexOf(part); - if (idx >= 0 && offMap.get(group).contains(keySequence.get(idx))) { - checkBtnMap.get(btnKey).setSelection(false); - keyRgbMap.remove(btnKey); - } else { - checkBtnMap.get(btnKey).setSelection(true); - keyRgbMap.put(btnKey, labelMap.get(btnKey) - .getBackground().getRGB()); - } + for (String key : offMap.keySet()) { + Collection valueList = offMap.get(key); + if (valueList.contains(se.getValue(key))) { + checkBtnMap.get(btnKey).setSelection(false); + keyRgbMap.remove(btnKey); + } else { + checkBtnMap.get(btnKey).setSelection(true); + keyRgbMap.put(btnKey, labelMap.get(btnKey) + .getBackground().getRGB()); } } } @@ -405,4 +421,33 @@ public class GroupingComp extends Composite implements IGroupSelection { fireCallback(); } + + /** + * {@inheritDoc} + */ + @Override + public void setItemsOff(List keys) { + for (String key : keys) { + if (checkBtnMap.containsKey(key)) { + checkBtnMap.get(key).setSelection(false); + keyRgbMap.remove(key); + } + } + + fireCallback(); + } + + /** + * {@inheritDoc} + */ + @Override + public Map getStates() { + Map stateMap = new HashMap(); + + for (Map.Entry state : checkBtnMap.entrySet()) { + stateMap.put(state.getKey(), state.getValue().getSelection()); + } + + return stateMap; + } } diff --git a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/HideDlg.java b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/HideDlg.java new file mode 100644 index 0000000000..82c9893bb2 --- /dev/null +++ b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/HideDlg.java @@ -0,0 +1,161 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.stats.ui; + +import java.util.Arrays; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Layout; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; + +import com.raytheon.viz.ui.dialogs.CaveSWTDialog; + +/** + * Hide graph lines dialog. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 4, 2012    1357     mpduff      Initial creation.
+ * 
+ * 
+ * + * @author mpduff + * @version 1.0 + */ + +public class HideDlg extends CaveSWTDialog { + /** Data List Widget */ + private List dataList; + + /** List of keys */ + private final java.util.List keyList; + + /** Callback to hide the lines */ + private final IGroupSelection callback; + + /** + * Constructor. + * + * @param parent + * The parent shell + * @param keyList + * The list of keys + * @param callback + * the callback + */ + public HideDlg(Shell parent, java.util.List keyList, + IGroupSelection callback) { + super(parent); + setText("Hide Graph Lines"); + + this.keyList = keyList; + this.callback = callback; + } + + /** + * {@inheritDoc} + */ + @Override + protected Layout constructShellLayout() { + // Create the main layout for the shell. + GridLayout mainLayout = new GridLayout(1, true); + mainLayout.marginHeight = 1; + mainLayout.marginWidth = 1; + return mainLayout; + } + + /** + * {@inheritDoc} + */ + @Override + protected void initializeComponents(Shell shell) { + setReturnValue(false); + + Composite mainComp = new Composite(shell, SWT.NONE); + GridLayout gl = new GridLayout(1, false); + gl.marginHeight = 0; + gl.marginWidth = 0; + gl.horizontalSpacing = 0; + gl.verticalSpacing = 5; + GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); + mainComp.setLayout(gl); + mainComp.setLayoutData(gd); + + GridData listData = new GridData(SWT.FILL, SWT.FILL, true, true); + listData.widthHint = 200; + listData.heightHint = 300; + dataList = new List(mainComp, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL + | SWT.H_SCROLL); + dataList.setLayoutData(listData); + dataList.setItems(keyList.toArray(new String[keyList.size()])); + + Composite buttonComp = new Composite(shell, SWT.NONE); + buttonComp.setLayout(new GridLayout(2, false)); + buttonComp.setLayoutData(new GridData(SWT.CENTER, SWT.DEFAULT, true, + false)); + + int buttonWidth = 120; + gd = new GridData(buttonWidth, SWT.DEFAULT); + Button hideBtn = new Button(buttonComp, SWT.PUSH); + hideBtn.setText("Hide Graph Lines"); + hideBtn.setLayoutData(gd); + hideBtn.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + handleHide(); + } + }); + + gd = new GridData(buttonWidth, SWT.DEFAULT); + Button closeBtn = new Button(buttonComp, SWT.PUSH); + closeBtn.setText("Close"); + closeBtn.setLayoutData(gd); + closeBtn.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + close(); + } + }); + } + + /** + * Hide event handler + */ + private void handleHide() { + if (dataList.getSelectionCount() > 0) { + String[] itemsToHide = dataList.getSelection(); + callback.setItemsOff(Arrays.asList(itemsToHide)); + for (String item : itemsToHide) { + dataList.remove(item); + } + } + } +} diff --git a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/IGroupSelection.java b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/IGroupSelection.java index e6ba63b898..9f546562d2 100644 --- a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/IGroupSelection.java +++ b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/IGroupSelection.java @@ -19,21 +19,23 @@ **/ package com.raytheon.uf.viz.stats.ui; +import java.util.List; import java.util.Map; /** * Interface for Group Selections. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Oct 18, 2012    728     mpduff     Initial creation
- *
+ * Oct 18, 2012    728     mpduff      Initial creation.
+ * Jan 17, 2013   1357     mpduff      Added setItemsOff and getStates.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -41,8 +43,23 @@ import java.util.Map; public interface IGroupSelection { /** * Set the selections. - * + * * @param selectionMap */ void setSelections(Map> selectionMap); + + /** + * Turn off the provided items. + * + * @param keys + * keys of the items to not draw + */ + void setItemsOff(List keys); + + /** + * Get the state of each item. + * + * @return Map of item -> checked or not checked + */ + Map getStates(); } diff --git a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/IStatsDisplay.java b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/IStatsDisplay.java index 12afff43ba..49ef4ef9a1 100644 --- a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/IStatsDisplay.java +++ b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/IStatsDisplay.java @@ -24,21 +24,21 @@ import java.util.Map; import org.eclipse.swt.graphics.RGB; import com.raytheon.uf.common.stats.data.GraphData; - +import com.raytheon.uf.common.stats.util.UnitUtils; /** * Stats display interface. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Oct 3, 2012     728     mpduff      Initial creation
- *
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -46,29 +46,36 @@ import com.raytheon.uf.common.stats.data.GraphData; public interface IStatsDisplay { /** * Get the GraphData object - * + * * @return GraphData */ GraphData getGraphData(); /** * Draw grid lines flag - * + * * @return true to draw the grid lines */ boolean drawGridLines(); /** * Draw data lines flag - * + * * @return true to draw the data lines */ boolean drawDataLines(); /** * Get the group settings. - * + * * @return The group settings map */ Map getGroupSettings(); + + /** + * Get the UnitUtils object. + * + * @return the UnitUtils object + */ + UnitUtils getUnitUtils(); } diff --git a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/SelectionEntry.java b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/SelectionEntry.java new file mode 100644 index 0000000000..b8b4620c8e --- /dev/null +++ b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/SelectionEntry.java @@ -0,0 +1,87 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.stats.ui; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Stats Graph Item. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 24, 2013            mpduff     Initial creation
+ * 
+ * 
+ * + * @author mpduff + * @version 1.0 + */ +public class SelectionEntry { + private final Map values = new LinkedHashMap(); + + private boolean checked = true; + + public SelectionEntry() { + + } + + public void addPair(String key, String value) { + values.put(key, value); + } + + public String getValue(String key) { + return values.get(key); + } + + /** + * @return the checked + */ + public boolean isChecked() { + return checked; + } + + /** + * @param checked + * the checked to set + */ + public void setChecked(boolean checked) { + this.checked = checked; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + for (Iterator iter = values.values().iterator(); iter.hasNext();) { + sb.append(iter.next()); + if (iter.hasNext()) { + sb.append(":"); + } + } + + return sb.toString(); + } +} diff --git a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/SelectionManagerDlg.java b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/SelectionManagerDlg.java index 71f48ae27d..d12231d3c5 100644 --- a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/SelectionManagerDlg.java +++ b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/SelectionManagerDlg.java @@ -21,8 +21,10 @@ package com.raytheon.uf.viz.stats.ui; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; @@ -44,17 +46,18 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialogBase; /** * Stats Selection Manager Dialog. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Oct 18, 2012            lvenable     Initial creation
- *
+ * Oct 18, 2012            lvenable    Initial creation
+ * Jan 17, 2013  1357      mpduff      Added selection state handling.
+ * 
  * 
- * + * * @author lvenable * @version 1.0 */ @@ -74,9 +77,9 @@ public class SelectionManagerDlg extends CaveSWTDialogBase { /** * Constructor. - * + * * @param parentShell - * @param graphData + * @param selectionEntries * @param callback */ public SelectionManagerDlg(Shell parentShell, GraphData graphData, @@ -86,8 +89,8 @@ public class SelectionManagerDlg extends CaveSWTDialogBase { | CAVE.INDEPENDENT_SHELL); setText("Selection Manager"); - this.graphData = graphData; this.callback = callback; + this.graphData = graphData; } /** @@ -202,7 +205,7 @@ public class SelectionManagerDlg extends CaveSWTDialogBase { /** * Check the path of the item. - * + * * @param item * @param checked * @param grayed @@ -232,7 +235,7 @@ public class SelectionManagerDlg extends CaveSWTDialogBase { /** * Check or uncheck the items in the TreeItem - * + * * @param item * @param checked */ @@ -261,10 +264,27 @@ public class SelectionManagerDlg extends CaveSWTDialogBase { for (String subKey : array) { TreeItem subTreeItem = new TreeItem(treeItem, SWT.NONE); subTreeItem.setText(subKey); - subTreeItem.setChecked(true); } } + + // Determine group checkbox setting, unchecked, grayed, checked + TreeItem[] children = selectionTree.getItems(); + Set selectionSet = new HashSet(); + for (TreeItem item : children) { + item.setChecked(true); + for (TreeItem subItem : item.getItems()) { + selectionSet.add(subItem.getChecked()); + } + + if (selectionSet.contains(Boolean.TRUE) + && selectionSet.contains(Boolean.FALSE)) { + item.setChecked(true); + item.setGrayed(true); + } else if (!selectionSet.contains(Boolean.TRUE)) { + item.setChecked(false); + } + } } /** @@ -314,6 +334,5 @@ public class SelectionManagerDlg extends CaveSWTDialogBase { } else { callback.setSelections(selectionMap); } - } } diff --git a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsControlDlg.java b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsControlDlg.java index 013b15fec7..62e63e59f1 100644 --- a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsControlDlg.java +++ b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsControlDlg.java @@ -69,7 +69,8 @@ import com.raytheon.viz.ui.widgets.duallist.IUpdate; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Sep 25, 2012 mpduff Initial creation + * Sep 25, 2012 1357 mpduff Initial creation. + * Jan 17, 2013 1357 mpduff Added timestep settings. * *
* @@ -92,7 +93,7 @@ public class StatsControlDlg extends CaveSWTDialog implements IStatsControl, TimeUtil.MILLIS_PER_HOUR * 3, TimeUtil.MILLIS_PER_HOUR * 6, TimeUtil.MILLIS_PER_HOUR * 12, TimeUtil.MILLIS_PER_DAY, TimeUtil.MILLIS_PER_WEEK, TimeUtil.MILLIS_PER_WEEK * 2, - TimeUtil.MILLIS_PER_MONTH }; + TimeUtil.MILLIS_PER_30_DAYS }; /** Date Format object */ private final ThreadLocal sdf = new ThreadLocal() { @@ -619,7 +620,24 @@ public class StatsControlDlg extends CaveSWTDialog implements IStatsControl, } TimeRange tr = new TimeRange(start, end); request.setTimeRange(tr); - request.setTimeStep(5); + + if (tr.getDuration() <= TimeUtil.MILLIS_PER_HOUR) { + request.setTimeStep(5); + } else if (tr.getDuration() <= TimeUtil.MILLIS_PER_HOUR * 3) { + request.setTimeStep(5); + } else if (tr.getDuration() <= TimeUtil.MILLIS_PER_HOUR * 6) { + request.setTimeStep(10); + } else if (tr.getDuration() <= TimeUtil.MILLIS_PER_HOUR * 12) { + request.setTimeStep(20); + } else if (tr.getDuration() <= TimeUtil.MILLIS_PER_HOUR * 24) { + request.setTimeStep(40); + } else if (tr.getDuration() <= TimeUtil.MILLIS_PER_DAY * 7) { + request.setTimeStep(240); + } else if (tr.getDuration() <= TimeUtil.MILLIS_PER_DAY * 14) { + request.setTimeStep(480); + } else { + request.setTimeStep(1000); + } try { GraphDataResponse response = (GraphDataResponse) ThriftClient diff --git a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsDisplayCanvas.java b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsDisplayCanvas.java index b6a26959d7..8ef620b160 100644 --- a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsDisplayCanvas.java +++ b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsDisplayCanvas.java @@ -23,15 +23,19 @@ import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TimeZone; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.PaintEvent; @@ -47,31 +51,41 @@ import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import com.raytheon.uf.common.stats.data.DataPoint; import com.raytheon.uf.common.stats.data.GraphData; import com.raytheon.uf.common.stats.data.StatsData; -import com.raytheon.uf.common.stats.util.DataViewUtils; +import com.raytheon.uf.common.stats.util.DataView; +import com.raytheon.uf.common.stats.util.UnitUtils; +import com.raytheon.uf.common.stats.util.UnitUtils.TimeConversion; +import com.raytheon.uf.common.stats.util.UnitUtils.UnitTypes; import com.raytheon.uf.common.time.TimeRange; import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.common.units.DataSizeUnit; import com.raytheon.uf.viz.core.RGBColors; import com.raytheon.uf.viz.stats.display.ScaleManager; /** * Statistics graph canvas. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Oct 3, 2012     728     mpduff      Initial creation
- *
+ * Oct 03, 2012     728    mpduff      Initial creation.
+ * Jan 17, 2013    1357    mpduff      Added mouse listeners.
+ * Jan 29, 2013    1523    mpduff      Fix for count units.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -106,6 +120,15 @@ public class StatsDisplayCanvas extends Canvas { } }; + /** Decimal Format object */ + private final ThreadLocal decFormat = new ThreadLocal() { + @Override + protected DecimalFormat initialValue() { + DecimalFormat format = new DecimalFormat("########.#"); + return format; + } + }; + /** Constant */ private final String COLON = ":"; @@ -185,21 +208,18 @@ public class StatsDisplayCanvas extends Canvas { /** Tooltip shell */ private Shell tooltip; - /** Graph Data object */ - private GraphData graphData; + /** Data View, avg, min, max, etc. */ + private DataView view = DataView.AVG; - /** Smallest value in the data set */ - private double minValue; + /** Group selection callback */ + private IGroupSelection groupCallback; - /** Largest value in the data set */ - private double maxValue; - - private String view = DataViewUtils.DataView.AVG.getView(); // Defaults to - // average + /** Hide dataset dialog */ + private HideDlg hideDlg; /** * Constructor - * + * * @param parent * Parent composite * @param callback @@ -214,8 +234,7 @@ public class StatsDisplayCanvas extends Canvas { this.callback = callback; this.graphTitle = graphTitle; - this.graphData = callback.getGraphData(); - TimeRange tr = graphData.getTimeRange(); + TimeRange tr = callback.getGraphData().getTimeRange(); String start = titleDateFormat.get().format(tr.getStart()); String end = titleDateFormat.get().format(tr.getEnd()); @@ -258,11 +277,18 @@ public class StatsDisplayCanvas extends Canvas { handleMouseMoveEvent(e); } }); + + addMouseListener(new MouseAdapter() { + @Override + public void mouseDown(MouseEvent e) { + handleMouseDownEvent(e); + } + }); } /** * Initialize drawing settings. - * + * * @param gc * The Graphics Context */ @@ -280,7 +306,7 @@ public class StatsDisplayCanvas extends Canvas { /** * Draw on the canvas. - * + * * @param gc * The Graphics Context */ @@ -327,7 +353,7 @@ public class StatsDisplayCanvas extends Canvas { /** * Draw the X axis. - * + * * @param gc * The Graphics Context */ @@ -342,8 +368,7 @@ public class StatsDisplayCanvas extends Canvas { List dateList = new ArrayList(); SimpleDateFormat sdf = axisFormat.get(); - - TimeRange tr = graphData.getTimeRange(); + TimeRange tr = callback.getGraphData().getTimeRange(); dateList.add(tr.getStart()); // Add the first date long milliRange = tr.getDuration(); @@ -356,24 +381,29 @@ public class StatsDisplayCanvas extends Canvas { long startMillis = tr.getStart().getTime(); StringBuilder buffer = new StringBuilder(); - Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + Calendar cal = TimeUtil.newGmtCalendar(); for (long i = tr.getStart().getTime(); i <= tr.getEnd().getTime(); i += TimeUtil.MILLIS_PER_HOUR) { cal.setTimeInMillis(i); int[] tickArray = { - (int) (GRAPH_BORDER + (i - startMillis) / millisPerPixelX), + Math.round(GRAPH_BORDER + (i - startMillis) + / millisPerPixelX), GRAPH_BORDER + GRAPH_HEIGHT, - (int) (GRAPH_BORDER + (i - startMillis) / millisPerPixelX), + Math.round(GRAPH_BORDER + (i - startMillis) + / millisPerPixelX), GRAPH_BORDER + GRAPH_HEIGHT + height }; - if (cal.get(Calendar.HOUR_OF_DAY) == 0) { + if (cal.get(Calendar.HOUR_OF_DAY) == 0 + && cal.get(Calendar.MINUTE) == 0) { gc.setLineWidth(3); } else { gc.setLineWidth(1); } int hour = cal.get(Calendar.HOUR_OF_DAY); + // Draw the tick marks if ((numHours / 24 <= 7) || (hour % 6) == 0) { gc.drawPolyline(tickArray); + // Draw grid lines if (callback.drawGridLines()) { boolean draw = false; if (numHours <= 6) { @@ -386,19 +416,20 @@ public class StatsDisplayCanvas extends Canvas { if (draw) { int[] gridLine = new int[] { - (int) (GRAPH_BORDER + (i - startMillis) + Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX), GRAPH_BORDER + GRAPH_HEIGHT, - (int) (GRAPH_BORDER + (i - startMillis) + Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX), GRAPH_BORDER }; gc.drawPolyline(gridLine); } } } + // Save the Zero hour for later if (hour == 0) { - dateLocationList.add((int) (GRAPH_BORDER + (i - startMillis) - / millisPerPixelX)); + dateLocationList.add(Math.round(GRAPH_BORDER + + (i - startMillis) / millisPerPixelX)); if (!dateList.contains(cal.getTime())) { dateList.add(cal.getTime()); } @@ -406,22 +437,28 @@ public class StatsDisplayCanvas extends Canvas { buffer.setLength(0); // Clear the buffer int y = GRAPH_BORDER + GRAPH_HEIGHT + 20; int hr = cal.get(Calendar.HOUR_OF_DAY); + int minute = cal.get(Calendar.MINUTE); + + // Draw the tick marks if ((numHours <= 24) || (hour % 6 == 0 && numHours <= 168)) { if (numHours <= 3) { - for (int j = 0; j < 60; j += 15) { + for (int j = 0; j < TimeUtil.MINUTES_PER_HOUR; j += 15) { + buffer.setLength(0); - int x = (int) (GRAPH_BORDER + (i - startMillis + j - * TimeUtil.MILLIS_PER_MINUTE) + int x = Math.round(GRAPH_BORDER + + (i - startMillis + j + * TimeUtil.MILLIS_PER_MINUTE) / millisPerPixelX); if (numHours == 1 || (numHours == 3 && (j == 0 || j == 30))) { String hrStr = (hr < 10) ? ZERO.concat(String .valueOf(hr)) : String.valueOf(hr); - if (j == 0) { + if (minute == 0) { buffer.append(hrStr).append(COLON) .append(MINUTE_00); } else { - buffer.append(hrStr).append(COLON).append(j); + buffer.append(hrStr).append(COLON) + .append(minute); } int adjustment = buffer.length() * fontAveWidth / 2 - 1; @@ -429,30 +466,46 @@ public class StatsDisplayCanvas extends Canvas { if (callback.drawGridLines()) { int[] gridLineArray = { - (int) (GRAPH_BORDER + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE - * j) - / millisPerPixelX), + Math.round(GRAPH_BORDER + + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE + * j) / millisPerPixelX), GRAPH_BORDER + GRAPH_HEIGHT, - (int) (GRAPH_BORDER + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE - * j) - / millisPerPixelX), + Math.round(GRAPH_BORDER + + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE + * j) / millisPerPixelX), GRAPH_BORDER }; + if (hr == 0 && minute == 0) { + gc.setLineWidth(3); + } gc.drawPolyline(gridLineArray); + gc.setLineWidth(1); + } + minute += 15; + // Roll the minutes and hours, account for rolling + // to the next hour/minute + if (minute >= TimeUtil.MINUTES_PER_HOUR) { + minute = 0; + hr++; + if (hr == TimeUtil.HOURS_PER_DAY) { + hr = 0; + } } } + + // Minor tick marks int[] minorTickArray = { - (int) (GRAPH_BORDER + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE - * j) - / millisPerPixelX), + Math.round(GRAPH_BORDER + + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE + * j) / millisPerPixelX), GRAPH_BORDER + GRAPH_HEIGHT, - (int) (GRAPH_BORDER + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE - * j) - / millisPerPixelX), + Math.round(GRAPH_BORDER + + (i - startMillis + TimeUtil.MILLIS_PER_MINUTE + * j) / millisPerPixelX), GRAPH_BORDER + GRAPH_HEIGHT + height - 5 }; gc.drawPolyline(minorTickArray); } } else { - int x = (int) (GRAPH_BORDER + (i - startMillis) + int x = Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX); String hrStr = (hr < 10) ? ZERO.concat(String.valueOf(hr)) : String.valueOf(hr); @@ -462,13 +515,13 @@ public class StatsDisplayCanvas extends Canvas { if (callback.drawGridLines()) { if ((numHours == 24 && hr % 6 == 0) - || (numHours == 168 && hr == 0)) { + || (numHours == TimeUtil.HOURS_PER_WEEK && hr == 0)) { int[] gridLineArray = { - (int) (GRAPH_BORDER + (i - startMillis) + Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX), GRAPH_BORDER + GRAPH_HEIGHT, - (int) (GRAPH_BORDER + (i - startMillis) + Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX), GRAPH_BORDER }; gc.setLineWidth(1); gc.drawPolyline(gridLineArray); @@ -477,7 +530,7 @@ public class StatsDisplayCanvas extends Canvas { } } } else if (numHours == 336 && hour == 0) { - int x = (int) (GRAPH_BORDER + (i - startMillis) + int x = Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX); buffer.append(cal.get(Calendar.MONTH) + 1); buffer.append("/"); @@ -489,10 +542,10 @@ public class StatsDisplayCanvas extends Canvas { // show every other line if (showLine) { int[] gridLineArray = { - (int) (GRAPH_BORDER + (i - startMillis) + Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX), GRAPH_BORDER + GRAPH_HEIGHT, - (int) (GRAPH_BORDER + (i - startMillis) + Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX), GRAPH_BORDER }; gc.setLineWidth(1); gc.drawPolyline(gridLineArray); @@ -503,7 +556,7 @@ public class StatsDisplayCanvas extends Canvas { } else if (numHours == 720) { if (cal.get(Calendar.DAY_OF_MONTH) % 2 == 0 && hour == 0) { - int x = (int) (GRAPH_BORDER + (i - startMillis) + int x = Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX); buffer.append(cal.get(Calendar.MONTH) + 1); buffer.append("/"); @@ -513,10 +566,10 @@ public class StatsDisplayCanvas extends Canvas { if (callback.drawGridLines()) { if (showLine) { int[] gridLineArray = { - (int) (GRAPH_BORDER + (i - startMillis) + Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX), GRAPH_BORDER + GRAPH_HEIGHT, - (int) (GRAPH_BORDER + (i - startMillis) + Math.round(GRAPH_BORDER + (i - startMillis) / millisPerPixelX), GRAPH_BORDER }; gc.setLineWidth(1); gc.drawPolyline(gridLineArray); @@ -556,7 +609,7 @@ public class StatsDisplayCanvas extends Canvas { /** * Draw the Y axis. - * + * * @param gc * The Graphics Context */ @@ -568,14 +621,21 @@ public class StatsDisplayCanvas extends Canvas { gc.drawPolyline(yAxis); Map groupSettings = callback.getGroupSettings(); - + GraphData graphData = callback.getGraphData(); double minVal = graphData.getMinValue(groupSettings.keySet(), view); double maxVal = graphData.getMaxValue(groupSettings.keySet(), view); + if (view != DataView.COUNT) { + UnitUtils uu = callback.getUnitUtils(); + minVal = uu.convertValue(minVal); + maxVal = uu.convertValue(maxVal); + } + + setScaleValues(minVal, maxVal); + int numberTicks = 4; double inc = 5; double minScaleVal = 0; double maxScaleVal = 10; - scalingManager = new ScaleManager(minVal, maxVal); numberTicks = scalingManager.getMajorTickCount(); inc = scalingManager.getMajorTickIncrement(); @@ -607,16 +667,18 @@ public class StatsDisplayCanvas extends Canvas { /** * Draw the YAxis label. - * + * * @param gc * The Graphics Context */ private void drawYAxisLabel(GC gc) { - String unit = this.graphData.getDisplayUnit(); + GraphData graphData = callback.getGraphData(); + String unit = graphData.getDisplayUnit(); StringBuilder yAxisLabel = new StringBuilder(graphTitle); - if (unit != null && !unit.equalsIgnoreCase(COUNT) && unit.length() > 0 - && !view.equals(DataViewUtils.DataView.COUNT.getView())) { + if (isCount(unit)) { + yAxisLabel.append(" Counts"); + } else { yAxisLabel.append(" (").append(unit).append(")"); } @@ -637,9 +699,13 @@ public class StatsDisplayCanvas extends Canvas { t.dispose(); } + private boolean isCount(String unit) { + return view.equals(DataView.COUNT) || COUNT.equalsIgnoreCase(unit); + } + /** * Draw the data on the canvas. - * + * * @param gc * The Graphics Context */ @@ -647,6 +713,8 @@ public class StatsDisplayCanvas extends Canvas { double maxScaleVal = scalingManager.getMaxScaleValue(); double minScaleVal = scalingManager.getMinScaleValue(); Map groupSettings = callback.getGroupSettings(); + UnitUtils uu = callback.getUnitUtils(); + GraphData graphData = callback.getGraphData(); for (String key : graphData.getKeysWithData()) { if (groupSettings.containsKey(key)) { @@ -672,30 +740,27 @@ public class StatsDisplayCanvas extends Canvas { int lastYpix = -999; for (DataPoint point : dataList) { long x = point.getX(); - double y; + double y = point.getValue(view); - if (view.equals(DataViewUtils.DataView.AVG - .getView())) { - y = point.getAvg(); - } else if (view.equals(DataViewUtils.DataView.MIN - .getView())) { - y = point.getMin(); - } else if (view.equals(DataViewUtils.DataView.MAX - .getView())) { - y = point.getMax(); - } else if (view.equals(DataViewUtils.DataView.SUM - .getView())) { - y = point.getSum(); - } else { - y = point.getCount(); + if (view != DataView.COUNT) { + y = uu.convertValue(y); } + + int xPix = 0; int yPix = y2pixel(minScaleVal, maxScaleVal, y); - int xPix = (int) ((x - startMillis) - / millisPerPixelX + GRAPH_BORDER); + + long diff = x - startMillis; + if (diff == 0) { + xPix = GRAPH_BORDER; + } else { + xPix = Math + .round((diff / millisPerPixelX + GRAPH_BORDER)); + } if (xPix > GRAPH_BORDER + GRAPH_WIDTH) { - break; + continue; } + pointList.add(xPix); pointList.add(yPix); Rectangle rect = new Rectangle(xPix - 3, yPix - 3, @@ -710,6 +775,7 @@ public class StatsDisplayCanvas extends Canvas { lastYpix = yPix; } + // Draw each rectangle for (int i = 0; i < rectangleMap.get(key).size(); i++) { Rectangle rect = rectangleMap.get(key).get(i); gc.setForeground(color); @@ -727,7 +793,7 @@ public class StatsDisplayCanvas extends Canvas { /** * Y Value to pixel conversion. - * + * * @param yMin * The smallest y value * @param yMax @@ -739,12 +805,12 @@ public class StatsDisplayCanvas extends Canvas { private int y2pixel(double yMin, double yMax, double y) { double yDiff = yMax - yMin; double yValue = (GRAPH_HEIGHT / yDiff) * (y - yMin); - return (int) (GRAPH_HEIGHT - Math.round(yValue) + GRAPH_BORDER); + return Math.round(GRAPH_HEIGHT - Math.round(yValue) + GRAPH_BORDER); } /** * Mouse move event hanler. - * + * * @param e * MouseEvent object */ @@ -758,6 +824,8 @@ public class StatsDisplayCanvas extends Canvas { if (graphData == null) { return; } + + UnitUtils uu = callback.getUnitUtils(); for (String key : graphData.getKeys()) { int idx = 0; if (rectangleMap.containsKey(key)) { @@ -771,7 +839,24 @@ public class StatsDisplayCanvas extends Canvas { sb.append(key).append(colon); DataPoint point = graphData.getStatsData(key) .getData().get(idx); - sb.append(point.getSampleText(view)); + double value = point.getValue(view); + + if (!view.equals(DataView.COUNT)) { + if (uu.getUnitType() == UnitTypes.DATA_SIZE) { + value = uu.convertDataSizeValue( + DataSizeUnit.BYTE, value); + } else if (uu.getUnitType() == UnitTypes.TIME) { + value = uu.convertTimeValue( + TimeConversion.MS, (long) value); + } + } + + SimpleDateFormat dateFormat = titleDateFormat.get(); + DecimalFormat decimalFormat = decFormat.get(); + + sb.append(dateFormat.format(new Date(point.getX()))) + .append("Z, "); + sb.append(decimalFormat.format(value)); } } idx++; @@ -790,9 +875,102 @@ public class StatsDisplayCanvas extends Canvas { } } + private void setScaleValues(double minVal, double maxVal) { + scalingManager = new ScaleManager(minVal, maxVal); + } + + private void handleMouseDownEvent(MouseEvent e) { + if (e.button == 3) { + GraphData graphData = callback.getGraphData(); + if (graphData == null) { + return; + } + + int x = e.x; + int y = e.y; + List keyList = new ArrayList(); + for (String key : graphData.getKeys()) { + if (rectangleMap.containsKey(key)) { + for (Rectangle rect : rectangleMap.get(key)) { + if (callback.getGroupSettings().containsKey(key)) { + // if true then data are on the graph + if (rect.contains(x, y)) { + keyList.add(key); + } + } + } + } + } + + if (!keyList.isEmpty()) { + showPopup(keyList); + } + } + } + + private void showPopup(final List inputList) { + // Remove the tooltip if it is up + if (tooltip != null && !tooltip.isDisposed()) { + tooltip.dispose(); + } + + // Remove any duplicate entries + Set set = new HashSet(inputList); + final List keyList = new ArrayList(set); + Collections.sort(keyList); + + Menu menu = new Menu(this.getShell(), SWT.POP_UP); + + if (keyList.size() == 1) { + MenuItem selectAll = new MenuItem(menu, SWT.NONE); + selectAll.setText("Hide " + keyList.get(0)); + selectAll.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + handleHide(keyList); + } + }); + } else if (keyList.size() > 1) { + MenuItem hideAll = new MenuItem(menu, SWT.NONE); + hideAll.setText("Hide All Data At Point"); + hideAll.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + handleHide(keyList); + } + }); + + new MenuItem(menu, SWT.SEPARATOR); + + MenuItem hideGraphDlgMI = new MenuItem(menu, SWT.NONE); + hideGraphDlgMI.setText("Hide Graph Lines..."); + hideGraphDlgMI.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + showHideDlg(keyList); + } + }); + } + + // We need to make the menu visible + menu.setVisible(true); + } + + private void handleHide(List keyList) { + groupCallback.setItemsOff(keyList); + redraw(); + } + + private void showHideDlg(List keyList) { + if (hideDlg == null || hideDlg.isDisposed()) { + this.hideDlg = new HideDlg(getShell(), keyList, groupCallback); + } + hideDlg.open(); + } + /** * Show the "tooltip" mouseover. - * + * * @param parent * @param x * @param y @@ -824,7 +1002,7 @@ public class StatsDisplayCanvas extends Canvas { /* * (non-Javadoc) - * + * * @see org.eclipse.swt.widgets.Widget#dispose() */ @Override @@ -836,20 +1014,20 @@ public class StatsDisplayCanvas extends Canvas { } /** - * Set the graph data. - * - * @param graphData - * The GraphData object + * @param view + * The view type */ - public void setGraphData(GraphData graphData) { - this.graphData = graphData; + public void setView(DataView view) { + this.view = view; } /** - * Set the view type. - * @param view The view type + * Set the group selection callback. + * + * @param groupCallback + * The group callback */ - public void setView(String view) { - this.view = view; + public void setCallback(IGroupSelection groupCallback) { + this.groupCallback = groupCallback; } } diff --git a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsGraphDlg.java b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsGraphDlg.java index 1a9e209d87..172f9daba3 100644 --- a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsGraphDlg.java +++ b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsGraphDlg.java @@ -20,24 +20,21 @@ package com.raytheon.uf.viz.stats.ui; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.ImageLoader; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Menu; @@ -48,7 +45,8 @@ import org.eclipse.swt.widgets.Shell; import com.raytheon.uf.common.stats.GraphDataRequest; import com.raytheon.uf.common.stats.GraphDataResponse; import com.raytheon.uf.common.stats.data.GraphData; -import com.raytheon.uf.common.stats.util.DataViewUtils; +import com.raytheon.uf.common.stats.util.DataView; +import com.raytheon.uf.common.stats.util.UnitUtils; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; @@ -61,17 +59,19 @@ import com.raytheon.viz.ui.widgets.duallist.ButtonImages.ButtonImage; /** * The Graph Data Structure. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Oct 3, 2012     728     mpduff      Initial creation
- *
+ * Oct 03, 2012     728    mpduff      Initial creation.
+ * Jan 17, 2013    1357    mpduff      Add ability to change units.
+ * Jan 18, 2013    1386    mpduff      Change menu text.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -101,8 +101,8 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, /** Menu bar */ private Menu menuBar; - /** Save Menu Item */ - private MenuItem saveMI; + // /** Save Menu Item */ + // private MenuItem saveMI; /** Exit Menu item */ private MenuItem exitMI; @@ -143,9 +143,17 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, /** Data view combo */ private Combo viewCombo; + /** Menu item map */ + private final Map menuItemMap = new HashMap(); + + /** The currently displayed unit */ + private String displayUnit; + + private UnitUtils unitUtils; + /** * Constructor. - * + * * @param parent * Parent Shell * @param callback @@ -204,6 +212,8 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, groupComp.setLayout(gl); groupComp.setLayoutData(gd); + displayCanvas.setCallback(groupComp); + gd = new GridData(SWT.FILL, SWT.DEFAULT, false, true); gl = new GridLayout(2, false); Composite ctrlComp = new Composite(leftComp, SWT.NONE); @@ -220,11 +230,11 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, graphLabel.setText("Graph: "); List viewList = new ArrayList(); - viewList.add(DataViewUtils.DataView.AVG.getView()); - viewList.add(DataViewUtils.DataView.MIN.getView()); - viewList.add(DataViewUtils.DataView.MAX.getView()); - viewList.add(DataViewUtils.DataView.SUM.getView()); - viewList.add(DataViewUtils.DataView.COUNT.getView()); + viewList.add(DataView.AVG.getView()); + viewList.add(DataView.MIN.getView()); + viewList.add(DataView.MAX.getView()); + viewList.add(DataView.SUM.getView()); + viewList.add(DataView.COUNT.getView()); gd = new GridData(SWT.LEFT, SWT.CENTER, true, false); viewCombo = new Combo(dataComp, SWT.READ_ONLY); @@ -314,15 +324,15 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, Menu fileMenu = new Menu(menuBar); fileMenuItem.setMenu(fileMenu); - saveMI = new MenuItem(fileMenu, SWT.NONE); - saveMI.setText("&Save\tCtrl+S"); - saveMI.setAccelerator(SWT.CTRL + 'S'); - saveMI.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent event) { - saveGraph(); - } - }); + // saveMI = new MenuItem(fileMenu, SWT.NONE); + // saveMI.setText("&Save Graph Image\tCtrl+S"); + // saveMI.setAccelerator(SWT.CTRL + 'S'); + // saveMI.addSelectionListener(new SelectionAdapter() { + // @Override + // public void widgetSelected(SelectionEvent event) { + // saveGraph(); + // } + // }); exitMI = new MenuItem(fileMenu, SWT.NONE); exitMI.setText("&Quit\tCtrl+Q"); @@ -371,11 +381,63 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, displayCanvas.redraw(); } }); + + // Set up the display units menu choices + MenuItem unitsMI = new MenuItem(graphMenu, SWT.CASCADE); + unitsMI.setText("Display Units"); + + unitUtils = new UnitUtils(graphData.getEventType(), + graphData.getDataType()); + String displayUnit = graphData.getDisplayUnit(); + unitUtils.setUnitType(displayUnit); + unitUtils.setDisplayUnit(displayUnit); + Set units = unitUtils.getUnitOptions(); + + Menu unitsMenu = new Menu(graphMenu); + unitsMI.setMenu(unitsMenu); + + for (String unit : units) { + MenuItem mi = new MenuItem(unitsMenu, SWT.CHECK); + mi.setText(unit); + if (unit.equals(graphData.getDisplayUnit())) { + mi.setSelection(true); + } + mi.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + handleUnitsSelection(e); + } + }); + + menuItemMap.put(unit, mi); + } + } + + /** + * Handle the unit selection event. + * + * @param e + * The selection event + */ + private void handleUnitsSelection(SelectionEvent e) { + MenuItem m = (MenuItem) e.getSource(); + for (Entry es : menuItemMap.entrySet()) { + MenuItem mi = es.getValue(); + if (es.getKey().equals(m.getText())) { + m.setSelection(true); + displayUnit = m.getText(); + unitUtils.setDisplayUnit(displayUnit); + graphData.setDisplayUnit(displayUnit); + displayCanvas.redraw(); + } else { + mi.setSelection(false); + } + } } /** * Create the canvas. - * + * * @param comp * Composite holding the canvas */ @@ -395,7 +457,7 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, /** * Set the GraphData object. - * + * * @param graphData */ public void setGraphData(GraphData graphData) { @@ -412,7 +474,7 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, /** * Set the title. - * + * * @param title */ public void setTitle(String title) { @@ -421,66 +483,66 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, /** * Set the graph title. - * + * * @param graphTitle */ public void setGraphTitle(String graphTitle) { this.graphTitle = graphTitle; } - /** - * Open a file dialog for saving the canvas. - */ - private void saveGraph() { - FileDialog dialog = new FileDialog(shell, SWT.SAVE); - String filename = dialog.open(); - if (filename == null) { - return; - } - saveCanvas(filename); - } + // /** + // * Open a file dialog for saving the canvas. + // */ + // private void saveGraph() { + // FileDialog dialog = new FileDialog(shell, SWT.SAVE); + // String filename = dialog.open(); + // if (filename == null) { + // return; + // } + // saveCanvas(filename); + // } - /** - * Captures the canvas and saves the result into a file in a format - * determined by the filename extension . - * - * @param control - * The control to save - * @param fileName - * The name of the image to be saved - */ - public void saveCanvas(String filename) { - StringBuilder sb = new StringBuilder(); - Display display = displayCanvas.getDisplay(); - Image image = new Image(display, displayCanvas.getBounds().width, - displayCanvas.getBounds().height); - GC gc = new GC(image); - - displayCanvas.drawCanvas(gc); - - /* Default to PNG */ - int style = SWT.IMAGE_PNG; - - if ((filename.endsWith(".jpg") == true) || filename.endsWith("jpeg")) { - style = SWT.IMAGE_JPEG; - } else if (filename.endsWith(".bmp") == true) { - style = SWT.IMAGE_BMP; - } else { - filename += ".png"; - } - - ImageLoader loader = new ImageLoader(); - loader.data = new ImageData[] { image.getImageData() }; - loader.save(filename, style); - - sb.setLength(0); - image.dispose(); - gc.dispose(); - } + // /** + // * Captures the canvas and saves the result into a file in a format + // * determined by the filename extension . + // * + // * @param control + // * The control to save + // * @param fileName + // * The name of the image to be saved + // */ + // public void saveCanvas(String filename) { + // StringBuilder sb = new StringBuilder(); + // Display display = displayCanvas.getDisplay(); + // Image image = new Image(display, displayCanvas.getBounds().width, + // displayCanvas.getBounds().height); + // GC gc = new GC(image); + // + // displayCanvas.drawCanvas(gc); + // + // /* Default to PNG */ + // int style = SWT.IMAGE_PNG; + // + // if ((filename.endsWith(".jpg") == true) || filename.endsWith("jpeg")) { + // style = SWT.IMAGE_JPEG; + // } else if (filename.endsWith(".bmp") == true) { + // style = SWT.IMAGE_BMP; + // } else { + // filename += ".png"; + // } + // + // ImageLoader loader = new ImageLoader(); + // loader.data = new ImageData[] { image.getImageData() }; + // loader.save(filename, style); + // + // sb.setLength(0); + // image.dispose(); + // gc.dispose(); + // } /** * Request the graph be redrawn with a new time range. - * + * * @param parameter * The amount of time to move */ @@ -516,7 +578,6 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, default: return; } - GraphDataRequest request = new GraphDataRequest(); request.setGrouping(this.groupList); request.setCategory(this.category); @@ -525,7 +586,7 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, request.setField(dataTypeID); TimeRange newTimeRange = new TimeRange(newStart, newEnd); request.setTimeRange(newTimeRange); - request.setTimeStep(5); + request.setTimeStep((int) graphData.getTimeStep()); try { GraphDataResponse response = (GraphDataResponse) ThriftClient .sendRequest(request); @@ -544,7 +605,6 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, } this.graphData = localGraphData; - this.displayCanvas.setGraphData(graphData); this.displayCanvas.redraw(); } catch (VizException e) { this.statusHandler.handle(Priority.ERROR, "Error Requesting Data", @@ -556,7 +616,8 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, * Handler for data view combo box change. */ private void handleDataViewChange() { - String view = viewCombo.getText(); + String viewStr = viewCombo.getText(); + DataView view = DataView.fromString(viewStr); this.displayCanvas.setView(view); this.displayCanvas.redraw(); } @@ -596,7 +657,7 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, /** * Set the groups. - * + * * @param groupList * List of groups */ @@ -606,7 +667,7 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, /** * Set the category. - * + * * @param category */ public void setCategory(String category) { @@ -615,7 +676,7 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, /** * Set the event type. - * + * * @param typeID */ public void setEventType(String typeID) { @@ -624,10 +685,18 @@ public class StatsGraphDlg extends CaveSWTDialog implements IStatsDisplay, /** * Set the data type id. - * + * * @param dataTypeID */ public void setDataType(String dataTypeID) { this.dataTypeID = dataTypeID; } + + /** + * {@inheritDoc} + */ + @Override + public UnitUtils getUnitUtils() { + return this.unitUtils; + } } diff --git a/cave/com.raytheon.uf.viz.thinclient.cave/src/com/raytheon/uf/viz/thinclient/cave/ThinClientComponent.java b/cave/com.raytheon.uf.viz.thinclient.cave/src/com/raytheon/uf/viz/thinclient/cave/ThinClientComponent.java index 7a7b439666..f2a2ff1134 100644 --- a/cave/com.raytheon.uf.viz.thinclient.cave/src/com/raytheon/uf/viz/thinclient/cave/ThinClientComponent.java +++ b/cave/com.raytheon.uf.viz.thinclient.cave/src/com/raytheon/uf/viz/thinclient/cave/ThinClientComponent.java @@ -55,9 +55,6 @@ import com.raytheon.uf.viz.thinclient.localization.LocalizationCachePersistence; import com.raytheon.uf.viz.thinclient.localization.ThinClientLocalizationInitializer; import com.raytheon.uf.viz.thinclient.preferences.ThinClientPreferenceConstants; import com.raytheon.uf.viz.thinclient.refresh.TimedRefresher; -import com.raytheon.viz.alerts.jobs.AutoUpdater; -import com.raytheon.viz.alerts.jobs.MenuUpdater; -import com.raytheon.viz.alerts.observers.ProductAlertObserver; import com.raytheon.viz.ui.personalities.awips.AbstractCAVEComponent; import com.raytheon.viz.ui.personalities.awips.CAVE; @@ -188,8 +185,11 @@ public class ThinClientComponent extends CAVE implements IThinClientComponent { @Override protected void initializeObservers() { ThinClientNotificationManagerJob.getInstance(); - ProductAlertObserver.addObserver(null, new MenuUpdater()); - ProductAlertObserver.addObserver(null, new AutoUpdater()); + IPreferenceStore store = Activator.getDefault().getPreferenceStore(); + if (store.getBoolean(ThinClientPreferenceConstants.P_DISABLE_JMS) == false) { + // JMS Enabled, register product alerts + registerProductAlerts(); + } } public void stopComponent() { diff --git a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/BundleContributionItem.java b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/BundleContributionItem.java index f111585083..032600742c 100644 --- a/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/BundleContributionItem.java +++ b/cave/com.raytheon.uf.viz.ui.menus/src/com/raytheon/uf/viz/ui/menus/widgets/BundleContributionItem.java @@ -56,8 +56,11 @@ import com.raytheon.uf.viz.core.procedures.BundleUtil.BundleDataItem; import com.raytheon.uf.viz.core.rsc.URICatalog; import com.raytheon.uf.viz.core.rsc.URICatalog.IURIRefreshCallback; import com.raytheon.uf.viz.ui.menus.xml.BundleMenuContribution; -import com.raytheon.viz.ui.MenuLoader; -import com.raytheon.viz.ui.actions.LoadSerializedXml; +import com.raytheon.viz.ui.BundleLoader; +import com.raytheon.viz.ui.BundleLoader.BundleInfoType; +import com.raytheon.viz.ui.BundleProductLoader; +import com.raytheon.viz.ui.UiUtil; +import com.raytheon.viz.ui.editor.AbstractEditor; /** * Provides an Eclipse menu contribution that loads a bundle, and is decorated @@ -345,15 +348,19 @@ public class BundleContributionItem extends ContributionItem { private void loadBundle(Event event) { try { + Bundle bundle = BundleLoader.getBundle( + this.menuContribution.xml.bundleFile, substitutions, + BundleInfoType.FILE_LOCATION); + AbstractEditor editor = UiUtil.createOrOpenEditor( + this.menuContribution.xml.editorType, bundle.getDisplays()); + BundleLoader loader; if (this.menuContribution.xml.fullBundleLoad == null || this.menuContribution.xml.fullBundleLoad == false) { - MenuLoader.loadProduct(this.menuContribution.xml.editorType, - this.menuContribution.xml.bundleFile, substitutions); + loader = new BundleProductLoader(editor, bundle); } else { - LoadSerializedXml.loadTo(PathManagerFactory.getPathManager() - .getStaticFile(this.menuContribution.xml.bundleFile), - substitutions); + loader = new BundleLoader(editor, bundle); } + loader.schedule(); if (this.menuContribution.xml.command != null) { ICommandService service = (ICommandService) PlatformUI diff --git a/cave/com.raytheon.viz.alerts/src/com/raytheon/viz/alerts/observers/ProductAlertObserver.java b/cave/com.raytheon.viz.alerts/src/com/raytheon/viz/alerts/observers/ProductAlertObserver.java index c83bf232d9..7fc148a79f 100644 --- a/cave/com.raytheon.viz.alerts/src/com/raytheon/viz/alerts/observers/ProductAlertObserver.java +++ b/cave/com.raytheon.viz.alerts/src/com/raytheon/viz/alerts/observers/ProductAlertObserver.java @@ -19,6 +19,7 @@ **/ package com.raytheon.viz.alerts.observers; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -306,58 +307,49 @@ public class ProductAlertObserver implements INotificationObserver { PracticeDataURINotificationMessage uriMsg = (PracticeDataURINotificationMessage) payLoad; dataURIs = uriMsg.getDataURIs(); } - for (int i = 0; i < dataURIs.length; ++i) { - String str = dataURIs[i]; - processDataURI(str); - } - - startWrappers(); - - if (dataURIs != null && dataURIs.length > 0) { - alertsProcessed += dataURIs.length; - } - - long curTime = System.currentTimeMillis(); - if (curTime - ALERT_LOG_INTERVAL > lastLogTime) { - if (alertsProcessed > 0) { - statusHandler.handle(Priority.VERBOSE, "Processed " - + alertsProcessed + " alerts in the last " - + ((curTime - lastLogTime) / 60000) - + " minutes"); - alertsProcessed = 0; - } - lastLogTime = curTime; - } + processDataURIs(Arrays.asList(dataURIs)); } } } - public static void processDerivedAlerts(Collection datauris) { - for (String datauri : datauris) { - getInstance().processDataURI(datauri); + /** + * Processes the DataURIs as alert messages + * + * @param datauris + */ + public static void processDataURIAlerts(Collection datauris) { + getInstance().processDataURIs(datauris); + } + + private synchronized void processDataURIs(Collection dataURIs) { + for (String str : dataURIs) { + processDataURI(str); + } + + startWrappers(); + + if (dataURIs != null && dataURIs.size() > 0) { + alertsProcessed += dataURIs.size(); + } + + long curTime = System.currentTimeMillis(); + if (curTime - ALERT_LOG_INTERVAL > lastLogTime) { + if (alertsProcessed > 0) { + statusHandler.handle(Priority.VERBOSE, "Processed " + + alertsProcessed + " alerts in the last " + + ((curTime - lastLogTime) / 60000) + " minutes"); + alertsProcessed = 0; + } + lastLogTime = curTime; } - getInstance().startWrappers(); } private void processDataURI(String datauri) { if (datauri == null) return; try { - Map attribs; - try { - attribs = RecordFactory.getInstance().loadMapFromUri(datauri); - - } catch (NoPluginException e) { - // ignore, if we hit this it means we received an alert from - // edex about ingested data, but viz doesn't have the necessary - // plugins to do anything with it - return; - } catch (Exception e1) { - statusHandler.handle(Priority.WARN, e1.getLocalizedMessage(), - e1); - return; - } - + Map attribs = RecordFactory.getInstance() + .loadMapFromUri(datauri); AlertMessage am = new AlertMessage(); am.dataURI = datauri; am.decodedAlert = Collections.unmodifiableMap(attribs); @@ -379,11 +371,12 @@ public class ProductAlertObserver implements INotificationObserver { sendToObserver(obs, am); } } - - } catch (RuntimeException e) { - statusHandler - .handle(Priority.PROBLEM, "Error preparing updates", e); - + } catch (NoPluginException e) { + // ignore, if we hit this it means we received an alert from + // edex about ingested data, but viz doesn't have the necessary + // plugins to do anything with it + } catch (Exception e1) { + statusHandler.handle(Priority.WARN, e1.getLocalizedMessage(), e1); } } diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java index 3305246d2d..e02600cd53 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java @@ -51,6 +51,8 @@ import com.raytheon.viz.gfe.smartscript.FieldDefinition; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Nov 10, 2008 njensen Initial creation + * Jan 18, 2013 njensen Added garbageCollect() + * * * * @author njensen @@ -354,4 +356,20 @@ public abstract class BaseGfePyController extends PythonScript implements execute("addModule", INTERFACE, argMap); } + /** + * Runs the python garbage collector. This should be run at the end of a + * procedure or tool in case the custom python used tk. If the python used + * tk and it is not garbage collected, errors about invalid threads may + * occur when the garbage collector runs in another python interpreter. + */ + public void garbageCollect() { + try { + jep.eval("import gc"); + jep.eval("gc.collect()"); + } catch (JepException e) { + statusHandler.handle(Priority.PROBLEM, + "Error garbage collecting GFE python interpreter", e); + } + } + } diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/DbParm.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/DbParm.java index 688b4d7f7c..aa9d2efe9c 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/DbParm.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/DbParm.java @@ -73,6 +73,7 @@ import com.raytheon.viz.gfe.core.griddata.IGridData; * to use IFPClient * 02/23/12 #346 dgilling Implement a dispose method. * 03/01/12 #346 dgilling Re-order dispose method. + * 01/21/12 #1504 randerso Cleaned up old debug logging to improve performance * * * @@ -411,6 +412,7 @@ public class DbParm extends Parm { // normal mode if (normal) { Arrays.sort(grids); + // Now replace the existing grids with the new ones replaceGrids(affectedTimeRange, grids); @@ -621,6 +623,7 @@ public class DbParm extends Parm { success &= allSaved; } + // if any pending saves if (sgr.size() > 0) { if (doSave(sgr)) { @@ -630,13 +633,7 @@ public class DbParm extends Parm { } else { success = false; } - } - - // if any pending saves - if (sgr.size() > 0) { - if (!doSave(sgr)) { - success = false; - } + pendingUnlocks.clear(); } if (success) { @@ -757,10 +754,10 @@ public class DbParm extends Parm { List lreq = new ArrayList(timesToSave.size()); for (int i = 0; i < timesToSave.size(); i++) { - String msg = "Reverting " + getParmID() + " tr=" - + timesToSave.get(i); - statusHandler.handle(Priority.DEBUG, msg, new Exception("Debug: " - + msg)); + // String msg = "Reverting " + getParmID() + " tr=" + // + timesToSave.get(i); + // statusHandler.handle(Priority.DEBUG, msg, new Exception("Debug: " + // + msg)); boolean success = true; IGridData[] grids = null; diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/gridmanager/GridCanvas.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/gridmanager/GridCanvas.java index fb3813d64f..ceebd780f3 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/gridmanager/GridCanvas.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/gridmanager/GridCanvas.java @@ -24,9 +24,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; -import java.util.HashMap; +import java.util.Iterator; import java.util.List; -import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -107,8 +106,11 @@ import com.raytheon.viz.ui.cmenu.AbstractRightClickAction; * Apr 7, 2009 randerso Initial creation * Jun 3, 2011 8919 rferrel Determine grid's VisMode based * on imageOnEdit - * 08/20/2012 #1082 randerso Moved calcStepTimes to AbstractParmManager for + * 08/20/2012 #1082 randerso Moved calcStepTimes to AbstractParmManager for * use in PngWriter + * 11/30/2012 #1328 mschenke Made GFE use descriptor for time matching + * and time storage and manipulation + * 01/22/2013 #1518 randerso Removed use of Map with Parms as keys * * * @@ -256,8 +258,6 @@ public class GridCanvas extends Canvas implements IMessageClient { private ArrayList gridBarList; - private Map parmToGridBar; - private Rectangle selection; private MenuManager menuMgr; @@ -294,7 +294,6 @@ public class GridCanvas extends Canvas implements IMessageClient { dataMgr = gridManager.getDataManager(); gridBarList = new ArrayList(); - parmToGridBar = new HashMap(); Parm[] displayedParms = gridManager.getDataManager().getParmManager() .getDisplayedParms(); @@ -684,10 +683,13 @@ public class GridCanvas extends Canvas implements IMessageClient { if (deletions != null) { for (Parm parm : deletions) { - GridBar gridBar = parmToGridBar.remove(parm); - if (gridBar != null) { - gridBarList.remove(gridBar); - gridBar.dispose(); + Iterator iter = gridBarList.iterator(); + while (iter.hasNext()) { + GridBar gridBar = iter.next(); + if (gridBar.getParm().equals(parm)) { + iter.remove(); + gridBar.dispose(); + } } } } @@ -695,11 +697,8 @@ public class GridCanvas extends Canvas implements IMessageClient { if (additions != null) { for (Parm parm : additions) { if (!parm.getGridInfo().isTimeIndependentParm()) { - if (!parmToGridBar.containsKey(parm)) { - GridBar gridBar = new GridBar(this, parm, gridManager); - gridBarList.add(gridBar); - parmToGridBar.put(parm, gridBar); - } + GridBar gridBar = new GridBar(this, parm, gridManager); + gridBarList.add(gridBar); } } } diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/ifpimage/ImageLegendResource.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/ifpimage/ImageLegendResource.java index 9ef5676f0c..da5272e317 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/ifpimage/ImageLegendResource.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/ifpimage/ImageLegendResource.java @@ -21,7 +21,6 @@ package com.raytheon.viz.gfe.ifpimage; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collection; import java.util.Formatter; import java.util.HashMap; import java.util.List; @@ -31,6 +30,7 @@ import java.util.TimeZone; import org.eclipse.swt.graphics.RGB; +import com.raytheon.uf.common.dataplugin.gfe.type.Pair; import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.common.time.TimeRange; import com.raytheon.uf.viz.core.RGBColors; @@ -42,7 +42,6 @@ import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability; import com.raytheon.viz.core.ColorUtil; import com.raytheon.viz.gfe.Activator; import com.raytheon.viz.gfe.core.DataManager; -import com.raytheon.viz.gfe.core.griddata.IGridData; import com.raytheon.viz.gfe.core.parm.Parm; import com.raytheon.viz.gfe.core.parm.ParmDisplayAttributes.VisMode; import com.raytheon.viz.gfe.rsc.GFELegendResource; @@ -62,6 +61,10 @@ import com.raytheon.viz.gfe.rsc.GFEResource; * Jul 10, 2012 15186 ryu Set legend font * Aug 20, 2012 #1078 dgilling Fix handling of ImageLegend_color * setting. + * Nov 30, 2012 #1328 mschenke Made GFE use descriptor for time matching + * and time storage and manipulation + * Jan 22, 2013 #1518 randerso Removed use of Map with Parms as keys, + * really just needed a list anyway. * * * @@ -100,9 +103,8 @@ public class ImageLegendResource extends GFELegendResource { @Override public LegendEntry[] getLegendData(IDescriptor descriptor) { - Map parmRscMap = new HashMap(); - Collection parms = getLegendOrderedParms(descriptor, parmRscMap); - LegendData[] data = makeLegend(parms, parmRscMap); + List> parms = getLegendOrderedParms(descriptor); + LegendData[] data = makeLegend(parms); LegendEntry[] entries = new LegendEntry[data.length]; for (int i = 0; i < entries.length; ++i) { @@ -113,15 +115,15 @@ public class ImageLegendResource extends GFELegendResource { return entries; } - private LegendData[] makeLegend(Collection parms, - Map parmRscMap) { + private LegendData[] makeLegend(List> parms) { FramesInfo currInfo = descriptor.getFramesInfo(); DataTime curTime = currInfo.getCurrentFrame(); // loop through the grids List legendData = new ArrayList(); - for (Parm parm : parms) { - ResourcePair rp = parmRscMap.get(parm); + for (Pair pair : parms) { + Parm parm = pair.getFirst(); + ResourcePair rp = pair.getSecond(); GFEResource rsc = (GFEResource) rp.getResource(); String parmName = parm.getParmID().getParmName(); ResourceProperties props = rp.getProperties(); @@ -150,7 +152,6 @@ public class ImageLegendResource extends GFELegendResource { // get the units for the time string String units = rsc.getParm().getGridInfo().getUnitString(); - IGridData[] gd = new IGridData[0]; Locale locale = Locale.getDefault(); String lang = getLanguage(); diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureJob.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureJob.java index ab3d246e95..a9b8a5d7c3 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureJob.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureJob.java @@ -56,6 +56,7 @@ import com.raytheon.viz.gfe.jobs.AsyncProgressJob; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Oct 8, 2009 njensen Initial creation + * Jan 18, 2013 1509 njensen Garbage collect after running procedure * * * @@ -395,6 +396,7 @@ public class ProcedureJob extends AbstractQueueJob { statusHandler.handle(Priority.PROBLEM, "Error executing procedure " + procedureName, e); } finally { + controller.garbageCollect(); progressJob.done(pjStatus); } } diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/GFELegendResource.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/GFELegendResource.java index ce10249422..4431e1be17 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/GFELegendResource.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/GFELegendResource.java @@ -23,13 +23,11 @@ import static com.raytheon.viz.gfe.core.parm.ParmDisplayAttributes.VisMode.IMAGE import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Date; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.TimeZone; import org.eclipse.jface.preference.IPreferenceStore; @@ -37,6 +35,7 @@ import org.eclipse.swt.graphics.RGB; import com.raytheon.uf.common.dataplugin.gfe.db.objects.DatabaseID; import com.raytheon.uf.common.dataplugin.gfe.db.objects.ParmID; +import com.raytheon.uf.common.dataplugin.gfe.type.Pair; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; @@ -65,6 +64,7 @@ import com.raytheon.viz.gfe.PreferenceInitializer; import com.raytheon.viz.gfe.core.DataManager; import com.raytheon.viz.gfe.core.ISpatialDisplayManager; import com.raytheon.viz.gfe.core.griddata.IGridData; +import com.raytheon.viz.gfe.core.msgs.INewModelAvailableListener; import com.raytheon.viz.gfe.core.msgs.Message; import com.raytheon.viz.gfe.core.msgs.Message.IMessageClient; import com.raytheon.viz.gfe.core.msgs.ShowQuickViewDataMsg; @@ -83,13 +83,18 @@ import com.raytheon.viz.ui.input.InputAdapter; * 03/17/2008 chammack Initial Creation. * 08/19/2009 2547 rjpeter Implement Test/Prac database display. * 07/10/2012 15186 ryu Clean up initInternal per Ron + * 11/30/2012 #1328 mschenke Made GFE use descriptor for time matching + * and time storage and manipulation + * 01/22/2013 #1518 randerso Removed use of Map with Parms as keys, + * really just needed a list anyway. * * * @author chammack * @version 1.0 */ public class GFELegendResource extends - AbstractLegendResource implements IMessageClient { + AbstractLegendResource implements + IMessageClient, INewModelAvailableListener { private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(GFELegendResource.class); @@ -118,8 +123,6 @@ public class GFELegendResource extends private class GFELegendInputHandler extends InputAdapter { - private boolean inDrag; - ResourcePair mouseDownRsc = null; @Override @@ -158,10 +161,9 @@ public class GFELegendResource extends if (rsc.getResource() instanceof GFEResource) { GFEResource gfeRsc = (GFEResource) rsc .getResource(); - DataManager - .getCurrentInstance() - .getSpatialDisplayManager() - .makeVisible(gfeRsc.getParm(), + GFELegendResource.this.dataManager + .getSpatialDisplayManager().makeVisible( + gfeRsc.getParm(), !props.isVisible(), false); } else { @@ -173,8 +175,7 @@ public class GFELegendResource extends } else if (mouseButton == 2) { if (rsc.getResource() instanceof GFEResource) { GFEResource gfeRsc = (GFEResource) rsc.getResource(); - ISpatialDisplayManager sdm = DataManager - .getCurrentInstance() + ISpatialDisplayManager sdm = GFELegendResource.this.dataManager .getSpatialDisplayManager(); Parm parm = gfeRsc.getParm(); @@ -242,7 +243,6 @@ public class GFELegendResource extends }.run(); } - @SuppressWarnings("unchecked") public GFELegendResource(DataManager dataManager, GFELegendResourceData resourceData, LoadProperties loadProps) { super(resourceData, loadProps); @@ -257,8 +257,6 @@ public class GFELegendResource extends } catch (Exception e) { mode = LegendMode.GRIDS; } - - Message.registerInterest(this, ShowQuickViewDataMsg.class); } protected void addSpaces(StringBuilder sb, int numSpace) { @@ -267,23 +265,6 @@ public class GFELegendResource extends } } - /* - * (non-Javadoc) - * - * @see java.lang.Object#finalize() - */ - @SuppressWarnings("unchecked") - @Override - protected void finalize() throws Throwable { - // FIXME: this needs to be a dispose method. - Message.unregisterInterest(this, ShowQuickViewDataMsg.class); - - if (font != null) { - font.dispose(); - font = null; - } - } - /* * (non-Javadoc) * @@ -319,26 +300,21 @@ public class GFELegendResource extends } /** - * Gets an ordered collection of Parms to display for the legend. + * Gets an ordered list of Parm/ResourcePair pairs to display for the + * legend. * * @param descriptor - * @param parmRscMap - * optional map to create Parm->ResourcePair mapping for parms - * returned * @return */ - protected Collection getLegendOrderedParms(IDescriptor descriptor, - Map parmRscMap) { - List parms = new ArrayList(); + protected List> getLegendOrderedParms( + IDescriptor descriptor) { + List> parms = new ArrayList>(); for (ResourcePair rp : descriptor.getResourceList()) { if (rp.getResource() instanceof GFEResource) { Parm parm = ((GFEResource) rp.getResource()).getParm(); if (qvGrid == null || (qvGrid != null && qvGrid.getParm() == parm)) { - parms.add(parm); - if (parmRscMap != null) { - parmRscMap.put(parm, rp); - } + parms.add(new Pair(parm, rp)); if (qvGrid != null) { break; } @@ -346,8 +322,14 @@ public class GFELegendResource extends } } - Collections.sort(parms); - Collections.reverse(parms); + Collections.sort(parms, new Comparator>() { + + @Override + public int compare(Pair o1, + Pair o2) { + return o2.getFirst().compareTo(o1.getFirst()); + } + }); return parms; } @@ -362,8 +344,7 @@ public class GFELegendResource extends .getActivatedParm(); StringBuilder labelBuilder = new StringBuilder(); - Map parmRscMap = new HashMap(); - Collection parms = getLegendOrderedParms(descriptor, parmRscMap); + List> parms = getLegendOrderedParms(descriptor); Parm qvParm = null; if (qvGrid != null) { qvParm = qvGrid.getParm(); @@ -374,11 +355,12 @@ public class GFELegendResource extends ParmID topoID = dataManager.getTopoManager().getCompositeParmID(); // Topmost resources: GFE Parms - for (Parm parm : parms) { + for (Pair pair : parms) { + Parm parm = pair.getFirst(); ParmID parmId = parm.getParmID(); DatabaseID dbId = parmId.getDbId(); StringBuilder sb = new StringBuilder(); - ResourcePair rp = parmRscMap.get(parm); + ResourcePair rp = pair.getSecond(); GFEResource rsc = (GFEResource) rp.getResource(); LegendData ld = new LegendData(); ResourceProperties props = rp.getProperties(); @@ -435,33 +417,27 @@ public class GFELegendResource extends // get the model name labelBuilder.setLength(0); - labelBuilder.append(dbId.getModelName()); + labelBuilder.append(dbId.getShortModelId()); - boolean iscTyped = false; - if (dataManager.getParmManager().iscMode() - && dbId.equals(dataManager.getParmManager() - .getMutableDatabase())) { + // FIXME this is from A1 and is not consistent with the code in + // getLongestFields - ParmID iscPID = dataManager.getParmManager().getISCParmID( - parmId); - if (iscPID.isValid()) { - // vparms (i.e. temp hazards) can't get here - String iscStr = "+" + iscPID.getDbId().getDbType() - + iscPID.getDbId().getModelName(); - labelBuilder.append(iscStr); - iscTyped = true; - } - } + // if (_showISCMode && _quickViewGrid == GridID() + // && _grids[i].gridID().parm()->parmID().databaseID() == + // _dbss->dataManager()->parmMgr()->mutableDatabase()) + // { + // unsigned int mpos = 0; + // if (modelText.found(' ', mpos)) + // { + // ParmID iscPID = + // _dbss->dataManager()->parmMgr()->getISCParmID( + // _grids[i].gridID().parm()->parmID()); + // TextString iscStr = "+" + iscPID.databaseID().type() + + // iscPID.databaseID().model(); + // modelText.insertBefore(mpos, iscStr); + // } + // } - if (!iscTyped) { - String type = dbId.getDbType(); - if ((type != null) && (type.length() > 0)) { - labelBuilder.append("_"); - labelBuilder.append(type); - } - } - - labelBuilder.append(" (" + dbId.getSiteId() + ")"); sb.append(labelBuilder.toString()); diff = lengths[3] - labelBuilder.length(); addSpaces(sb, diff + 1); @@ -562,16 +538,14 @@ public class GFELegendResource extends * @param descriptor * @return */ - private int[] getLongestFields(Collection parms) { + private int[] getLongestFields(List> parms) { // Iterator rl = descriptor.getResourceList().iterator(); int[] sz = new int[4]; StringBuilder labelBuilder = new StringBuilder(); // synchronized (rl) { // while (rl.hasNext()) { - for (Parm parm : parms) { - // AbstractVizResource resource = rl.next().getResource(); - // if (resource instanceof GFEResource) { - // Parm parm = ((GFEResource) resource).getParm(); + for (Pair pair : parms) { + Parm parm = pair.getFirst(); ParmID parmId = parm.getParmID(); sz[0] = Math.max(sz[0], parmId.getParmName().length()); sz[1] = Math.max(sz[1], parmId.getParmLevel().length()); @@ -580,52 +554,33 @@ public class GFELegendResource extends DatabaseID dbId = parmId.getDbId(); labelBuilder.setLength(0); - labelBuilder.append(dbId.getModelName()); + labelBuilder.append(dbId.getShortModelId()); - boolean iscTyped = false; - if (dataManager.getParmManager().iscMode() - && dbId.equals(dataManager.getParmManager() - .getMutableDatabase())) { + // FIXME this is A1 code and is not consistent with the code in + // getLegendDataGrids - ParmID iscPID = dataManager.getParmManager().getISCParmID( - parmId); - if (iscPID.isValid()) { - // vparms (i.e. temp hazards) can't get here - String iscStr = "+" + iscPID.getDbId().getDbType() - + iscPID.getDbId().getModelName(); - labelBuilder.append(iscStr); - iscTyped = true; - } - } - - if (!iscTyped) { - String type = dbId.getDbType(); - if ((type != null) && (type.length() > 0)) { - labelBuilder.append("_"); - labelBuilder.append(type); - } - } - - labelBuilder.append(" (" + dbId.getSiteId() + ")"); - // TODO: FIXME // if (showIscMode // && ids[i].gridID().parm()->parmID().databaseID() == // _dbss->dataManager()->parmMgr()->mutableDatabase()) // label += "+VISC"; - sz[3] = Math.max(sz[3], labelBuilder.length()); - // } + sz[3] = Math.max(sz[3], labelBuilder.length()); } - // } return sz; } + @SuppressWarnings("unchecked") @Override protected void disposeInternal() { super.disposeInternal(); + + this.dataManager.getParmManager().removeNewModelAvailableListener(this); + Message.unregisterInterest(this, ShowQuickViewDataMsg.class); + if (font != null) { font.dispose(); + font = null; } IDisplayPaneContainer container = getResourceContainer(); if (container != null) { @@ -633,9 +588,14 @@ public class GFELegendResource extends } } + @SuppressWarnings("unchecked") @Override protected void initInternal(IGraphicsTarget target) throws VizException { super.initInternal(target); + + Message.registerInterest(this, ShowQuickViewDataMsg.class); + this.dataManager.getParmManager().addNewModelAvailableListener(this); + int fontNum = 3; if (GFEPreference.contains("SELegend_font")) { fontNum = GFEPreference.getIntPreference("SELegend_font"); @@ -689,4 +649,9 @@ public class GFELegendResource extends } } + @Override + public void newModelAvailable(DatabaseID additions) { + issueRefresh(); + } + } diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/DiscreteColorbar.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/DiscreteColorbar.java index 503d3ad132..a504f92471 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/DiscreteColorbar.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/DiscreteColorbar.java @@ -82,7 +82,7 @@ import com.vividsolutions.jts.geom.Coordinate; /** * Implements a colorbar for continuous (scalar and vector) elements - * + * *
  * SOFTWARE HISTORY
  * Date         Ticket#    Engineer    Description
@@ -91,11 +91,13 @@ import com.vividsolutions.jts.geom.Coordinate;
  * Aug 20, 2008            dglazesk    Updated for the new ColorMap interface
  * Aug 20, 2012      1079  randerso    Changed to display all discrete values for
  *                                     non-overlapping discretes
- * Jan 9, 2013  15661      ryu         Set font for drawing regular Wx/discrete parm labels.
- * Jan 10, 2013  15548     ryu         Update colorbar when new discrete colormap is selected
- *
+ * Jan  9, 2013     15661  ryu         Set font for drawing regular Wx/discrete parm labels.
+ * Jan 10, 2013     15548  ryu         Update colorbar when new discrete colormap is selected
+ * Jan 23, 2013     #1524  randerso    Fix missing discrete color bar and error when clicking 
+ *                                     on discrete color bar when no grid exists
+ * 
  * 
- * + * * @author chammack * @version 1.0 */ @@ -139,7 +141,7 @@ public class DiscreteColorbar implements IColorBarDisplay, /** * Constructor for the Discrete Color Bar - * + * * @param parm * The parm * @param colorbarResource @@ -162,8 +164,7 @@ public class DiscreteColorbar implements IColorBarDisplay, DataManager dataManager = parm.getDataManager(); ISpatialDisplayManager spatialDisplayManager = dataManager .getSpatialDisplayManager(); - ResourcePair resourcePair = spatialDisplayManager - .getResourcePair(parm); + ResourcePair resourcePair = spatialDisplayManager.getResourcePair(parm); AbstractVizResource resource = resourcePair.getResource(); ColorMapParameters params = resource.getCapability( ColorMapCapability.class).getColorMapParameters(); @@ -172,7 +173,7 @@ public class DiscreteColorbar implements IColorBarDisplay, /* * (non-Javadoc) - * + * * @see com.raytheon.viz.gfe.rsc.colorbar.IColorBarDisplay#dispose() */ @Override @@ -193,7 +194,7 @@ public class DiscreteColorbar implements IColorBarDisplay, /** * Gets the Discrete Color map. - * + * * @return Returns the color map used for the discrete data. */ public static ColorMap getFallbackColorMap() { @@ -202,7 +203,7 @@ public class DiscreteColorbar implements IColorBarDisplay, /* * (non-Javadoc) - * + * * @see * com.raytheon.viz.core.drawables.IRenderable#paint(com.raytheon.viz.core * .IGraphicsTarget, com.raytheon.viz.core.drawables.PaintProperties) @@ -210,7 +211,7 @@ public class DiscreteColorbar implements IColorBarDisplay, @Override public void paint(IGraphicsTarget target, PaintProperties paintProps) throws VizException { - DataTime currentTime = paintProps.getDataTime(); + DataTime currentTime = paintProps.getFramesInfo().getCurrentFrame(); if (parm == null || currentTime == null) { return; } @@ -426,7 +427,7 @@ public class DiscreteColorbar implements IColorBarDisplay, * Labels that do not fit their designated band on the bar will be * truncated. Pickup value text will always be displayed in full, so any * text it overlaps will not be drawn. - * + * * @param target * The graphics target on which to draw * @param colorTable @@ -557,7 +558,7 @@ public class DiscreteColorbar implements IColorBarDisplay, /** * Draws the colorbar once colors and patterns have been decided. - * + * * @param target * The graphics target on which to draw. * @param pixelExtent @@ -657,34 +658,42 @@ public class DiscreteColorbar implements IColorBarDisplay, /* * (non-Javadoc) - * + * * @see * com.raytheon.viz.gfe.rsc.colorbar.IColorBarDisplay#getValueAt(double[], * int) */ @Override public WxValue getValueAt(double[] coord, int mouseButton) { - PixelExtent lastExtent = colorbarResource.getExtent(); - float fractionX = (float) ((coord[0] - lastExtent.getMinX()) / (lastExtent - .getMaxX() - lastExtent.getMinX())); - int index = (int) (gridKeys.size() * fractionX); - if (index >= gridKeys.size()) { - index = gridKeys.size() - 1; - } + WxValue retVal = null; + if (!gridKeys.isEmpty()) { + PixelExtent lastExtent = colorbarResource.getExtent(); + float fractionX = (float) ((coord[0] - lastExtent.getMinX()) / (lastExtent + .getMaxX() - lastExtent.getMinX())); + int index = (int) (gridKeys.size() * fractionX); + if (index >= gridKeys.size()) { + index = gridKeys.size() - 1; + } - switch (parm.getGridInfo().getGridType()) { - case DISCRETE: { - DiscreteWxValue castedVal = (DiscreteWxValue) gridKeys.get(index); - return new DiscreteWxValue(castedVal.getDiscreteKey(), parm); - } - case WEATHER: { - WeatherWxValue castedVal = (WeatherWxValue) gridKeys.get(index); - return new WeatherWxValue(castedVal.getWeatherKey(), parm); - } - default: - throw new IllegalArgumentException( - "getValueAt does not support type: " - + parm.getGridInfo().getGridType()); + switch (parm.getGridInfo().getGridType()) { + case DISCRETE: { + DiscreteWxValue castedVal = (DiscreteWxValue) gridKeys + .get(index); + retVal = new DiscreteWxValue(castedVal.getDiscreteKey(), parm); + break; + } + case WEATHER: { + WeatherWxValue castedVal = (WeatherWxValue) gridKeys.get(index); + retVal = new WeatherWxValue(castedVal.getWeatherKey(), parm); + + break; + } + default: + throw new IllegalArgumentException( + "getValueAt does not support type: " + + parm.getGridInfo().getGridType()); + } } + return retVal; } } diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/GFEColorbarResource.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/GFEColorbarResource.java index 9e5888fdf6..22a6bafaec 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/GFEColorbarResource.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/rsc/colorbar/GFEColorbarResource.java @@ -28,8 +28,6 @@ import java.util.Set; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.graphics.RGB; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.PlatformUI; import com.raytheon.uf.common.dataplugin.gfe.db.objects.GFERecord.GridType; import com.raytheon.uf.common.dataplugin.gfe.db.objects.ParmID; @@ -98,8 +96,10 @@ import com.raytheon.viz.ui.input.InputAdapter; * 05Aug2008 #1405 ebabin Fix fo delta not displaying after first use. * 06/03/2011 #8919 rferrel No longer display color bar when * VisMode is GRAPHIC - * 11/13/20112 #1298 rferrel Changes for non-blocking SetDeltaDialog. + * 11/13/2012 #1298 rferrel Changes for non-blocking SetDeltaDialog. * Changes for non-blocking SetValueDialog. + * 01/23/2013 #1524 randerso Fix error when clicking on discrete color bar when + * no grid exists * * * @@ -175,6 +175,10 @@ public class GFEColorbarResource extends private void setPickup(double[] v, int mouseButton) { WxValue val = colorbarDisplay.getValueAt(v, mouseButton); + if (val == null) { + return; + } + Parm parm = getParm(); if (parm == null) { throw new IllegalStateException("Parm is null from colorbar"); diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/script/SmartToolJob.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/script/SmartToolJob.java index 05dcae6f9f..c154f9439b 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/script/SmartToolJob.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/script/SmartToolJob.java @@ -53,6 +53,7 @@ import com.raytheon.viz.gfe.smarttool.Tool; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Jan 19, 2010 njensen Initial creation + * Jan 18, 2013 1509 njensen Garbage collect after running tool * * * @@ -164,6 +165,7 @@ public class SmartToolJob extends AbstractQueueJob { "Error in smart tool", e); throw e; } finally { + python.garbageCollect(); progressJob.done(pjResult); req = request; request = null; diff --git a/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/GridProductBrowserDataDefinition.java b/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/GridProductBrowserDataDefinition.java index 16a87185fc..f0d46ed512 100644 --- a/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/GridProductBrowserDataDefinition.java +++ b/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/GridProductBrowserDataDefinition.java @@ -47,9 +47,12 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.viz.core.datastructure.DataCubeContainer; +import com.raytheon.uf.viz.core.drawables.ResourcePair; import com.raytheon.uf.viz.core.exception.VizCommunicationException; +import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.level.LevelMappingFactory; import com.raytheon.uf.viz.core.rsc.DisplayType; +import com.raytheon.uf.viz.core.rsc.ResourceProperties; import com.raytheon.uf.viz.core.rsc.ResourceType; import com.raytheon.uf.viz.derivparam.library.DerivParamDesc; import com.raytheon.uf.viz.derivparam.library.DerivedParameterGenerator; @@ -129,6 +132,48 @@ public class GridProductBrowserDataDefinition extends return new GridResourceData(); } + @Override + public void constructResource(String[] selection, ResourceType type) { + GridInventory inventory = getInventory(); + if (inventory == null) { + super.constructResource(selection, type); + return; + } + if (type != null) { + loadProperties.setResourceType(type); + } + HashMap parameters = getProductParameters( + selection, order); + List ensembles = null; + try { + ensembles = inventory.getEnsembles(parameters); + } catch (VizException e) { + statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e); + } + if (ensembles != null && ensembles.size() > 1) { + Collections.sort(ensembles); + List pairs = new ArrayList(); + for (String ensemble : ensembles) { + ResourcePair pair = new ResourcePair(); + resourceData = getResourceData(); + HashMap newParameters = new HashMap( + parameters); + newParameters.put(GridConstants.ENSEMBLE_ID, + new RequestConstraint(ensemble)); + resourceData.setMetadataMap(newParameters); + pair.setResourceData(resourceData); + pair.setLoadProperties(loadProperties); + pair.setProperties(new ResourceProperties()); + pairs.add(pair); + } + constructResource(pairs); + } else { + resourceData = getResourceData(); + resourceData.setMetadataMap(parameters); + constructResource(); + } + } + @Override protected String[] queryData(String param, HashMap queryList) { diff --git a/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/inv/GridUpdater.java b/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/inv/GridUpdater.java index 227c654343..367873f2e3 100644 --- a/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/inv/GridUpdater.java +++ b/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/inv/GridUpdater.java @@ -298,7 +298,7 @@ public class GridUpdater implements IAlertObserver { } } myUpdates.addAll(datauris); - ProductAlertObserver.processDerivedAlerts(datauris); + ProductAlertObserver.processDataURIAlerts(datauris); } /** diff --git a/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/inv/RadarUpdater.java b/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/inv/RadarUpdater.java index 81c04a55b4..8dc2089ab6 100644 --- a/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/inv/RadarUpdater.java +++ b/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/inv/RadarUpdater.java @@ -203,7 +203,7 @@ public class RadarUpdater implements IAlertObserver { "Unable to generate updates for derived product", e); } } - ProductAlertObserver.processDerivedAlerts(datauris); + ProductAlertObserver.processDataURIAlerts(datauris); } private CacheKey getCacheKey(RadarRequestableLevelNode rNode) { diff --git a/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/rsc/general/AbstractGridResource.java b/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/rsc/general/AbstractGridResource.java index ed9a9b0ae8..0b9037e1f6 100644 --- a/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/rsc/general/AbstractGridResource.java +++ b/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/rsc/general/AbstractGridResource.java @@ -51,6 +51,7 @@ import com.raytheon.uf.viz.core.IGraphicsTarget; import com.raytheon.uf.viz.core.VizApp; import com.raytheon.uf.viz.core.drawables.ColorMapLoader; import com.raytheon.uf.viz.core.drawables.ColorMapParameters; +import com.raytheon.uf.viz.core.drawables.ColorMapParameters.PersistedParameters; import com.raytheon.uf.viz.core.drawables.IRenderable; import com.raytheon.uf.viz.core.drawables.PaintProperties; import com.raytheon.uf.viz.core.exception.VizException; @@ -595,6 +596,13 @@ public abstract class AbstractGridResource // reuse the old parameters. This is useful when the resource is // sharing capabilities, for example in an FFGVizGroupResource. newParameters = oldParameters; + } else if (oldParameters != null) { + newParameters.setColorMapName(oldParameters.getColorMapName()); + newParameters.setColorMap(oldParameters.getColorMap()); + PersistedParameters persisted = oldParameters.getPersisted(); + if (persisted != null) { + newParameters.applyPersistedParameters(persisted); + } } return newParameters; } diff --git a/cave/com.raytheon.viz.lightning/src/com/raytheon/viz/lightning/LightningResourceData.java b/cave/com.raytheon.viz.lightning/src/com/raytheon/viz/lightning/LightningResourceData.java index 71705c8b2d..10340b221c 100644 --- a/cave/com.raytheon.viz.lightning/src/com/raytheon/viz/lightning/LightningResourceData.java +++ b/cave/com.raytheon.viz.lightning/src/com/raytheon/viz/lightning/LightningResourceData.java @@ -81,6 +81,16 @@ public class LightningResourceData extends AbstractRequestableResourceData { return rsc; } + @Override + public boolean isUpdatingOnMetadataOnly() { + return true; + } + + @Override + public boolean isRetrieveData() { + return true; + } + /** * @return the handlingPositiveStrikes */ diff --git a/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/rsc/MetarPrecipResource.java b/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/rsc/MetarPrecipResource.java index 06c0dcd3aa..58a3d61d28 100644 --- a/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/rsc/MetarPrecipResource.java +++ b/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/rsc/MetarPrecipResource.java @@ -157,7 +157,11 @@ public class MetarPrecipResource extends @Override protected void paintInternal(IGraphicsTarget target, PaintProperties paintProps) throws VizException { - List precips = data.get(paintProps.getDataTime()); + DataTime time = paintProps.getDataTime(); + if (time == null) { + return; + } + List precips = getPrecipData(time); if (precips == null) { dataProcessJob.schedule(); return; @@ -201,6 +205,19 @@ public class MetarPrecipResource extends target.drawStrings(strings); } + private List getPrecipData(DataTime time) { + List currData = null; + synchronized (data) { + currData = data.get(time); + } + if (currData != null) { + synchronized (currData) { + return new ArrayList(currData); + } + } + return null; + } + @Override protected void initInternal(IGraphicsTarget target) throws VizException { @@ -262,7 +279,7 @@ public class MetarPrecipResource extends Double magnification = getCapability(MagnificationCapability.class) .getMagnification(); - List precips = data.get(descriptor + List precips = getPrecipData(descriptor .getTimeForResource(this)); if (precips == null || precips.isEmpty()) { @@ -299,12 +316,14 @@ public class MetarPrecipResource extends private void processReproject() { if (reproject) { reproject = false; - for (List dataList : data.values()) { - for (RenderablePrecipData precip : dataList) { - Coordinate latLon = precip.getLatLon(); - double[] px = descriptor.worldToPixel(new double[] { - latLon.x, latLon.y }); - precip.string.setCoordinates(px[0], px[1], px[2]); + synchronized (data) { + for (List dataList : data.values()) { + for (RenderablePrecipData precip : dataList) { + Coordinate latLon = precip.getLatLon(); + double[] px = descriptor.worldToPixel(new double[] { + latLon.x, latLon.y }); + precip.string.setCoordinates(px[0], px[1], px[2]); + } } } } @@ -312,10 +331,12 @@ public class MetarPrecipResource extends } private void processRemoves() { - while (!removes.isEmpty()) { - DataTime toRemove = removes.poll(); - this.dataTimes.remove(toRemove); - this.data.remove(toRemove); + synchronized (data) { + while (!removes.isEmpty()) { + DataTime toRemove = removes.poll(); + this.dataTimes.remove(toRemove); + this.data.remove(toRemove); + } } } @@ -354,10 +375,13 @@ public class MetarPrecipResource extends // No need to reprocess times after the earliest update. continue; } - Iterator iter = entry.getValue().iterator(); - while (iter.hasNext()) { - if (newStations.contains(iter.next().getStationName())) { - iter.remove(); + synchronized (entry.getValue()) { + Iterator iter = entry.getValue() + .iterator(); + while (iter.hasNext()) { + if (newStations.contains(iter.next().getStationName())) { + iter.remove(); + } } } addData(time, container.getBasePrecipData(time)); @@ -393,6 +417,9 @@ public class MetarPrecipResource extends } int curIndex = frameInfo.getFrameIndex(); int count = frameInfo.getFrameCount(); + if (times.length != count) { + System.out.println("Uh oh"); + } // This will generate the number series 0, -1, 1, -2, 2, -3, 3... for (int i = 0; i < count / 2 + 1; i = i < 0 ? -i : -i - 1) { int index = (count + curIndex + i) % count; @@ -417,27 +444,31 @@ public class MetarPrecipResource extends } } } - // This will only happen if frames were removed while we were processing - // DOn't leave any half created frames - for (DataTime time : baseOnly) { - this.dataTimes.remove(time); - this.data.remove(time); + + synchronized (data) { + // This will only happen if frames were removed while we were + // processing. Don't leave any half created frames + for (DataTime time : baseOnly) { + this.dataTimes.remove(time); + this.data.remove(time); + } } } private void addData(DataTime time, List precips) { if (precips.isEmpty()) { if (!dataTimes.contains(time)) { - List newPrecips = Collections.emptyList(); - data.put(time, newPrecips); + synchronized (data) { + List newPrecips = Collections + .emptyList(); + data.put(time, newPrecips); + } dataTimes.add(time); } } if (data.containsKey(time)) { precips = new ArrayList(precips); - for (RenderablePrecipData pData : data.get(time)) { - precips.add(pData); - } + precips.addAll(getPrecipData(time)); } Collections.sort(precips, new Comparator() { @@ -480,9 +511,11 @@ public class MetarPrecipResource extends data.distValue = bestDist; newPrecips.add(data); } - data.put(time, newPrecips); - if (!dataTimes.contains(time)) { - dataTimes.add(time); + synchronized (data) { + data.put(time, newPrecips); + if (!dataTimes.contains(time)) { + dataTimes.add(time); + } } issueRefresh(); } diff --git a/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/rsc/MetarPrecipResourceData.java b/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/rsc/MetarPrecipResourceData.java index 2e0f5e823a..f6c2be7742 100644 --- a/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/rsc/MetarPrecipResourceData.java +++ b/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/rsc/MetarPrecipResourceData.java @@ -67,6 +67,16 @@ public class MetarPrecipResourceData extends AbstractRequestableResourceData { this.duration = duration; } + @Override + public boolean isUpdatingOnMetadataOnly() { + return true; + } + + @Override + public boolean isRetrieveData() { + return false; + } + @Override public int hashCode() { final int prime = 31; diff --git a/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/util/PointMetadataContainer.java b/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/util/PointMetadataContainer.java index 35e06b2f6f..5e48511836 100644 --- a/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/util/PointMetadataContainer.java +++ b/cave/com.raytheon.viz.pointdata/src/com/raytheon/viz/pointdata/util/PointMetadataContainer.java @@ -102,15 +102,17 @@ public class PointMetadataContainer extends MetadataContainer { } pdc = pdca.getBaseRecords(baseParams, originalConstraints); for (PointDataLevelNode node : nodes) { - IDataRecord rec = pdc.getParameterRecord(node.getParameter()); Set cacheSet = new HashSet(); - cacheSet.add(new PointRequestableData(rec, pdc.getDescription( - node.getParameter()).getUnitObject())); - dataCache.put(node, cacheSet); - if (!Arrays.asList("id", "latitude", "longitude", "dataURI") - .contains(rec.getName())) { - pdc.remove(rec.getName()); + if (pdc != null) { + IDataRecord rec = pdc.getParameterRecord(node.getParameter()); + cacheSet.add(new PointRequestableData(rec, pdc.getDescription( + node.getParameter()).getUnitObject())); + if (!Arrays.asList("id", "latitude", "longitude", "dataURI") + .contains(rec.getName())) { + pdc.remove(rec.getName()); + } } + dataCache.put(node, cacheSet); } } diff --git a/cave/com.raytheon.viz.ui.personalities.awips/src/com/raytheon/viz/ui/personalities/awips/AbstractCAVEComponent.java b/cave/com.raytheon.viz.ui.personalities.awips/src/com/raytheon/viz/ui/personalities/awips/AbstractCAVEComponent.java index e9b60f47b8..72495a05bd 100644 --- a/cave/com.raytheon.viz.ui.personalities.awips/src/com/raytheon/viz/ui/personalities/awips/AbstractCAVEComponent.java +++ b/cave/com.raytheon.viz.ui.personalities.awips/src/com/raytheon/viz/ui/personalities/awips/AbstractCAVEComponent.java @@ -54,6 +54,7 @@ import com.raytheon.uf.viz.alertviz.SystemStatusHandler; import com.raytheon.uf.viz.alertviz.ui.dialogs.AlertVisualization; import com.raytheon.uf.viz.application.ProgramArguments; import com.raytheon.uf.viz.application.component.IStandaloneComponent; +import com.raytheon.uf.viz.core.RecordFactory; import com.raytheon.uf.viz.core.VizApp; import com.raytheon.uf.viz.core.localization.CAVELocalizationNotificationObserver; import com.raytheon.uf.viz.core.localization.LocalizationConstants; @@ -383,9 +384,15 @@ public abstract class AbstractCAVEComponent implements IStandaloneComponent { protected void initializeObservers() { // Setup cave notification observer CAVELocalizationNotificationObserver.register(); - // Register product observers - ProductAlertObserver.addObserver(null, new MenuUpdater()); - ProductAlertObserver.addObserver(null, new AutoUpdater()); + registerProductAlerts(); } + protected void registerProductAlerts() { + // Register product observers + ProductAlertObserver.addObserver(null, new MenuUpdater()); + for (String plugin : RecordFactory.getInstance().getSupportedPlugins()) { + // Create separate AutoUpdater per plugin + ProductAlertObserver.addObserver(plugin, new AutoUpdater()); + } + } } diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/BundleLoader.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/BundleLoader.java new file mode 100644 index 0000000000..c9056f8739 --- /dev/null +++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/BundleLoader.java @@ -0,0 +1,346 @@ +package com.raytheon.viz.ui; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ui.IEditorPart; + +import com.raytheon.uf.common.localization.PathManagerFactory; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.viz.core.AbstractTimeMatcher; +import com.raytheon.uf.viz.core.IDisplayPane; +import com.raytheon.uf.viz.core.IDisplayPaneContainer; +import com.raytheon.uf.viz.core.VizApp; +import com.raytheon.uf.viz.core.drawables.AbstractRenderableDisplay; +import com.raytheon.uf.viz.core.drawables.IDescriptor; +import com.raytheon.uf.viz.core.drawables.IRenderableDisplay; +import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.uf.viz.core.globals.VizGlobalsManager; +import com.raytheon.uf.viz.core.procedures.Bundle; +import com.raytheon.viz.ui.editor.IMultiPaneEditor; + +/** + * + * Loads a bundle to a container. Replaces contents of bundle on the container + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 8, 2013            mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ +public class BundleLoader extends Job { + + protected static final IUFStatusHandler statusHandler = UFStatus + .getHandler(BundleLoader.class); + + public static enum BundleInfoType { + FILE_LOCATION, XML + } + + protected static class LoadItem { + + public final IDisplayPane loadTo; + + public final IRenderableDisplay loadFrom; + + public LoadItem(IDisplayPane loadTo, IRenderableDisplay loadFrom) { + this.loadTo = loadTo; + this.loadFrom = loadFrom; + } + + } + + private class InstantiationTask implements Runnable { + + private LoadItem loadItem; + + private InstantiationTask(LoadItem loadItem) { + this.loadItem = loadItem; + } + + @Override + public void run() { + IDisplayPane loadTo = loadItem.loadTo; + IRenderableDisplay loadFrom = loadItem.loadFrom; + if (loadTo.getDescriptor() != loadFrom.getDescriptor()) { + load(loadTo, loadFrom); + } + loadTo.getDescriptor().getResourceList() + .instantiateResources(loadTo.getDescriptor(), true); + } + + } + + protected IDisplayPaneContainer container; + + private Bundle bundle; + + public BundleLoader(IDisplayPaneContainer container, Bundle bundle) { + this("Bundle Loader", container, bundle); + } + + protected BundleLoader(String name, IDisplayPaneContainer container, + Bundle bundle) { + super(name); + this.container = container; + this.bundle = bundle; + } + + /** + * Runs the loading synchronously. + */ + public final void run() { + run(new NullProgressMonitor()); + } + + @Override + protected final IStatus run(IProgressMonitor monitor) { + long t0 = System.currentTimeMillis(); + try { + loadBundleToContainer(container, bundle); + if (bundle.getLoopProperties() != null) { + container.setLoopProperties(bundle.getLoopProperties()); + } + + /** refresh the editor */ + container.refresh(); + + if (container instanceof IEditorPart) { + /** update the history list */ + HistoryList.getInstance().refreshLatestBundle( + HistoryList.prepareHistoryEntry(container)); + } + + if (container instanceof IEditorPart) { + VizApp.runAsync(new Runnable() { + @Override + public void run() { + VizGlobalsManager.getCurrentInstance().updateUI( + container); + } + }); + } + } catch (VizException e) { + return new Status(IStatus.ERROR, UiPlugin.PLUGIN_ID, + "Error loading bundle", e); + } + long t2 = System.currentTimeMillis(); + System.out.println("Total bundle retrieval: " + (t2 - t0)); + return Status.OK_STATUS; + } + + /** + * Loads a {@link Bundle} onto an {@link IDisplayPaneContainer} + * + * @param container + * @param bundle + * @throws VizException + */ + private final void loadBundleToContainer(IDisplayPaneContainer container, + Bundle bundle) throws VizException { + LoadItem[] items = getLoadItems(container, bundle); + int numItems = items.length; + + if (numItems > 0) { + Thread[] threads = new Thread[numItems - 1]; + for (int i = 0; i < numItems; ++i) { + Thread t = new Thread(new InstantiationTask(items[i])); + if (i == 0) { + IRenderableDisplay loadFrom = items[i].loadFrom; + IDisplayPane loadTo = items[i].loadTo; + AbstractTimeMatcher srcTimeMatcher = loadFrom + .getDescriptor().getTimeMatcher(); + if (srcTimeMatcher != null) { + loadTo.getDescriptor().getTimeMatcher() + .copyFrom(srcTimeMatcher); + } + loadTo.getDescriptor().getTimeMatcher().resetMultiload(); + t.run(); + } else { + t.start(); + threads[i - 1] = t; + } + } + + for (Thread t : threads) { + try { + t.join(); + } catch (InterruptedException e) { + // Ignore + } + } + } + } + + /** + * Gets the pairing of display->pane loading that should occur. Each item + * will have {@link #load(IDisplayPane, IRenderableDisplay)} called on it + * + * @param container + * @param bundle + * @return + * @throws VizException + */ + protected LoadItem[] getLoadItems(IDisplayPaneContainer container, + Bundle bundle) throws VizException { + IDisplayPane[] containerPanes = container.getDisplayPanes(); + AbstractRenderableDisplay[] bundleDisplays = bundle.getDisplays(); + + if (containerPanes.length != bundleDisplays.length) { + boolean success = ensureOneToOne(container, bundle); + containerPanes = container.getDisplayPanes(); + if (success == false) { + throw new VizException("Unable to load " + + bundleDisplays.length + + " displays onto container with " + + containerPanes.length + " panes"); + } + } + + int numPanes = containerPanes.length; + LoadItem[] items = new LoadItem[numPanes]; + + List orderedDisplays = Arrays + .asList(bundleDisplays); + for (int i = 0; i < numPanes; ++i) { + IDescriptor desc = bundleDisplays[i].getDescriptor(); + if (desc.getTimeMatcher() != null) { + orderedDisplays = desc.getTimeMatcher().getDisplayLoadOrder( + orderedDisplays); + for (AbstractRenderableDisplay d : orderedDisplays) { + d.getDescriptor().synchronizeTimeMatching(desc); + } + break; + } + } + if (orderedDisplays.size() != numPanes) { + throw new VizException( + "Error ordering bundle displays. Number of displays returned not same as passed in"); + } + + int j = 0; + for (AbstractRenderableDisplay display : orderedDisplays) { + for (int i = 0; i < numPanes; ++i) { + if (display == bundleDisplays[i]) { + items[j] = new LoadItem(containerPanes[i], + bundleDisplays[i]); + } + } + ++j; + } + + return items; + } + + /** + * Ensures there is a one to one relationship for number of panes on + * container to number of displays in bundle + * + * @param container + * @param bundle + * @return true of mapping is 1-1, false otherwise + */ + protected boolean ensureOneToOne(IDisplayPaneContainer container, + Bundle bundle) { + IDisplayPane[] containerPanes = container.getDisplayPanes(); + AbstractRenderableDisplay[] bundleDisplays = bundle.getDisplays(); + + // Attempt to match 1-1 pane to display + if (container instanceof IMultiPaneEditor) { + final IMultiPaneEditor mpe = (IMultiPaneEditor) container; + final int numPanes = containerPanes.length; + final int numDisplays = bundleDisplays.length; + final IDisplayPane[] cPanes = containerPanes; + final AbstractRenderableDisplay[] bDisplays = bundleDisplays; + VizApp.runSync(new Runnable() { + @Override + public void run() { + for (int i = numPanes; i < numDisplays; ++i) { + // This will hit if fewer panes than displays + mpe.addPane(bDisplays[i]); + } + for (int i = numDisplays; i < numPanes; ++i) { + // This will hit if fewer displays than panes + mpe.removePane(cPanes[i]); + } + } + }); + } + containerPanes = container.getDisplayPanes(); + return containerPanes.length == bundleDisplays.length; + } + + /** + * Loads the renderable display onto the pane + * + * @param loadTo + * @param loadFrom + */ + protected void load(final IDisplayPane loadTo, + final IRenderableDisplay loadFrom) { + VizApp.runSync(new Runnable() { + @Override + public void run() { + loadTo.setRenderableDisplay(loadFrom); + } + }); + } + + /** + * Gets a bundle object from bundle text, text type is specified by + * {@link BundleInfoType} passed in + * + * @param bundleText + * @param variables + * @param type + * @return + * @throws VizException + */ + public static Bundle getBundle(String bundleText, + Map variables, BundleInfoType type) + throws VizException { + /** Make sure bundle text is not null */ + if (bundleText == null) { + throw new IllegalArgumentException("Bundle text cannot be null"); + } + + Bundle b = null; + /** Is the bundle location the bundle xml or a file with the xml? */ + if (type == BundleInfoType.FILE_LOCATION) { + /** File with xml */ + b = Bundle.unmarshalBundle(PathManagerFactory.getPathManager() + .getStaticFile(bundleText), variables); + } else { + /** bundleLocation variable contains the xml */ + b = Bundle.unmarshalBundle(bundleText, variables); + } + + return b; + } + + /** + * Schedules a {@link BundleLoader} to run to load the bundle on the + * container + * + * @param container + * @param b + */ + public static void loadTo(IDisplayPaneContainer container, Bundle b) { + new BundleLoader(container, b).schedule(); + } +} diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/BundleProductLoader.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/BundleProductLoader.java new file mode 100644 index 0000000000..f24c57d517 --- /dev/null +++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/BundleProductLoader.java @@ -0,0 +1,168 @@ +package com.raytheon.viz.ui; + +import java.util.ArrayList; +import java.util.List; + +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.viz.core.IDisplayPane; +import com.raytheon.uf.viz.core.IDisplayPaneContainer; +import com.raytheon.uf.viz.core.drawables.AbstractRenderableDisplay; +import com.raytheon.uf.viz.core.drawables.IDescriptor; +import com.raytheon.uf.viz.core.drawables.IDescriptor.FramesInfo; +import com.raytheon.uf.viz.core.drawables.IRenderableDisplay; +import com.raytheon.uf.viz.core.drawables.ResourcePair; +import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.uf.viz.core.procedures.Bundle; +import com.raytheon.uf.viz.core.rsc.AbstractResourceData; +import com.raytheon.uf.viz.core.rsc.ResourceList; +import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability; +import com.raytheon.viz.core.ColorUtil; +import com.raytheon.viz.ui.editor.IMultiPaneEditor; + +/** + * + * Loads a bundle as a product to a container. This will add the resources from + * the bundle displays onto the container instead of replacing + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 8, 2013            mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ +public class BundleProductLoader extends BundleLoader { + + public BundleProductLoader(IDisplayPaneContainer container, Bundle bundle) { + super("Product Loader", container, bundle); + } + + @Override + protected LoadItem[] getLoadItems(IDisplayPaneContainer container, + Bundle bundle) throws VizException { + IDisplayPane[] containerPanes = container.getDisplayPanes(); + AbstractRenderableDisplay[] bundleDisplays = bundle.getDisplays(); + + int bundleSize = bundleDisplays.length; + int editorSize = containerPanes.length; + + IDisplayPane[] loadTo; + IRenderableDisplay[] loadFrom; + + IDisplayPane selected = null; + if (container instanceof IMultiPaneEditor) { + selected = ((IMultiPaneEditor) container) + .getSelectedPane(IMultiPaneEditor.LOAD_ACTION); + } + + // Figure out what panes to load to + if (selected != null && bundleSize == 1) { + // Only load to selected pane + loadTo = new IDisplayPane[] { selected }; + loadFrom = new IRenderableDisplay[] { bundleDisplays[0] }; + } else if (bundleSize == 1 && editorSize >= 1) { + loadTo = new IDisplayPane[editorSize]; + loadFrom = new IRenderableDisplay[editorSize]; + for (int i = 0; i < editorSize; ++i) { + loadTo[i] = containerPanes[i]; + loadFrom[i] = bundleDisplays[0].cloneDisplay(); + } + } else { + // Load 1-1 + if (editorSize < bundleSize) { + // If fewer container panes than bundle displays, attempt to + // ensure 1-1 by adding panes + ensureOneToOne(container, bundle); + containerPanes = container.getDisplayPanes(); + editorSize = containerPanes.length; + } + // Load what is possible + int maxCanLoad = Math.min(editorSize, bundleSize); + loadTo = new IDisplayPane[maxCanLoad]; + loadFrom = new IRenderableDisplay[maxCanLoad]; + for (int i = 0; i < maxCanLoad; ++i) { + loadTo[i] = containerPanes[i]; + loadFrom[i] = bundleDisplays[i]; + } + } + + LoadItem[] items = new LoadItem[loadTo.length]; + for (int i = 0; i < items.length; ++i) { + items[i] = new LoadItem(loadTo[i], loadFrom[i]); + } + return items; + } + + @Override + protected void load(IDisplayPane loadTo, IRenderableDisplay loadFrom) { + IDescriptor existingDescriptor = loadTo.getDescriptor(); + IDescriptor fromDescriptor = loadFrom.getDescriptor(); + + /** + * Update the frame count based on what has been listed in the bundle if + * we don't have times already loaded + */ + FramesInfo info = existingDescriptor.getFramesInfo(); + if (info.getFrameCount() == 0) { + existingDescriptor.setNumberOfFrames(fromDescriptor + .getNumberOfFrames()); + } + + // Pull out the resources to load + ResourceList rscs = loadFrom.getDescriptor().getResourceList(); + List resourcesToLoad = new ArrayList(); + + for (ResourcePair rp : rscs) { + if (rp.getProperties().isSystemResource() == false) { + resourcesToLoad.add(rp); + } + } + + rscs.clear(); + + /** + * For each resource pair in the bundle resources: Give a unique color + * for the legend if one isn't set, add to pane's descriptor's resource + * list + */ + for (ResourcePair rp : resourcesToLoad) { + AbstractResourceData ard = rp.getResourceData(); + + try { + ard.configure(rp.getLoadProperties(), existingDescriptor); + } catch (VizException e) { + statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), + e); + } + + boolean newRP = true; + if (existingDescriptor.getResourceList().contains(rp)) { + newRP = false; + } + if (newRP + && (rp.getProperties().isSystemResource() == false && !rp + .getLoadProperties().getCapabilities() + .hasCapability(ColorableCapability.class))) { + rp.getLoadProperties() + .getCapabilities() + .getCapability(rp.getResourceData(), + ColorableCapability.class) + .setColor( + ColorUtil.getNewColor( + container.getDisplayPanes(), + existingDescriptor, rp)); + } + + if (newRP) { + existingDescriptor.getResourceList().add(rp); + } + } + } + +} diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/HistoryList.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/HistoryList.java index 751b7ac625..e399a3d114 100644 --- a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/HistoryList.java +++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/HistoryList.java @@ -256,7 +256,10 @@ public class HistoryList { } public static Bundle prepareHistoryEntry() { - IDisplayPaneContainer cont = EditorUtil.getActiveVizContainer(); + return prepareHistoryEntry(EditorUtil.getActiveVizContainer()); + } + + public static Bundle prepareHistoryEntry(IDisplayPaneContainer cont) { if (cont != null) { Bundle b = new Bundle(); com.raytheon.uf.viz.core.IDisplayPane[] panes = cont diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/MenuLoader.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/MenuLoader.java deleted file mode 100644 index 4c6f180cd4..0000000000 --- a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/MenuLoader.java +++ /dev/null @@ -1,350 +0,0 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ -package com.raytheon.viz.ui; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; - -import com.raytheon.uf.common.localization.PathManagerFactory; -import com.raytheon.uf.common.status.IUFStatusHandler; -import com.raytheon.uf.common.status.UFStatus; -import com.raytheon.uf.common.status.UFStatus.Priority; -import com.raytheon.uf.viz.core.AbstractTimeMatcher; -import com.raytheon.uf.viz.core.IDisplayPane; -import com.raytheon.uf.viz.core.VizApp; -import com.raytheon.uf.viz.core.drawables.IDescriptor; -import com.raytheon.uf.viz.core.drawables.IDescriptor.FramesInfo; -import com.raytheon.uf.viz.core.drawables.IRenderableDisplay; -import com.raytheon.uf.viz.core.drawables.ResourcePair; -import com.raytheon.uf.viz.core.exception.VizException; -import com.raytheon.uf.viz.core.globals.VizGlobalsManager; -import com.raytheon.uf.viz.core.procedures.Bundle; -import com.raytheon.uf.viz.core.rsc.AbstractResourceData; -import com.raytheon.uf.viz.core.rsc.ResourceList; -import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability; -import com.raytheon.viz.core.ColorUtil; -import com.raytheon.viz.ui.editor.AbstractEditor; -import com.raytheon.viz.ui.editor.IMultiPaneEditor; - -/** - * TODO Add Description - * - *
- * 
- * SOFTWARE HISTORY
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * Apr 2, 2009            chammack     Initial creation
- * Apr 7, 2009      2215  jsanchez     Updated the scaleFile.
- * June 25, 2010    1691  bkowal       The frame count for the created / 
- *                                     discovered editor will now be
- *                                     updated to match the frame
- *                                     count that was specified in the bundle.
- * 
- * 
- * - * @author chammack - * @version 1.0 - */ - -public class MenuLoader extends Job { - private static final transient IUFStatusHandler statusHandler = UFStatus - .getHandler(MenuLoader.class); - - private Bundle bundle; - - private AbstractEditor editor; - - private class InstantiationThread extends Thread { - private IDisplayPane loadTo; - - private IRenderableDisplay loadFrom; - - public InstantiationThread(IDisplayPane loadTo, - IRenderableDisplay loadFrom) { - this.loadTo = loadTo; - this.loadFrom = loadFrom; - } - - @Override - public void run() { - IDescriptor existingDescriptor = loadTo.getDescriptor(); - - /** - * Update the frame count based on what has been listed in the - * bundle if we don't have times already loaded - */ - FramesInfo info = existingDescriptor.getFramesInfo(); - if (info.getFrameCount() == 0) { - existingDescriptor.setNumberOfFrames(loadFrom.getDescriptor() - .getNumberOfFrames()); - } - - // Pull out the resources to load - ResourceList rscs = loadFrom.getDescriptor().getResourceList(); - List resourcesToLoad = new ArrayList(); - - for (ResourcePair rp : rscs) { - if (rp.getProperties().isSystemResource() == false) { - resourcesToLoad.add(rp); - } - } - - rscs.clear(); - - /** - * For each resource pair in the bundle resources: Give a unique - * color for the legend if one isn't set, add to pane's descriptor's - * resource list - */ - for (ResourcePair rp : resourcesToLoad) { - AbstractResourceData ard = rp.getResourceData(); - - try { - ard.configure(rp.getLoadProperties(), existingDescriptor); - } catch (VizException e) { - statusHandler.handle(Priority.PROBLEM, - e.getLocalizedMessage(), e); - } - - boolean newRP = true; - if (existingDescriptor.getResourceList().contains(rp)) { - newRP = false; - } - if (newRP - && (rp.getProperties().isSystemResource() == false && !rp - .getLoadProperties().getCapabilities() - .hasCapability(ColorableCapability.class))) { - rp.getLoadProperties() - .getCapabilities() - .getCapability(rp.getResourceData(), - ColorableCapability.class) - .setColor( - ColorUtil.getNewColor( - editor.getDisplayPanes(), - existingDescriptor, rp)); - } - - if (newRP) { - existingDescriptor.getResourceList().add(rp); - } - } - - existingDescriptor.getResourceList().instantiateResources( - existingDescriptor, true); - } - } - - public static enum BundleInfoType { - FILE_LOCATION, XML - } - - public MenuLoader(Bundle b, AbstractEditor editor) { - super("Request EDEX Product"); - this.bundle = b; - this.editor = editor; - } - - public static void loadProduct(final String editorType, - final String bundleLocation, final Map variables) - throws VizException { - loadProduct(editorType, bundleLocation, variables, - BundleInfoType.FILE_LOCATION); - } - - public static void loadProduct(String editorType, String bundleLocation, - Map variables, BundleInfoType type) - throws VizException { - Bundle b = null; - - /** Make sure bundle location is not null */ - if (bundleLocation == null) { - throw new VizException("bundleLocation was null"); - } - - /** Is the bundle location the bundle xml or a file with the xml? */ - if (type.equals(BundleInfoType.FILE_LOCATION)) { - /** File with xml */ - b = Bundle.unmarshalBundle(PathManagerFactory.getPathManager() - .getStaticFile(bundleLocation), variables); - } else { - /** bundleLocation variable contains the xml */ - b = Bundle.unmarshalBundle(bundleLocation, null); - } - - /** Load the editor from the bundle */ - AbstractEditor editor = null; - editor = UiUtil.createOrOpenEditor(editorType, b.getDisplays()); - - /** Error loading the editor */ - if (editor == null) { - throw new VizException("unable to get editor: " + editorType); - } - - /** - * If the descriptor in the bundle did not get set as the descriptor in - * the editor, we need to go through and add the resources in the - * bundle's IDisplayPane's descriptor to the editor's IDisplayPane's - * descriptor, which is done in the job - */ - if (editor.getDisplayPanes()[0].getDescriptor() != b.getDisplays()[0] - .getDescriptor()) { - Job j = new MenuLoader(b, editor); - j.schedule(); - } else { - /** - * The editor and bundle have the same descriptors meaning the - * editor was opened from the bundle so we need to instantiate the - * resources on them only (this needs to be done outside the job bc - * paint will be called immediately after this and the resources may - * not have been instantiated yet. - * - * TODO: There may be a way to create a list of resources from the - * bundle and in this statement just remove the resources from the - * editor then re add them in the job. so this doesn't hang on - * construction of the resource - */ - for (IDisplayPane pane : editor.getDisplayPanes()) { - pane.getDescriptor().getResourceList() - .instantiateResources(pane.getDescriptor(), true); - } - HistoryList.getInstance().refreshLatestBundle(); - } - - } - - @Override - protected IStatus run(IProgressMonitor monitor) { - long t0 = System.currentTimeMillis(); - try { - /** extracted to method when doing a refactor, not really needed */ - loadExisting(); - /** refresh the editor */ - editor.refresh(); - /** update the history list */ - HistoryList.getInstance().refreshLatestBundle(); - } catch (VizException e) { - return new Status(IStatus.ERROR, UiPlugin.PLUGIN_ID, - "Error loading bundle", e); - } - long t2 = System.currentTimeMillis(); - System.out.println("Total bundle retrieval: " + (t2 - t0)); - return Status.OK_STATUS; - } - - private void loadExisting() throws VizException { - IDisplayPane selected = null; - if (editor instanceof IMultiPaneEditor) { - selected = ((IMultiPaneEditor) editor) - .getSelectedPane(IMultiPaneEditor.LOAD_ACTION); - } - - int bundleSize = bundle.getDisplays().length; - int editorSize = editor.getDisplayPanes().length; - - List loadToPanes = new ArrayList(); - List loadFromBundle = new ArrayList(); - List executionThreads = new ArrayList(); - - // Figure out what panes to load to - if (selected != null && bundleSize == 1) { - loadToPanes.add(selected); - loadFromBundle.add(bundle.getDisplays()[0]); - } else if (selected == null && bundleSize == 1) { - // load to all panes the single bundle display - for (IDisplayPane pane : editor.getDisplayPanes()) { - loadToPanes.add(pane); - loadFromBundle.add(bundle.getDisplays()[0].cloneDisplay()); - } - } else { - int max = Math.max(bundleSize, editorSize); - for (int i = 0; i < max; ++i) { - if (editorSize > i) { - loadToPanes.add(editor.getDisplayPanes()[i]); - } else { - loadToPanes.add(null); - } - - if (bundleSize > i) { - loadFromBundle.add(bundle.getDisplays()[i]); - } else { - loadFromBundle.add(null); - } - } - } - - for (int i = 0; i < loadToPanes.size(); ++i) { - IDisplayPane loadTo = loadToPanes.get(i); - final IRenderableDisplay loadFrom = loadFromBundle.get(i); - if (i == 0) { - AbstractTimeMatcher srcTimeMatcher = loadFrom.getDescriptor() - .getTimeMatcher(); - if (srcTimeMatcher != null) { - loadTo.getDescriptor().getTimeMatcher() - .copyFrom(srcTimeMatcher); - } - loadTo.getDescriptor().getTimeMatcher().resetMultiload(); - new InstantiationThread(loadTo, loadFrom).run(); - continue; - } - - if (loadFrom == null) { - continue; - } else if (loadTo == null) { - if (editor instanceof IMultiPaneEditor) { - VizApp.runSync(new Runnable() { - @Override - public void run() { - ((IMultiPaneEditor) (editor)).addPane(loadFrom); - } - }); - - } - continue; - } - - Thread t = new InstantiationThread(loadTo, loadFrom); - t.start(); - executionThreads.add(t); - } - - for (Thread t : executionThreads) { - try { - t.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - VizApp.runAsync(new Runnable() { - @Override - public void run() { - VizGlobalsManager.getCurrentInstance().updateUI(editor); - } - }); - - } -} diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/actions/LoadSerializedXml.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/actions/LoadSerializedXml.java index 86ee7cfa47..33fa3207dc 100644 --- a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/actions/LoadSerializedXml.java +++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/actions/LoadSerializedXml.java @@ -20,9 +20,6 @@ package com.raytheon.viz.ui.actions; import java.io.File; -import java.util.Arrays; -import java.util.List; -import java.util.Map; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; @@ -46,21 +43,16 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.viz.core.DescriptorMap; -import com.raytheon.uf.viz.core.IDisplayPane; import com.raytheon.uf.viz.core.IDisplayPaneContainer; -import com.raytheon.uf.viz.core.VizApp; -import com.raytheon.uf.viz.core.drawables.AbstractRenderableDisplay; import com.raytheon.uf.viz.core.drawables.IDescriptor; import com.raytheon.uf.viz.core.drawables.IRenderableDisplay; import com.raytheon.uf.viz.core.exception.VizException; -import com.raytheon.uf.viz.core.globals.VizGlobalsManager; import com.raytheon.uf.viz.core.procedures.Bundle; import com.raytheon.uf.viz.core.procedures.Procedure; -import com.raytheon.uf.viz.core.rsc.ResourceList; +import com.raytheon.viz.ui.BundleLoader; import com.raytheon.viz.ui.UiUtil; import com.raytheon.viz.ui.VizWorkbenchManager; import com.raytheon.viz.ui.editor.AbstractEditor; -import com.raytheon.viz.ui.editor.IMultiPaneEditor; /** * Handles loading of bundles or procedures @@ -133,11 +125,10 @@ public class LoadSerializedXml extends AbstractHandler { IDescriptor bundleDescriptor = renderableDisplay.getDescriptor(); String bundleEditorId = DescriptorMap.getEditorId(bundleDescriptor .getClass().getName()); - synchronizeDisplays(bundle); AbstractEditor editor = UiUtil.createOrOpenEditor(bundleEditorId, bundle.getDisplays()); - loadTo(editor, bundle); + BundleLoader.loadTo(editor, bundle); } public static void loadProcedureToScreen(Procedure procedure, @@ -183,7 +174,6 @@ public class LoadSerializedXml extends AbstractHandler { for (Bundle b : bundles) { // If an editor is specified, or no view part is specified, // assume an editor part - synchronizeDisplays(b); if (b.getView() == null) { String editorName = b.getEditor(); AbstractEditor openedEditor = UiUtil.createEditor(editorName, @@ -202,33 +192,22 @@ public class LoadSerializedXml extends AbstractHandler { } } - loadTo(openedEditor, b); + BundleLoader.loadTo(openedEditor, b); } else { // There is a view part specified IViewPart part = UiUtil.findView(windowToLoadTo, b.getView(), false); if (part != null && part instanceof IDisplayPaneContainer) { - loadTo((IDisplayPaneContainer) part, b); + BundleLoader.loadTo((IDisplayPaneContainer) part, b); } } } } - private static void synchronizeDisplays(Bundle b) { - IDescriptor firstDesc = null; - for (AbstractRenderableDisplay d : b.getDisplays()) { - if (firstDesc == null) { - firstDesc = d.getDescriptor(); - } else { - d.getDescriptor().synchronizeTimeMatching(firstDesc); - } - } - } - /** - * Load a bundle to a container + * Use {@link BundleLoader} instead * * @param editor * the container to load to @@ -236,119 +215,10 @@ public class LoadSerializedXml extends AbstractHandler { * the bundle * @throws VizException */ - public static void loadTo(final IDisplayPaneContainer container, - final Bundle b) throws VizException { - final int containerSize = container.getDisplayPanes().length; - final boolean multiEditor = container instanceof IMultiPaneEditor; - - if (multiEditor) { - if (container.getDisplayPanes().length > b.getDisplays().length) { - VizApp.runSync(new Runnable() { - @Override - public void run() { - while (container.getDisplayPanes().length > b - .getDisplays().length) { - ((IMultiPaneEditor) container).removePane(container - .getDisplayPanes()[container - .getDisplayPanes().length - 1]); - } - } - }); - } - - } - List orderedDisplays = Arrays.asList(b - .getDisplays()); - IDescriptor firstDesc = orderedDisplays.get(0).getDescriptor(); - if (firstDesc != null && firstDesc.getTimeMatcher() != null) { - orderedDisplays = firstDesc.getTimeMatcher().getDisplayLoadOrder( - orderedDisplays); - } - for (AbstractRenderableDisplay d : orderedDisplays) { - d.getDescriptor().synchronizeTimeMatching(firstDesc); - ResourceList rl = d.getDescriptor().getResourceList(); - rl.instantiateResources(d.getDescriptor(), true); - } - - final VizException[] errors = new VizException[1]; - - VizApp.runSync(new Runnable() { - @Override - public void run() { - int i = 0; - for (AbstractRenderableDisplay d : b.getDisplays()) { - if (i >= containerSize && multiEditor) { - ((IMultiPaneEditor) container).addPane(d); - } else if (i >= containerSize) { - errors[0] = new VizException( - "Unable to add panes to non IMultiPaneEditor"); - return; - } else { - IRenderableDisplay oldDisplay = container - .getDisplayPanes()[i].getRenderableDisplay(); - if (oldDisplay != null && oldDisplay != d) { - oldDisplay.dispose(); - } - container.getDisplayPanes()[i].setRenderableDisplay(d); - container.getDisplayPanes()[i].resize(); - container.getDisplayPanes()[i].refresh(); - } - i++; - } - - if (b.getLoopProperties() != null) { - container.setLoopProperties(b.getLoopProperties()); - } - - // if loading to an editor, update the globals - if (container instanceof IEditorPart) { - VizGlobalsManager.getCurrentInstance().updateUI(container); - } - } - }); - - if (errors[0] != null) { - throw errors[0]; - } - } - - /** - * Load a bundle from a file into a container - * - * @param editor - * the container to load to - * @param f - * the file containing the bundle - * @param descriptor - * Optional: A descriptor that should be used for time matching - * @throws VizException - */ - public static void loadTo(File f, Map variables) + @Deprecated + public static void loadTo(final IDisplayPaneContainer container, Bundle b) throws VizException { - Bundle b = Bundle.unmarshalBundle(f, variables); - - IRenderableDisplay renderableDisplay = b.getDisplays()[0]; - IDescriptor bundleDescriptor = renderableDisplay.getDescriptor(); - String bundleEditorId = DescriptorMap.getEditorId(bundleDescriptor - .getClass().getName()); - AbstractEditor editor = UiUtil.createOrOpenEditor(bundleEditorId, - b.getDisplays()); - - loadTo(editor, b); + new BundleLoader(container, b).run(); } - public static void loadTo(IDisplayPane pane, File f, - Map variables) throws VizException { - - Bundle b = Bundle.unmarshalBundle(f, variables); - - for (AbstractRenderableDisplay d : b.getDisplays()) { - ResourceList rl = d.getDescriptor().getResourceList(); - rl.instantiateResources(d.getDescriptor(), true); - - pane.setRenderableDisplay(d); - pane.resize(); - pane.refresh(); - } - } } diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/perspectives/AbstractVizPerspectiveManager.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/perspectives/AbstractVizPerspectiveManager.java index 5636abbd62..779fd25940 100644 --- a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/perspectives/AbstractVizPerspectiveManager.java +++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/perspectives/AbstractVizPerspectiveManager.java @@ -136,6 +136,20 @@ public abstract class AbstractVizPerspectiveManager implements @Override public void partDeactivated(IWorkbenchPart part) { + // update editor on last selected modal tool + if (part instanceof IEditorPart + && part instanceof IDisplayPaneContainer) { + AbstractVizPerspectiveManager mgr = VizPerspectiveListener + .getCurrentPerspectiveManager(); + if (mgr != null) { + for (AbstractModalTool tool : mgr.getToolManager() + .getSelectedModalTools()) { + if (tool.getCurrentEditor() == part) { + tool.deactivate(); + } + } + } + } } @Override @@ -362,12 +376,6 @@ public abstract class AbstractVizPerspectiveManager implements page.hideEditor(ref); } - for (AbstractModalTool tool : toolManager.getSelectedModalTools()) { - if (tool != null) { - tool.deactivate(); - } - } - deactivateDialogs(); deactivateContexts(); removeFromStatusLine(); diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/tools/AbstractModalTool.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/tools/AbstractModalTool.java index 450b1860df..64da65bfb4 100644 --- a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/tools/AbstractModalTool.java +++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/tools/AbstractModalTool.java @@ -156,6 +156,7 @@ public abstract class AbstractModalTool extends AbstractTool { this.setEnabled(false); if (editor != null) { deactivateTool(); + editor = null; } } diff --git a/cave/com.raytheon.viz.volumebrowser/src/com/raytheon/viz/volumebrowser/vbui/ProductTableComp.java b/cave/com.raytheon.viz.volumebrowser/src/com/raytheon/viz/volumebrowser/vbui/ProductTableComp.java index acc2eaff5f..11ff433ab4 100644 --- a/cave/com.raytheon.viz.volumebrowser/src/com/raytheon/viz/volumebrowser/vbui/ProductTableComp.java +++ b/cave/com.raytheon.viz.volumebrowser/src/com/raytheon/viz/volumebrowser/vbui/ProductTableComp.java @@ -88,7 +88,7 @@ import com.raytheon.viz.core.slice.request.VerticalPointRequest.TimeDirection; import com.raytheon.viz.skewt.SkewtDisplay; import com.raytheon.viz.skewt.rscdata.SkewTResourceData; import com.raytheon.viz.ui.EditorUtil; -import com.raytheon.viz.ui.MenuLoader; +import com.raytheon.viz.ui.BundleProductLoader; import com.raytheon.viz.ui.UiUtil; import com.raytheon.viz.ui.editor.AbstractEditor; import com.raytheon.viz.ui.editor.IMultiPaneEditor; @@ -1078,7 +1078,7 @@ public class ProductTableComp extends Composite { Bundle b = new Bundle(); b.setDisplays(new AbstractRenderableDisplay[] { display }); - Job j = new MenuLoader(b, editor); + Job j = new BundleProductLoader(editor, b); j.schedule(); } } diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java index e44dbcf3a5..9ef6bc3676 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java @@ -15,6 +15,7 @@ import org.geotools.referencing.GeodeticCalculator; import com.raytheon.uf.common.dataplugin.warning.config.PathcastConfiguration; import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration; +import com.raytheon.uf.common.dataplugin.warning.gis.PreparedGeometryCollection; import com.raytheon.uf.common.dataquery.requests.RequestConstraint; import com.raytheon.uf.common.geospatial.SpatialQueryResult; import com.raytheon.uf.viz.core.exception.VizException; @@ -26,7 +27,6 @@ import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.prep.PreparedGeometry; -import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; /** * @@ -146,7 +146,7 @@ public class DbAreaSourceDataAdaptor extends AbstractDbSourceDataAdaptor { boolean userDirections = Boolean.valueOf(String.valueOf(attributes .get(useDirectionField))); if (userDirections) { - PreparedGeometry prepGeom = PreparedGeometryFactory.prepare(geom); + PreparedGeometry prepGeom = new PreparedGeometryCollection(geom); if (prepGeom.intersects(searchArea) && !prepGeom.within(searchArea)) { Geometry intersection = searchArea.intersection(geom); partOfArea = GisUtil.asStringList(calculateLocationPortion( diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Area.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Area.java index ea42c71a28..018126daa8 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Area.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Area.java @@ -50,6 +50,7 @@ import com.raytheon.viz.warngen.gui.WarngenLayer; import com.raytheon.viz.warngen.suppress.SuppressMap; import com.raytheon.viz.warngen.util.Abbreviation; import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.prep.PreparedGeometry; /** * Area @@ -176,6 +177,7 @@ public class Area { GeodeticCalculator gc = new GeodeticCalculator(); for (GeospatialData regionFeature : countyMap.values()) { Geometry regionGeom = regionFeature.geometry; + PreparedGeometry preparedRegionGeom = regionFeature.prepGeom; AffectedAreas area = new AffectedAreas(); area.name = regionFeature.attributes.get(areaField).toString(); area.fips = regionFeature.attributes.get(fipsField).toString(); @@ -237,7 +239,7 @@ public class Area { if (ptFeatures != null) { List pointList = new ArrayList(); for (SpatialQueryResult ptRslt : ptFeatures) { - if (regionGeom.contains(ptRslt.geometry)) { + if (preparedRegionGeom.contains(ptRslt.geometry)) { pointList.add(String.valueOf(ptRslt.attributes .get(pointField))); } @@ -331,7 +333,7 @@ public class Area { } return retVal; } - + public static List converFeAreaToPartList(String feArea) { final List partList = new ArrayList(); if (feArea == null) { diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java index 538a6294a7..f677f85ae4 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java @@ -29,6 +29,7 @@ import java.util.List; import org.geotools.referencing.GeodeticCalculator; +import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil; import com.raytheon.viz.warngen.suppress.SuppressMap; import com.vividsolutions.jts.algorithm.CGAlgorithms; import com.vividsolutions.jts.geom.Coordinate; @@ -37,7 +38,6 @@ import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Polygon; /** @@ -206,27 +206,21 @@ public class GisUtil { yDirection = Direction.SOUTH; } + List geoms = new ArrayList(geom.getNumGeometries()); + GeometryUtil.buildGeometryList(geoms, geom); boolean isExtreme = false; - Coordinate[] coords; - if (geom instanceof Polygon) { - LineString lineString = ((Polygon) geom).getExteriorRing(); - coords = lineString.getCoordinates(); - isExtreme = isExtreme(coords, point, - (extremaThresholdX + extremaThresholdY) / 2.0); - } else if (geom instanceof MultiPolygon) { - int geoms = ((MultiPolygon) geom).getNumGeometries(); - for (int i = 0; i < geoms; i++) { - LineString lineString = ((Polygon) ((MultiPolygon) geom) - .getGeometryN(i)).getExteriorRing(); - coords = lineString.getCoordinates(); - if (isExtreme(coords, point, + for (Geometry g : geoms) { + if (g instanceof Polygon) { + LineString lineString = ((Polygon) g).getExteriorRing(); + if (isExtreme(lineString.getCoordinates(), point, (extremaThresholdX + extremaThresholdY) / 2.0)) { isExtreme = true; break; } } } + EnumSet retVal = EnumSet.noneOf(Direction.class); if (xDirection != null && !suppressType.equals(SuppressMap.EAST_WEST) diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PolygonUtil.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PolygonUtil.java index 1d65601dd9..cf583d39d3 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PolygonUtil.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PolygonUtil.java @@ -30,6 +30,7 @@ import org.geotools.referencing.operation.DefaultMathTransformFactory; import org.opengis.metadata.spatial.PixelOrientation; import org.opengis.referencing.operation.MathTransform; +import com.raytheon.uf.common.dataplugin.warning.gis.PreparedGeometryCollection; import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil; import com.raytheon.uf.viz.core.IExtent; import com.raytheon.uf.viz.core.exception.VizException; @@ -44,7 +45,6 @@ import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineSegment; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.prep.PreparedGeometry; -import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; /** * Utility for polygon operations @@ -57,7 +57,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; * ------------ ---------- ----------- -------------------------- * Dec 1, 2010 mschenke Initial creation * 12/06/2012 DR 15559 Qinglu Lin Added round() methods. - * + * * * * @author mschenke @@ -850,7 +850,7 @@ public class PolygonUtil { List prepped = new ArrayList( geomList.size()); for (Geometry g : geomList) { - prepped.add(PreparedGeometryFactory.prepare(g)); + prepped.add(new PreparedGeometryCollection(g)); } GeometryFactory gf = warningArea.getFactory(); @@ -931,56 +931,54 @@ public class PolygonUtil { } } } - - public static void truncate(Listcoordinates, int decimalPlaces) { + + public static void truncate(List coordinates, int decimalPlaces) { for (Coordinate coordinate : coordinates) { truncate(coordinate, decimalPlaces); } } - + public static void truncate(Coordinate[] coordinates, int decimalPlaces) { for (Coordinate coordinate : coordinates) { truncate(coordinate, decimalPlaces); } } - + public static void truncate(Coordinate coordinate, int decimalPlaces) { double x = coordinate.x * Math.pow(10, decimalPlaces); double y = coordinate.y * Math.pow(10, decimalPlaces); - + x = x >= 0 ? Math.floor(x) : Math.ceil(x); y = y >= 0 ? Math.floor(y) : Math.ceil(y); - + coordinate.x = x / Math.pow(10, decimalPlaces); coordinate.y = y / Math.pow(10, decimalPlaces); } - public static void round(Listcoordinates, int decimalPlaces) { + public static void round(List coordinates, int decimalPlaces) { for (Coordinate coordinate : coordinates) { round(coordinate, decimalPlaces); } } - + public static void round(Coordinate[] coordinates, int decimalPlaces) { for (Coordinate coordinate : coordinates) { round(coordinate, decimalPlaces); } } - + /** - * round() - * Rounding coordinates, instead of truncating them. - * - * History - * 12/06/2012 DR 15559 Qinglu Lin Created. + * round() Rounding coordinates, instead of truncating them. + * + * History 12/06/2012 DR 15559 Qinglu Lin Created. */ public static void round(Coordinate coordinate, int decimalPlaces) { double x = coordinate.x * Math.pow(10, decimalPlaces); double y = coordinate.y * Math.pow(10, decimalPlaces); - + x = Math.round(x); y = Math.round(y); - + coordinate.x = x / Math.pow(10, decimalPlaces); coordinate.y = y / Math.pow(10, decimalPlaces); } diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gui/WarngenLayer.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gui/WarngenLayer.java index 5887eb290d..c7736358ac 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gui/WarngenLayer.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gui/WarngenLayer.java @@ -24,13 +24,13 @@ import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.TimeZone; import java.util.regex.Matcher; @@ -40,10 +40,15 @@ import javax.measure.converter.UnitConverter; import javax.measure.unit.NonSI; import javax.measure.unit.SI; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IMenuManager; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; import org.eclipse.ui.PlatformUI; import org.geotools.geometry.jts.JTS; import org.geotools.referencing.GeodeticCalculator; @@ -60,6 +65,7 @@ import com.raytheon.uf.common.dataplugin.warning.config.WarngenConfiguration; import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialData; import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialFactory; import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialMetadata; +import com.raytheon.uf.common.dataplugin.warning.gis.PreparedGeometryCollection; import com.raytheon.uf.common.dataplugin.warning.util.CountyUserData; import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil; import com.raytheon.uf.common.geospatial.DestinationGeodeticCalculator; @@ -118,7 +124,6 @@ import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.TopologyException; import com.vividsolutions.jts.geom.prep.PreparedGeometry; -import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKTReader; @@ -152,10 +157,10 @@ import com.vividsolutions.jts.io.WKTReader; * 12/13/2012 DR 15559 Qinglu Lin Added code to call WarngenUIState's adjustPolygon(). * 12/17/2012 DR 15571 Qinglu Lin For hydro products,futurePoints is null. Resolved an issue caused by trying to get * Coordinate[] from futurePoints. - * 12/18/2012 DR 15571 Qinglu Lin Resolved coordinate issue in TML line caused by clicking Restart button. + * 12/18/2012 DR 15571 Qinglu Lin Resolved coordinate issue in TML line caused by clicking Restart button. * 01/24/2013 DR 15723 Qinglu Lin Added initRemovedGids() and updated updateWarnedAreas() to prevent the removed * counties from being re-hatched. - * + * * * * @author mschenke @@ -183,6 +188,60 @@ public class WarngenLayer extends AbstractStormTrackResource { int nx, ny; } + private class CustomMaps extends Job { + + private Set customMaps = new HashSet(); + + private Set mapsToLoad; + + private MapManager manager; + + public CustomMaps() { + super("Loading WarnGen Maps"); + manager = MapManager.getInstance(descriptor); + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + boolean done = false; + while (!done) { + Set toLoad = null; + synchronized (this) { + if (mapsToLoad != null) { + toLoad = mapsToLoad; + mapsToLoad = null; + } + } + + if (toLoad != null) { + for (String loaded : customMaps) { + manager.unloadMap(loaded); + } + + for (String load : toLoad) { + manager.loadMapByName(load); + } + + issueRefresh(); + } + + done = mapsToLoad == null; + } + return Status.OK_STATUS; + } + + public void loadCustomMaps(Collection maps) { + synchronized (this) { + mapsToLoad = new HashSet(maps); + } + schedule(); + } + + public void clearMaps() { + loadCustomMaps(new HashSet()); + } + } + private static Map siteMap = new HashMap(); private static Map timezoneMap = new HashMap(); @@ -222,7 +281,7 @@ public class WarngenLayer extends AbstractStormTrackResource { private boolean boxEditable = true; - private Map> loadedCustomMaps; + private CustomMaps customMaps; protected Mode lastMode = null; @@ -264,7 +323,7 @@ public class WarngenLayer extends AbstractStormTrackResource { super(resourceData, loadProperties, descriptor); displayState.displayType = DisplayType.POINT; getCapability(ColorableCapability.class).setColor(WHITE); - loadedCustomMaps = new HashMap>(); + customMaps = new CustomMaps(); try { dialogConfig = DialogConfiguration @@ -389,13 +448,7 @@ public class WarngenLayer extends AbstractStormTrackResource { @Override protected void disposeInternal() { - for (Entry> entry : loadedCustomMaps - .entrySet()) { - for (String map : entry.getValue()) { - MapManager.getInstance(entry.getKey()).unloadMap(map); - } - } - loadedCustomMaps.clear(); + customMaps.clearMaps(); super.disposeInternal(); @@ -436,7 +489,6 @@ public class WarngenLayer extends AbstractStormTrackResource { } super.initInternal(target); VizApp.runSync(new Runnable() { - @Override public void run() { createDialog(); @@ -497,17 +549,17 @@ public class WarngenLayer extends AbstractStormTrackResource { displayState.geomChanged = false; } if (warningAction == null || warningAction == WarningAction.NEW) { - // Initialize box - if (((configuration.isTrackEnabled() == false || configuration - .getPathcastConfig() == null) && this.displayState.displayType != DisplayType.POLY) - || frameCount == 1) { - createSquare(); - resetInitialFrame(); - } else { - redrawBoxFromTrack(); - } + // Initialize box + if (((configuration.isTrackEnabled() == false || configuration + .getPathcastConfig() == null) && this.displayState.displayType != DisplayType.POLY) + || frameCount == 1) { + createSquare(); + resetInitialFrame(); + } else { + redrawBoxFromTrack(); + } } else { - redrawBoxFromTrack(); + redrawBoxFromTrack(); } } @@ -750,7 +802,7 @@ public class WarngenLayer extends AbstractStormTrackResource { local); gd.attributes.put( GeospatialDataList.LOCAL_PREP_GEOM, - PreparedGeometryFactory.prepare(local)); + new PreparedGeometryCollection(local)); locals.add(local); } @@ -829,43 +881,11 @@ public class WarngenLayer extends AbstractStormTrackResource { String areaSource = config.getGeospatialConfig().getAreaSource(); geoData = siteMap.get(areaSource + "." + site); }// end synchronize - loadCustomMaps(descriptor, config); - this.configuration = config; - System.out.println("Time to init warngen config: " - + (System.currentTimeMillis() - t0)); - } + customMaps.loadCustomMaps(Arrays.asList(config.getMaps())); - protected void loadCustomMaps(MapDescriptor descriptor, - WarngenConfiguration config) { - if (config == null || descriptor == null) { - return; - } - long t1 = System.currentTimeMillis(); - MapManager mapManager = MapManager.getInstance(descriptor); - List maps = Arrays.asList(config.getMaps()); - Set loadedCustomMaps = this.loadedCustomMaps.get(descriptor); - if (loadedCustomMaps == null) { - loadedCustomMaps = new HashSet(); - this.loadedCustomMaps.put(descriptor, loadedCustomMaps); - } - Iterator it = loadedCustomMaps.iterator(); - while (it.hasNext()) { - String map = it.next(); - if (!maps.contains(map)) { - it.remove(); - mapManager.unloadMap(map); - } - } - for (String map : maps) { - if (!loadedCustomMaps.contains(map)) { - if (!mapManager.isMapLoaded(map)) { - mapManager.loadMapByName(map); - loadedCustomMaps.add(map); - } - } - } - System.out.println("Time to load custom maps: " - + (System.currentTimeMillis() - t1)); + this.configuration = config; + System.out.println("Total time to init warngen config = " + + (System.currentTimeMillis() - t0) + "ms"); } public GeospatialData[] getGeodataFeatures(String key) { @@ -1107,30 +1127,17 @@ public class WarngenLayer extends AbstractStormTrackResource { dialog = new WarngenDialog(PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell(), this); dialog.open(); - addDialogDisposeListener(descriptor); - } else { - showDialog(true); - } - } - - public void addDialogDisposeListener(final MapDescriptor descriptor) { - if (dialog != null) { - dialog.getShell().addDisposeListener(new DisposeListener() { + dialog.addListener(SWT.Dispose, new Listener() { @Override - public void widgetDisposed(DisposeEvent e) { + public void handleEvent(Event event) { descriptor.getResourceList().removeRsc(WarngenLayer.this); } }); + } else { + showDialog(true); } } - @Override - public void setDescriptor(MapDescriptor descriptor) { - super.setDescriptor(descriptor); - addDialogDisposeListener(descriptor); - loadCustomMaps(descriptor, configuration); - } - /** * Show the WarnGen dialog and move it to the front. */ @@ -1625,15 +1632,15 @@ public class WarngenLayer extends AbstractStormTrackResource { if (hatched != null) { // DR 15559 Coordinate[] coords = hatched.getCoordinates(); - PolygonUtil.round(coords, 2); - state.adjustPolygon(coords); - GeometryFactory gf = new GeometryFactory(); - LinearRing lr = gf.createLinearRing(coords); - state.setWarningPolygon(gf.createPolygon(lr, null)); - updateWarnedAreas(true, true); - issueRefresh(); - // End of DR 15559 - state.snappedToArea = true; + PolygonUtil.round(coords, 2); + state.adjustPolygon(coords); + GeometryFactory gf = new GeometryFactory(); + LinearRing lr = gf.createLinearRing(coords); + state.setWarningPolygon(gf.createPolygon(lr, null)); + updateWarnedAreas(true, true); + issueRefresh(); + // End of DR 15559 + state.snappedToArea = true; } System.out.println("Time to createWarningPolygon: " + (System.currentTimeMillis() - t0) + "ms"); @@ -1852,16 +1859,20 @@ public class WarngenLayer extends AbstractStormTrackResource { Coordinate[] cc = null; switch (stormTrackState.displayType) { case POINT: - cc = new Coordinate[] { stormTrackState.futurePoints == null ? stormTrackState.dragMePoint - .getCoordinate() : stormTrackState.futurePoints[0].coord }; - if (warningAction == null || warningAction == WarningAction.NEW || warningAction == WarningAction.CON - || warningAction == WarningAction.CAN) { - Coordinate coord = new Coordinate(stormTrackState.dragMePoint.getCoordinate()); - DataTime currentDataTime = new DataTime(SimulatedTime.getSystemTime().getTime()); - if (stormTrackState.compuateCurrentStormCenter(coord,currentDataTime)) - cc = new Coordinate[] {coord}; - } - break; + cc = new Coordinate[] { stormTrackState.futurePoints == null ? stormTrackState.dragMePoint + .getCoordinate() : stormTrackState.futurePoints[0].coord }; + if (warningAction == null || warningAction == WarningAction.NEW + || warningAction == WarningAction.CON + || warningAction == WarningAction.CAN) { + Coordinate coord = new Coordinate( + stormTrackState.dragMePoint.getCoordinate()); + DataTime currentDataTime = new DataTime(SimulatedTime + .getSystemTime().getTime()); + if (stormTrackState.compuateCurrentStormCenter(coord, + currentDataTime)) + cc = new Coordinate[] { coord }; + } + break; case POLY: Coordinate[] polyPoints = stormTrackState.dragMeLine .getCoordinates(); @@ -2378,9 +2389,9 @@ public class WarngenLayer extends AbstractStormTrackResource { + e.getLocalizedMessage(), e); } } - + public void setWarningAction(WarningAction warningAction) { - this.warningAction = warningAction; + this.warningAction = warningAction; } public void initRemovedGids() { diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/CurrentWarnings.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/CurrentWarnings.java index dab39fd1fd..d82e4d996b 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/CurrentWarnings.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/CurrentWarnings.java @@ -20,6 +20,7 @@ package com.raytheon.viz.warngen.util; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; @@ -37,8 +38,10 @@ import com.raytheon.uf.common.dataplugin.warning.UGCZone; import com.raytheon.uf.common.dataplugin.warning.WarningRecord; import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction; import com.raytheon.uf.common.dataplugin.warning.util.AnnotationUtil; +import com.raytheon.uf.common.dataquery.requests.DbQueryRequest; import com.raytheon.uf.common.dataquery.requests.RequestConstraint; import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType; +import com.raytheon.uf.common.dataquery.responses.DbQueryResponse; import com.raytheon.uf.common.site.SiteMap; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; @@ -46,10 +49,8 @@ import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.SimulatedTime; import com.raytheon.uf.common.time.TimeRange; import com.raytheon.uf.viz.core.alerts.AlertMessage; -import com.raytheon.uf.viz.core.catalog.LayerProperty; -import com.raytheon.uf.viz.core.catalog.ScriptCreator; -import com.raytheon.uf.viz.core.comm.Connector; -import com.raytheon.uf.viz.core.rsc.ResourceType; +import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.uf.viz.core.requests.ThriftClient; import com.raytheon.viz.alerts.IAlertObserver; import com.raytheon.viz.alerts.observers.ProductAlertObserver; import com.raytheon.viz.core.mode.CAVEMode; @@ -187,7 +188,8 @@ public class CurrentWarnings { * @param phenSigs * @return */ - public List getCorrectableWarnings(AbstractWarningRecord warnRec) { + public List getCorrectableWarnings( + AbstractWarningRecord warnRec) { List rval = new ArrayList(); Calendar current = Calendar.getInstance(); Calendar end = Calendar.getInstance(); @@ -197,24 +199,28 @@ public class CurrentWarnings { for (AbstractWarningRecord warning : records) { String phensig = warning.getPhensig(); String etn = warning.getEtn(); - - if (warnRec.getPhensig().equals(phensig) && warnRec.getEtn().equals(etn)) { - WarningAction action = WarningAction.valueOf(warning.getAct()); + + if (warnRec.getPhensig().equals(phensig) + && warnRec.getEtn().equals(etn)) { + WarningAction action = WarningAction.valueOf(warning + .getAct()); end.setTime(warning.getStartTime().getTime()); end.add(Calendar.MINUTE, 10); - TimeRange t = new TimeRange(warning.getStartTime().getTime(), - end.getTime()); - if ((action == WarningAction.NEW || action == WarningAction.CON || action == WarningAction.EXT) + TimeRange t = new TimeRange(warning.getStartTime() + .getTime(), end.getTime()); + if ((action == WarningAction.NEW + || action == WarningAction.CON || action == WarningAction.EXT) && t.contains(current.getTime())) { rval.add(warning); - } else if (action == WarningAction.CAN || action == WarningAction.EXP) { + } else if (action == WarningAction.CAN + || action == WarningAction.EXP) { rval.clear(); return rval; } } } } - + return rval; } @@ -253,7 +259,7 @@ public class CurrentWarnings { for (AbstractWarningRecord warning : warnings) { if (getAction(warning.getAct()) == WarningAction.CON) { if (rval != null) { - //rval.setAct("CON"); + // rval.setAct("CON"); rval.setGeometry(warning.getGeometry()); rval.setCountyheader(warning.getCountyheader()); rval.setUgczones(warning.getUgczones()); @@ -421,7 +427,10 @@ public class CurrentWarnings { Map constraints = new HashMap(); constraints.put("officeid", new RequestConstraint(officeId)); + long t0 = System.currentTimeMillis(); List warnings = requestRecords(constraints); + System.out.println("Time to request CurrentWarnings records: " + + (System.currentTimeMillis() - t0) + "ms"); processRecords(warnings); } @@ -472,6 +481,10 @@ public class CurrentWarnings { } } + if (dataURIs.size() == 0) { + return; + } + Map constraints = new HashMap(); RequestConstraint constraint = new RequestConstraint(null, ConstraintType.IN); @@ -534,25 +547,16 @@ public class CurrentWarnings { private static List requestRecords( Map constraints) { List newRecords = new ArrayList(); - Object[] resp; - LayerProperty lp = new LayerProperty(); + try { - String tableName = AnnotationUtil.getTableName(getWarningClass()); - - constraints.put("pluginName", new RequestConstraint(tableName)); - lp.setDesiredProduct(ResourceType.PLAN_VIEW); - lp.setEntryQueryParameters(constraints, false); - - lp.setNumberOfImages(9999); - - String script = ScriptCreator.createScript(lp); - if (script != null) { - resp = Connector.getInstance().connect(script, null, 60000); - for (int i = 0; i < resp.length; i++) { - newRecords.add((AbstractWarningRecord) resp[i]); - } - } - } catch (Exception e) { + DbQueryRequest request = new DbQueryRequest(); + request.setConstraints(constraints); + request.setEntityClass(getWarningClass()); + DbQueryResponse response = (DbQueryResponse) ThriftClient + .sendRequest(request); + newRecords.addAll(Arrays.asList(response + .getEntityObjects(AbstractWarningRecord.class))); + } catch (VizException e) { statusHandler.handle(Priority.PROBLEM, "Error retreiving warnings", e); } diff --git a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WarningsResource.java b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WarningsResource.java index bc02f41e81..d4257aede8 100644 --- a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WarningsResource.java +++ b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WarningsResource.java @@ -22,8 +22,8 @@ package com.raytheon.viz.warnings.rsc; import java.util.ArrayList; import java.util.Calendar; -import java.util.Date; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.Timer; import java.util.TimerTask; @@ -33,14 +33,10 @@ import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord; import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.DataTime; -import com.raytheon.uf.common.time.SimulatedTime; import com.raytheon.uf.viz.core.IGraphicsTarget; -import com.raytheon.uf.viz.core.VizApp; import com.raytheon.uf.viz.core.drawables.IDescriptor.FramesInfo; -import com.raytheon.uf.viz.core.drawables.IRenderableDisplay; import com.raytheon.uf.viz.core.drawables.IWireframeShape; import com.raytheon.uf.viz.core.exception.VizException; -import com.raytheon.uf.viz.core.rsc.AbstractVizResource; import com.raytheon.uf.viz.core.rsc.LoadProperties; import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability; import com.raytheon.viz.core.rsc.jts.JTSCompiler; @@ -70,132 +66,38 @@ import com.vividsolutions.jts.geom.Geometry; public class WarningsResource extends AbstractWWAResource { - protected static class RepaintHeartbeat extends TimerTask { + protected static class RefreshTimerTask extends TimerTask { - private final HashSet> resourceSet = new HashSet>(); - - private boolean cancelled = false; - - public RepaintHeartbeat() { - - } - - /** - * copy resources from old task, just in case some were added after it - * should have been replaced (threads are fun) - **/ - public void copyResourceSet(RepaintHeartbeat oldTask) { - // copy resources, in case one was added after a cancel - Set> oldResourceSet = oldTask - .getResourceSet(); - synchronized (oldResourceSet) { - for (AbstractVizResource rsc : oldResourceSet) { - this.addResource(rsc); - } - } - } - - public Set> getResourceSet() { - return resourceSet; - } + private final Set resourceSet = new HashSet(); @Override public void run() { - // get the unique displays from all the added resources - ArrayList displaysToRefresh = new ArrayList( - 1); + List rscs; synchronized (resourceSet) { - for (AbstractVizResource rsc : resourceSet) { - try { - IRenderableDisplay disp = rsc.getDescriptor() - .getRenderableDisplay(); - if (!displaysToRefresh.contains(disp)) { - displaysToRefresh.add(disp); - } - } catch (Exception e) { - statusHandler - .handle(Priority.PROBLEM, - "Encountered error during Warnings Heartbeat, continuing with other Warnings ", - e); - } - } + rscs = new ArrayList(resourceSet); } - - // create an array with final modifier - final IRenderableDisplay[] refreshList = displaysToRefresh - .toArray(new IRenderableDisplay[displaysToRefresh.size()]); - - // execute refersh in UI thread - VizApp.runAsync(new Runnable() { - - @Override - public void run() { - for (IRenderableDisplay disp : refreshList) { - disp.refresh(); - } - } - - }); - - // cancel the task if there are no more resources - boolean cancel = false; - synchronized (resourceSet) { - if (resourceSet.size() < 1) { - cancel = true; - } - } - - if (cancel) { - doCancel(); + for (WarningsResource rsc : rscs) { + rsc.issueRefresh(); } } - public void addResource(AbstractVizResource rsc) { - // if task has no resources then it needs to be started when the - // first is added - boolean start = false; + public void addResource(WarningsResource rsc) { synchronized (resourceSet) { - // if this is the first resource added to an empty set start the - // timer - if (resourceSet.size() < 1) { - start = true; - } resourceSet.add(rsc); } - if (start) { - WarningsResource.scheduleHeartBeat(); - } } - public void removeResource(AbstractVizResource rsc) { + public void removeResource(WarningsResource rsc) { synchronized (resourceSet) { resourceSet.remove(rsc); - // cancel the task if there are no more resources - if (resourceSet.size() < 1) { - doCancel(); - } } } - private void doCancel() { - synchronized (heartBeatChangeLock) { - if (cancelled == false) { - cancelled = true; - heartBeatTimer.cancel(); - heartBeatTask = new RepaintHeartbeat(); - heartBeatTimer = new Timer(); - heartBeatTask.copyResourceSet(this); - } - } - } } - /** lock when changing heartBeatTask **/ - protected static final Object heartBeatChangeLock = new Object(); + protected static RefreshTimerTask refreshTask; - protected static RepaintHeartbeat heartBeatTask = null; - - protected static Timer heartBeatTimer = null; + protected static Timer refreshTimer; /** * Constructor @@ -207,14 +109,13 @@ public class WarningsResource extends AbstractWWAResource { @Override protected void initInternal(IGraphicsTarget target) throws VizException { - DataTime earliest = this.descriptor.getFramesInfo().getFrameTimes()[0]; - requestData(earliest); - synchronized (heartBeatChangeLock) { - if (heartBeatTask == null) { - heartBeatTask = new RepaintHeartbeat(); - } - heartBeatTask.addResource(this); + FramesInfo info = descriptor.getFramesInfo(); + DataTime[] times = info.getFrameTimes(); + if (times != null && times.length > 0) { + // Request data for "earliest" time + requestData(times[0]); } + scheduleRefreshTask(this); } /* @@ -224,9 +125,7 @@ public class WarningsResource extends AbstractWWAResource { */ @Override protected void disposeInternal() { - synchronized (heartBeatChangeLock) { - heartBeatTask.removeResource(this); - } + cancelRefreshTask(this); for (WarningEntry entry : entryMap.values()) { if (entry.shadedShape != null) { entry.shadedShape.dispose(); @@ -404,43 +303,45 @@ public class WarningsResource extends AbstractWWAResource { } + /** + * Cancel the heart beat timer task + * + * @param resource + */ + protected static void cancelRefreshTask(WarningsResource resource) { + synchronized (RefreshTimerTask.class) { + if (refreshTask != null) { + refreshTask.removeResource(resource); + if (refreshTask.resourceSet.isEmpty()) { + refreshTimer.cancel(); + refreshTimer = null; + refreshTask = null; + } + } + } + } + /** * schedule the heart beat for the next minute */ - protected static void scheduleHeartBeat() { - // get simulated time - Date currentTime = SimulatedTime.getSystemTime().getTime(); - // get a calendar - Calendar now = Calendar.getInstance(); - // set calendar time to simulated time - now.setTime(currentTime); - // add one to the minutes field - now.add(Calendar.MINUTE, 1); - // reset second and milisecond to 0 - now.set(Calendar.SECOND, 0); - now.set(Calendar.MILLISECOND, 0); - // schedule task to fire every minute - synchronized (heartBeatChangeLock) { - try { - if (heartBeatTimer == null) { - heartBeatTimer = new Timer(); - } - // schedule on the minute every minute - heartBeatTimer.schedule(heartBeatTask, now.getTime(), - 1 * 60 * 1000); - } catch (Exception e) { - try { - heartBeatTimer.cancel(); - } catch (Exception e2) { - // ignore, we just want to make sure the timer is cancelled - } finally { - // create a new task if there was an error when scheduling - heartBeatTask = new RepaintHeartbeat(); - heartBeatTimer = new Timer(); - } - statusHandler.handle(Priority.SIGNIFICANT, - "Error scheduling warnings heart beat ", e); + protected static void scheduleRefreshTask(WarningsResource resource) { + synchronized (RefreshTimerTask.class) { + if (refreshTask == null) { + refreshTimer = new Timer(true); + refreshTask = new RefreshTimerTask(); + + // get a calendar + Calendar now = Calendar.getInstance(); + // add one to the minutes field + now.add(Calendar.MINUTE, 1); + // reset second and milisecond to 0 + now.set(Calendar.SECOND, 0); + now.set(Calendar.MILLISECOND, 0); + + refreshTimer.scheduleAtFixedRate(refreshTask, now.getTime(), + 60 * 1000); } + refreshTask.addResource(resource); } } diff --git a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WatchesResource.java b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WatchesResource.java index 330b178d6b..ae2b363dc2 100644 --- a/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WatchesResource.java +++ b/cave/com.raytheon.viz.warnings/src/com/raytheon/viz/warnings/rsc/WatchesResource.java @@ -192,6 +192,9 @@ public class WatchesResource extends AbstractWWAResource { JTSCompiler jtsCompiler = new JTSCompiler(ss, null, this.descriptor, PointStyle.CROSS); jtsCompiler.handle(geo, color); + if (record.getPhen() == null) { + return; + } ss.setFillPattern(FillPatterns.getGLPattern(record.getPhen() .equals("TO") ? "VERTICAL" : "HORIZONTAL")); ss.compile(); diff --git a/cots/org.junit/.classpath b/cots/org.junit/.classpath index 7363c566f4..e8a366c3b4 100644 --- a/cots/org.junit/.classpath +++ b/cots/org.junit/.classpath @@ -1,5 +1,7 @@ + + @@ -10,6 +12,5 @@ - diff --git a/cots/org.junit/META-INF/MANIFEST.MF b/cots/org.junit/META-INF/MANIFEST.MF index 7f2d8e6aba..e357195e12 100644 --- a/cots/org.junit/META-INF/MANIFEST.MF +++ b/cots/org.junit/META-INF/MANIFEST.MF @@ -11,7 +11,8 @@ Bundle-ClassPath: jmock-2.0.0.jar, mockito-all-1.9.0.jar, objenesis-1.2.jar, powermock-mockito-1.4.12-full.jar, - junit-4.10.jar + hamcrest-all-1.3.jar, + junit-dep-4.11.jar Export-Package: javassist, javassist.bytecode, javassist.bytecode.analysis, @@ -43,8 +44,28 @@ Export-Package: javassist, net.sf.cglib.transform.impl, net.sf.cglib.util, org.hamcrest, + org.hamcrest.beans, + org.hamcrest.collection, org.hamcrest.core, + org.hamcrest.generator, + org.hamcrest.generator.config, + org.hamcrest.generator.qdox, + org.hamcrest.generator.qdox.ant, + org.hamcrest.generator.qdox.directorywalker, + org.hamcrest.generator.qdox.junit, + org.hamcrest.generator.qdox.model, + org.hamcrest.generator.qdox.model.annotation, + org.hamcrest.generator.qdox.model.util, + org.hamcrest.generator.qdox.parser, + org.hamcrest.generator.qdox.parser.impl, + org.hamcrest.generator.qdox.parser.structs, + org.hamcrest.generator.qdox.tools, + org.hamcrest.integration, org.hamcrest.internal, + org.hamcrest.number, + org.hamcrest.object, + org.hamcrest.text, + org.hamcrest.xml, org.jmock, org.jmock.api, org.jmock.example.qcon, diff --git a/cots/org.junit/build.properties b/cots/org.junit/build.properties index da97b1e7e3..4679b8281a 100644 --- a/cots/org.junit/build.properties +++ b/cots/org.junit/build.properties @@ -8,4 +8,5 @@ bin.includes = META-INF/,\ mockito-all-1.9.0.jar,\ objenesis-1.2.jar,\ powermock-mockito-1.4.12-full.jar,\ - junit-4.10.jar + hamcrest-all-1.3.jar,\ + junit-dep-4.11.jar diff --git a/cots/org.junit/hamcrest-all-1.3-sources.jar b/cots/org.junit/hamcrest-all-1.3-sources.jar new file mode 100644 index 0000000000000000000000000000000000000000..77dfc35d1f805a08e3a4ab438964ff90b31fbf1d GIT binary patch literal 87801 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 z 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�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

5cU~d-7wZqn2y(f6%Buc6y1-?q{vST<$hY| zw?y%Oh1BnmZsP1>|6kTo__Pkpo2}f|1Y^!Q05X#J4pw~xaDIhUZ!586x(meFIlD|F z>SA#zYlvQER+f!$JL&}lo~{Jt6@PL1>#b6MDfuitG!ZYHAHn~BnxI|c_BUN9-v5=RK6qF*WZ-)1wPFt+p$#!($UtW5d)X%HpGRikDF1qtpuIO!H-vz?M@7l%K_`thAiU5G82n$#)hsU=|cD z;J>(5kmxi;_-DRA_n9#KmYV+ITK`i#3OG5LIQ{|C;~F+j%j^j6Fr9|ILAV|iEfW$$ z4ee59oK7}&qz~XIME+Pr4vi3l&et1lWnZ*d^^JjupQ5|V=FV@p+hT1z26Dw%_b-iT zkywJ6Sofe)cy!&`lFZC>*!`oToj@7E5)ZhQ==UrM#hw5*sV1D#Q-Md>#bam<;&DZ|{3XYTp&{|! z@BHSOKw@~huifPzPcbMANqoIm{R>OXRgPtxX^)K_!2s-JquWV68G;+gSnlLkJ(nG&`@v ze>1G1{skoJ(&k31Q(kom0zGChPcqYB0g9}Ww%MY`!8`Ln=iidh=gB;DrU2SgjMa5rKsCFzfLr$La;~Zn_ zV4DGrk>^a~$~W?Xb+Ty;mMz4Pc$C)wSO7mLoyNXejgHOM^jHtVRWFbLSh?@PRg)7g zSDqRTAXsXFyaKl4YIEGUm|#6B$(m71IVw$i47~W1tI7YA*y3^N7bgTeH^}$q-cFf3 z((hC1zpSyT!is`c^PStuROdWk=0J4tn@EsyL|m53yTl$4G+l({YOKmRr7(dNt=?87 zqe*+Bv%wK=6?6Y4Vs>1;v2c4M@j;~&2k1Ez#&NM0pO!PO$emfS)LqOZb4}P~(SNMk zt4rxUJ5paMtUsf-NTG!iqBJ}!DqzYuIG94Ft72-Qxk2s!g&Gi92As%&OA3 zHrLshO2r#roCDn&{Dpz{2OAAQM#uWc0Q%zlc)w4?xt&Jf+nqP1m0Lm6rMg5mx8QT_ zk*k_TROeLNI?giMBDRYN5J!Fg&lQ^Gj_>U)p)G8^u~BvLn9(2&^ECV47}tT@eL4nx z-j0P#Fc`F@Dq0al=>lXYDOWWo3buo2Nk?W|(;-I5v~NuoYiH~@4lBh%WN}&XvHSz}Z51OKaxh=Ll}9b#wdhYu;t}Aa|Z3(qg(y3l7Ki_$@Be z#hy_Bj@HW)KbgnXpucMyBzQR@+uf!>JrAb62Ex%P7~iTlU{%fSgx z{r$tL^8QDUDssFM+2^~)E-#7BaL6C2kly|JBU1tSj^@y*-w5K zKXHHl(3ugaZlQ?{6%R^G=^$*)Alx%7Cw)_DZV;PK+hcnGS6A|Fy+04h%WdC(TYUrl z^QKZnK+d`R3EnZEIl^zJM9k}Xu;1uvb2eqc{mk>19K#CbLEX5=PSC~TPOm3aG%ki}Rn zISfkmQrQXUGY_Qx*Y!BC6A;aM>2X2^shNJcMwZ$1flF=zJK(F*W0XT|@l?KEhIdxd zli5sqghyWj2~Db@E?L)T`LI`kV+k@9O3-DfH&92KY8v-Th3OUr~-=_P2^SZV=yxHS^Wnoa9y>1{<6#Etc_1r ze%2$CpB-fKzfq8oosGSLqlJ^5?eG7L{yWc&P?51q4TT;;X(cX3n-o}5XyG?(yKR%X*v6!=s%47667aLkcBBJ$LlvAaF ze!eWDgDO88%+PGn$R$iQAAR2G$A+@rOTRdE4C??BPDI;fA|elKB};V;Gdg#C?&IC` z%OJ7vh?*<1L#GlKjW21#7W8%S`E3cOZ3@Hj_0$ZG5^74i=RzfP2lP_L3 z*^4+(LjZ+(NI_Dg_bOAX2sH(Zaf(e_WuXtKL!k#l@SVBSkw981S_r4X3)w@B5KI( z!uC%7qh*N~(FG%n@7|A*Nf;Gs!9Hg&mvID2E7H3H^!xRS`8aR5YA4Y7RCDhXqb8?X zepBIBzpMPYp0Xlr+E&cIIekLW7u2gHXRR2YQdN*Pf%#ll(VrQ)W2@BK61Xq!K9#jk zo|$NL!L-d&)Ia1}_HdgyS^Qx84^>FHux%y}b7`d-^N}gV;C2f8jOii(EN7@)C(8wn zeRSxx4;nw}>I75=kHp3gh5Cjil z?3rf(bA4_X{j!2!HY$+B2aZt}EgL$_J5kpDmqp4w{Urt*=TJB7A-Pxf=-mjaDHN_y zt{9a1w{>U{z^_`276ddfug;>yuo)@Q$$bfh&w3PPf!!eUa$WpPgG}NwF}>Q`xM&zs zO2R`DyP+ukD z^ct8#9q%GMHhqa4AScOrR*E^vAUW8pV;6X6ZcSx-Z^v6-Jv>{Uc>^c#$g0SVb6ELN zLE<{6)Jtzpj!#f{b>cS3A+hmw&RHCThIe1*(z$v>tvyj!aTPRCMmUum%^;ENux{x~ zdKbyY$wwTArj{+0X@w9VDaodbj+aSgdCC+=DnYF1bZ2-M_02|&L)NVK&z@GF-BURV zGke5;1x;18m7j&DR;Jb3;IHx&gU!|zhyuT9GU1!HqixnFJlp%SRqUZ~D&Jy7^Gzm* zYBUG$Jo=f!Xfn!5PlsB{3O95spIQXQu?|AZ-B_ondRRGgqLB8segO z%dwuTVx%*+32U~o6~fjn&$O{_FRE2vf73cUS3~;+^Rp%u2fE6%-8fgk$uRH61vj^s z>CcPal-G_O@_*-?aF5-VN|cCWy&{4 z`)lb={r4Rpn$&u6MHHUt=@C=G7)l8a*w9zcmV9cd&@=pYb!HAOrnXVB{yOju!RD$2 zdkX{ikf>#DX)z)N)n)eP1FXz>*`eFAYFoCdamomREHz22^bT$M21WB}srnQ|sgC$6 zKT5KCPMFs24VKstf8R@vpSq4DrJ9bh5`2(H>kzz|LUfy&8y;o%U{bWR+j2jucITlx z?xNYu5z`qlRPGc*VHk%i0_pg;-*H-+hdlNGH;0K6i_<| zZEmP8=i=eWj;oy1G3>TFT6E{eA(hWmYB!-T1R zWL3!(w2XlHY1ABJqY^U8C=6;T%$4KHwi zV=+rD50B>b+r)M^{7}4Ff|ucV<=UX#8+7ls7V1Es?3Ke$y7wo%KL-b-5PMVNXK=`T z1_#yOfbstd4k3fjBdFgaq(Ei(w+P{p(qm{J{+^S~FXy7jJmgm>ql7PYp=4pqq(E*U zz61&N;n^b2IHw-6f^99iJC^ofnsfhfZ@372vl3-BcJ3f+zaXA7<9GF46?J1`Tb+9r z)vCFdq%Z=_L+n&O7yUF%tK zRZSE^A*+PU9CEBeoQf(;3yf%v#kHO3cCDypTb~3%|8n7i&65g;XL}(@yghZRZKE+X zkX!RhCr}$CI3O9N>iMiqH|#m;#A3*JRtHA%fIg%V$zKA9(A3|MsCFDYeSm^4-wj!} z8G3TqlLn+sjnhdgM8{%7Vo(}VH5U=PIF67ht0`O2D6wbQ@0g#z;6=Q%M#V=|lEm0J`^NPNg2r=z~ z0n9My2d#p#O=pSdXf-(ODubba6wf}v1i)Fjgopm3?@iZ@wt>|d;cxk-cj@DXFs-Uk z+}c+p#dIxER#%Mv3EqL^PLB}ZT5wlvNS72NwSS`AtR9(%op}X8I=c$YFQY+{j_x;m z%6b`TRZ}SzZuzb;x+piX@nq|H=L+dB@jTXph=uGdW@urojYrofzO@BK@P4Qx)eTX& zR_qE>Q^okRN-ukoTd0x0assw*S{7{HG7x3y1fhB;u%1#l_3J!qvZ z>pJgFW%R`TdrOi%->K0njHdZfAn3;kTE?{bO#st-(S1~Z~JuHr^ev1gwF%R?F zv@?M>VO!@NdY?(ob+k7kW>dnRyo6wb&RH%zf4V3+b6NzgK5MeEU-%vyac3H^ z@a-@8^=WgkKI3Qc;qmF>e^-F~k9!LlIGKnV7#SG<;oN~S6TcN80~5o)6(Ed?U~LKA z`rqK%U|P=svBf0XIbEaoT#atmil}j1M)bi~fV`iN;(lsVJF5Gpo2*l{E7A0LI{z5` zp&SG**QS!0R{7AkSwb^NEOHP%0uGZZT|gOD_Dz@v>jGqMa0C-}xfEgZNyeEC3&yJo zh?kzzJ01%i~C0=9n&npiz2l^khy-4sPw3};cE)PEIhXUM0Q)V&m%5NY8BT1Px628`oJkE~Nrc_am^YW<#13u(+G?$(mNo;mB}276W>~xRR(X9m(T^@o^q4>slvdJHOD?X*+r!Ssm0& zY$`(Ks2dc3EV|dysw^9PnE>Qxqzzi@V z3vo*B8m0_RzN!$jSjyU65;)P~M$ zbf7#^B2-Cpw%wvDTEF%!Ui5J_O}heXTSL^uECOt~Bd7SF_xV2vIwiR^JI6=rgejiB z0{_|eG^9I%C*S}8v}gbTIR8N(zlGZ$d6v4C6IK(dPoWQJ&(G+_TItmzDGH0zMT?y= z^&|CAyyaWKRZtOiDSc>ti8|c32OsbS9m(2lchN*whsuo>LoVHoYpibGd&yQyn@82t zh8CU7^dXy~2qV0wNHrQYwgkiz)!E9gWv;FJvX(C6;}Q0J-lZa9QKN$%>yS-T<4F+C zL<@@Of;sq5$aMT)J|C4^Ve}F5&E)BGgOUdT4Zgi?v`3LRyZXX zbU?pUO&tUTC!9~dF}co;HEH|ovNG$kIfaFw|b(N=c9r6zxQzp@65?7>P9 zH^EVB(C4xx)@xW7KTmc^wGL=!ck|1K3+Ia^`QE-;@tTG1fzGZ5Ug*|?z9jC_%iC#P z&}y=wx#e?WdecTE;X>8?TzP@6$7O&70v~4Ym&W$B3cp~)@E00lPL_K+cCdKIGb=%cETL82n!(S*JMl38eoTsq+;TU9et57qgz z3Y8U_-&JHAY(HSWZ1F%X3d%hP`#5JFj&sNl7R+@13t&6XtKRF;1G>Xk++o?#A0p;; zV6S0}6H8&oFMC%fUk*;`_U>@rI-uo6lMc5omg!>%a7fqZlfYK&h-C`|7umCkGTWWg z3veHH9$>=dXU`&Kb#sH$svCcLi~D_4)O# z>CK0?l}=!KdqXuxV1SG-5}Gp0iRn7oKB0Jwk-e0wgit&DZT6d3#V~N^^txOr-{TG( zPHaZil!9_^qw>PIz!gp8{cH5IJUL6$uvP*z-*oh~`uA=@`^WmoZnEy09F!M=B`hHs z(;_<&r5v((&9i{mcuob6yb>f6NdWcSdQNK>IgzqS5HFGl|Aew&YhE+SQ>TLQ!k-p} zB-XvzqGf{u<1x5uzTd8+eW`FGdqp1Mzn{{inx%se>0ejON?2+x1+;~>yM*ACc=IP@ z3qsjqF}E+r0R+=mpS+b zgU2@;nmcP|wbq#PJVno(PQ0bo?tF;Y`TC=$Ftbsp)`Oc~W5K+Y|4Ldn-!y!z+6>wQ z5lfCTf}MeS_?ll-g}_RvtORU_L)=hsnmkx$IB_{71skmN3uY0;jzMZKrPHO2UN7o3 z3YJJM;b)J8jC*;sv4Da9jA2%-y2kCRR4Y07!1v%1ESZ*HKCssdd}>4Pco|}X2}~~( z$853mA6J)j2DiTB5YBd}%}Eb~z@8R?m;3DxkCD1h+1umW#9w>WSosmajAa{{@rCf{ z5|G6=F9YsNAxYMZLgb3V;v~#=BhjKJKbD@6>eWXXKMLOAJn>uz)u$KKoyp||r|$i? zEM7@>9)yl-$eYv|`ohQxGVq*A5oN}#m3@SWETzf-G0S&s%*|TeJZuf9<4Ec}5>8=! zi9x)S$&l@6ODpYG_J(&WlixU(tb)=EFlyP5BIbZ^lKmhcV!~ZKd4LnIb^en~I9rt6MkaXlrT6O|E+V_+a)iABC7$0{d$KeBI%rY z&;Fu_l%HYVrQun#MR16h&z2yRQxM5oZ%*HG-0d5-gKi;km|kcrL=TTCi*2JjnFpsL z=b@aNl3h4(qVO~5<0+;}$`5mwfpgT)%bm&fp2ucvCxy|xz;zcB?Iib&{Mh1nV5bO(LEZ`Oo z2ky*keE(i;dLK^OyYR=uZ5;RV(HV}uQ?gVY;SW(*B%)?s42THu%!pD&%1(IqT54~_ zN-p8YXrNqQY{F1UQUGJsNp^U+u^?R7WWQDO{^XmqzM~w<*PYTj$vZ$;PbQS)HO2hMlBSGUa4VNbC%Xs43?o4s7+ zT0d4`?_qKrnFgcbvp`Jy+>UDq9($x}DPC0=Nx_j~8R$X-elqFv46PxJLhPF&AMJQ& z6SlGe`OgIJ>-;1NU~KH;Eri>NX%yizSL4wUJZZG+aSIktS7E3CVa^Fj+qDXs+`}Sd$nK41(QBw8%6?y1p0TnIim+?3W5MsuMH>dYGC~wv~?_Hfs1jE+D zXl&3%eicvD0ZzGN@{H1_>M)n^{NT-foM@&FmO~P#E%|?yFPDW?>Zqh@s z(q^`zJh?_?mMNB;STkgXYKCp--gM-_UnYI%q?u~#&h;Z)n2 zzio_m(NSD9Z>`v;4o{NCFv5>r)vNQhtgmOh{-yG~h!+-z{7lQ;J`Z{E|3jAW?+w5N z0o9Hj{iSux>24n5#DK~*SGn-jBH_NX{MtNeX0fhl(-da^$&h!# z0M5;xNG4EEck&55XL)^loG{au*(Pk73qf89gz6Fm$d2_8tDc^G0|aW>7v-(+%D0om zRTo3&M^}YV0RL-1r5z6r&2^<-lcb+@pi@`uv`SQ~<7M-@qT*wmSq4jHVm#Yswofo& z&sPs5>vD{~R*~Wz#f>OJh{OX8`qY?IJ5esX7vo?vINsclh~*qv(!k2*6l(E_`{kuI zLJBU3m%iCYC5AeE3L{e0({;uG(qlCxFraq4GcPelB;~rM7W{Y;id>NFERhW@o{~e7 z^Zd;nNiXAj?zyL#YA-oNl=Xg=95X8C=~4&~B|L4#ZZW{7D6V={75B;5=d@NPnn0%x7{7G@ooI=FEQU-9^uJB^*?e z8RT|VacM&)-rUW_A15+oG1NvkaKJ*fH-0yLQf6{0u7K~SM^raRb1-6;{o4*B@&Kwm zr{8|!Eg#EwtN-BXZ;{nKLGEZ^pn-xNiEw(dBbC3UK+q&)S;%lQ?{)Zk>}eGdv3v3D zFUdFa$+Ga!r~4#-Cf@}A!HuLXoIbCp|5szrW`f7D7asw1Q!{-#A(GSxhd%+jNb(38 zU!7tR$~-Ya$Jo&g`1-MP@9brr-oj}T*nrQI>?HG!E&~WpvmmuqwYa9cDNHaE-CG|* zq`S{RKa^oFB6Z)^8SEFdLlvw+l5AxLp9*U6NIW5FcQ`BmkIeNKf0&iJ=QNx35t$+PzL%kRN-*4jl&vl94Y7oWWFMI!6Uc zvCDImL6V#a5xcJH4k;A4%x%Pg1L3(d&LYYdb z%LmnR6!sBv`XcjQ=bqLD6AOtqKZbLX`_(;x6As<8=6<>lx7CeBcu&ubFl)X`3BpI@ z=a*YuICTTOF+B#-(vOSEw|)Y@7>!%41 zE#4%Xw{M<=GlWFH$SrN&_4!^eLGZWwCwv(HlYPLA5MuInkbN*6GiKnD)O!jS;DiR` ze04dnWYLisA8YPp#Foi&xMC=Q=p$~W(!~~3cnmLQ*4qHZtM`0f?6kooE?&Doc4dVO8@21YlR>E7vYm*VGerh3 zX+d~!D@XTye{M3AuNOE~Lw=?XpZ5-byY>FpQ^enI9{%exdAo*|-D)$cPv#Tq7|Noh zp^$7FJSb};)K&5v~_0uoEnYZ7uy{16e`%$Fy3 zxb~R-25ri#mXd~vFRGPu6*UWVMM~}K=qLSV9z;$y*YK(f?`&o5wRCO|wA|LTL9A37 zbWUYx36x$www4DrO72d0b7{{5DAQI-dXjC*?{`UpHkUVigbCp-E zBNOEbE1gyc;P<)<RbQ!KX8{wGqCh`V|nTj#4j9;uLq!4X2o@qp=5v(qI-Y?$@7(Hzwl9&1sl=KerZ`(mSlzl z@;`W!3~|&NZJ>RWEpx5*E&+W zWe_?yGvP?%i@X){&Xc-JI_r#Qxf;7tm<996{m8?k8mh+JcE~F|BVf;)X~ZvUPY5J4 zifKY#52gytM6SIug(ZX5P|;$1nhu_ZFzcIVHYCc(a}o*U`)+11hxFleX{!$A%0J_# zG-YxZ$BnTTjeG(Q)2S_>jVzH{E$J7s31moX+n@(YA7QPo#KG>^nKUm1M-S-X1;&h& zPF$5x9N|moPh3SX;hI5%FJw#tqk>18NEVd?0?tl=mK}tGs!C!1o$?q7Nk*~qBFaho z^)ZC}R|R_u#kf)7J@+=iNgbg8>zOKR|sE+qvRC9BYUcCY8lk=_dw@YmPELg z0JQ#vBWJ$`Za^@POexv;2EZbAP~m-14Nb*qRjtKpmanfBwF#B*{hnosg@rR#GqbwK znB{$^K*9}{c~S(USO^R1Cf^@i^Z22r@npyl_=YqPnMqvOZK9|Bfv3|j@6D5Nxrj|V%uj@g?{hod@e@- zLNRnQ%+d{}rcpt76WDeE4|as4bz9=DQf?2R|7=sS=thO$2h(e!!_#XbiLV^)+tW6?1+ z${A^uAI2P^U-T_fcAI+zAP{CisJC{_CajX`y&6UdaFSJDkK=Q!h$@{_IOJ@26SzWO z!68`kk|%4HNUG(eg4$cn^Ck>=#ad&qDf4sG$3;eE<&1u!$_+i8>pGM49|&FwcOWH|=TV1x zg_+Kcs~Z{F=U2sTmAY4YvCd$jPVI&4(7#Ty`3{XE0BFmgRct;hEVNt}$;@Zy;kZ5dUa`N- z48~I#4Iyz{$0HPIv(wx>+xLviTjC*^2O>G70i7Xib>v`KTLPCtw6JyPEphth!tE~aJ8#w+*>3ahaZAwULh)QH9#3FU}@gwZ2^dkI^KH{?iaX!jjqouJH zlLR35-8er}w}ypOujFqr?t4Q60XDb(W-gqL19`*KU~ zH5LmpiiI-!dm&uMZ5ij^W?TT#xhQz%^So1kabi8@QFW&#IFfj=gJ_1`c@uH!zne50 zy!@`T)MYItRx=mhP;wO$GNX$foI)O9h`sG>)z0;T*MF@wy0cSM^kryJPT^Snd!KyN zoR}4L6Y47UX#-@2;?a0o!xDmH1Ot>SMVjl2N9-gI7@VLKrHA&VQ1w&?@116t^=^nI z1WXzy^Nvehhu?YAL*po&D|1M|fwVblOGTemVHI0_kG%+RXK^NUoj@C)`a7d4r3bSz zMVr&F2?2gLdqQ)n4U;71`Fa*cu^5g=Me#LV7`pIq+!YBz5-f`~fh31Kd&_=gb}JHC z!l`X!yYiL7Qr9uKrNwpjBYV_mkJ}dUS?gnF9(iMT?IIH!fmDA{=nH1rLA^syasdKT z4KYMGQeXB>)75}BKi{w;rzS=j6MCcs&T8!(f6+^mk50Z@1#L;QM+25y&f7MXe62z>^uaVK_6FtDJ*=0Zb z#p=lf*2G7`hAMAyc*;>%OJ$-x2hPF{pWQ9b&DSAQcHdH-MX)*?53JYn*@o4WP~KMO zK%3oLFO7YT%(gOLI?Z@L9!ZuQ z{yKDx9;z#O=Fac+kgNEi1&%9VqIWKYGPXGI31j=bCD#_o$7)OZxZygN(pBqG*AP{^>A=Z(kiG~ zUi#d)hmEfrHEBgCrb9L<)|)D;>a?A4*HKm^#rr!YA9@ONZYvxj@;VyLf zUvtKw-lS5F;AFQXRLj5iWsg=SanPwsP$agfn`gJjK}TATySE^<290ixXG~h9bb#Q` zSf?}`SzhJGJW$fWsu7)a_33|9P&1)xm5#86mrfX9M;@39sXW!kH zQWuDofN~>CcDj3{QP4nLG5)XswFHU$B`X`b2tb^{Dk=gFQS}SoIz_J-x7O4gU=cHNYd8R^|EQOolwvZYyfPWYyp)-oXLv zr1psRB@h6CVi!>nrl8B1v&MH#@Vm2$-R!7@Hg?0yjirz$haTJX@&TO`Z7@RQNe!Y0 zryBL7+M$l%_%q|gT>gRqGKTjFb?e|z%uPF`pC}gLon)G^x!YR^%`cYmge>lj;u)F{ zd6SuvhH@$^`^n~ytynJ$-XPq@WzjGMV~N!FF|}98s4AH=HetF1_qaXi1%?FDKosPW zj?>?m4G}f*f%sVufwVEHDC-RY!Y88#r+xLZ!5Fs#EAgQ;ZH@Ecy%L;9-3a3~{W%^& zJyK?amu1@#VpX^AWw0rcs)l=jb$H{JmrG^i6AOX?NyIT?h*6|kyaCmQ36mse9q%D` z^CE4Ceb6R|z9evEs`-t%b%9Z?bs@=1*??ElhSpC^RfXPyvRw!bDUH-I?8RVS43Q>c zEdQ8r>gHCA&oWA@)XpZIS=u`_cwU(^cI3m*pnle3=l4R@%u5TZY`r`?)z({I<(004 zL+9i&s`w%^%@R^<&?-Ck!+@_$9eQWVvzV$^jgE&9`mKOWm07y~&=J+WtO$35Js7NP z5di79uP@K93kjqn+Js_O6|IDTW_%nf6fK^*93E1oK|19Cd(xk@TGd)wj2@`Cg+eJh za#uFqBoT@_G_idPA~bn3`SrWVrKRwUv2`zyd&iYFRR_TfoB}4vYziH>oTHKxzSvLP zI;S*1U`6y)+7JCiXNuu$_qPc)QKkJT2X8$x&g)HV7M61Vy;I$VzS}f4{&>6O$~(-IPU08X$djIXJE%WPeci| zy!$!W0y)9=b$^OGp(&T?U5-~-f_}0GS^W& zfDy`Q0M+pDsM140tl5i&K%xhgUrrdXU(5X42R#SJ^4oJJq`)#h%n*rQgZm$DjuZbCvx;5eLtP|E4-~DHlP7n@{-R~GYrTe~7WtOo&cSKjp zxgv7=?*IBldxhj%jKZ&pbjfuhu>CN}k~{Bf9Q{U7DRQ&Erlqlng|P1jYqnUc+JBEu~!YKzJPl7cA(cBjfvOJq6Th$f>)kT&A;S@j_pf^&UN~ zuGDB^!74vXjStw)>qL?n-xW?!v-d9%w}8gG^?E>qFysZYkQA*sIt*s^sVKwYGVQvG zHRtbS{%7qVyF6w4@qFCMm(YD4l$qyA4)MZ5_ONtxG(TN?7T#d$p`MTpf1=Ib|G;{W zw<(1sGP5Ef(PCSL4$D73{mF2z@7WbOc=`f;zvd>*(!Q1!$>NWQ^USyx;>mjq#2pb! z9Kvm(A~oWG8mI=vYw0g&!JvHCQ;2r27Qno zLzPn!@}x@_i;h20)f-U;P;#FZdLyuU?B5xEmUYvbi!0-kA*^y*b$SocOt5D=^#^QK z@p?HcrWJuRCQX9Asv%ns*++G?szT3x*PN>&G38B@hOO5a$f|UeWg>&K!UYY*} zcsstR&e*My?cl_3iyfB(@Kw2i8(^`(F6by{)-w1b$BSO~^0Q065V?K*%X0A19?3eV zuOz_Dwf@cRd$6-AdFhZFg8~nR05vF$)D0hKFV+t@jZ2=K`E(}Ip!0>j$?C$3mpAxn zT8EeHs(X_=GcerUv+a6DD#1oS0m>2}_jj}&fk7%~5|a8NhnHYMIxv>C8`lRsIvuix6rKSajWz0{*7}&va{w%J z-aQ=q{hjda>S?bM{4R1$eAi6>n*{$S0sT+%`L{w>N`it^A3bu&)*IDjVQOuDwF$fs zD?+H?8jsZCrmdS)QsO#{$oti1gHj25hKB_^&ruthL`hl4D*kyO0dAW-WJlv9|R4o9x!s$P5bQMoDx&hX4%vFJ&@Thkcb*FFVj1SySp+^ebN!bqGt z9Q1MwSPj|FA`#YZHqawv5_1moHXMF79MN?!7q7r6m``qYQ0AU_^kT#tl66k_Wa!$Z zeQ-yyZaUK3-J`hi6dwvoHKeYGa{kJN+8D327i8%$KUd&v7PNDAPHkdqX<$wTGGBJ5 zo;JUW7Z7N(^g(nhHL-l1?Q`su?~yMa#g*&gp7!Hi+!s<7SB>3nbbe`2qH9`PxXH z*|P-ny*4ihT3MOT_pP6J{|6kZfHG&mWf$jlj}W;@N0zYz)6RQ=?aoYk0Z?Zfbn}7vNxOzt49AbkIWm;~-#gxOZ^HFO1Ki(l32f1oBT~17rPd!)ZVY zpaV$o*btZkY(`uxRBY=*gj7ckdIJNbDF3>o@X(z?V4L<`2}Vpbw3a4HcDEB}Yi&pO zf>5^^yf{cXosv_mYN|gNE&WcRqPCkE89k+9Zxy7gCo zn9+@c$D@8fD&>%rx!d9_eg3L$qcznzouy7&(_)eNSa;kj7HHKa^k_~ajkt8!V3DEo zwtJYcQ>v_{h2v3w(wiLc)XE1AV)@5Yic+(I<^6s-g5RJ2)?xk=BL9DYIk^N4tpYja z#Mrml-Tw{DgTyud=@5|BNhFr}{a>BF_XqR)`)|SNWMg1${r62mHbO9do&*5;?;aT# zyZ{fv6zU_x_}FiE2Ym6L^7Z-AKj4i60pY|Glhd)=3)4e54!c{cZ!Zs%^dHst668mO zXz1F;isdIVL3dedMhyjrgk=&prtq#qs5{nZ^*XL(;f2VpbG-bH(b$1GdO$wE=(W*5=Ck&}*o>j^Rc@hl$^yL^1Vi}-+W|FekyA78tFSMTK=|K-f} zuX83x&Bktx72(tRD>CX)Bo>wg^s&^ouDCJ=^sJRoVrHtrJ9b69NI+4hp5V*JjTl9# z_5hzL5q-CV=c)H7c}FzaZ5MUNtFVX)`_nll8!oJF(|m8c?U?|oG>T4?((M8!(sMPT zR^Yqhg=T)ZI^XLu5R;_Bpd=F`%3i9nyE3GOp|ID%>NXJ4Xs&KTYaB9`!LTa*mTWiO z8YJjCi_ZP~PC_#b3SR7w;F|K3QHE%O&W*16J?CeF;u>?5WU9PsuO>ulr@guVIaP%M z2egItvm3j(C3Lx+DCZ+f9+SGyw2D$W6MJ#c4u0zu`=rvDmmRlZNzm~LHEv>%*rS6Z z44NLTK`|^ds=*CF{=ooi!VW;JTxef_kNm-^ImuTK$@{b;Bvx#S-5AiIpG@BDDe7-Z zwz@%t&GOFxLkR>eKm&kR_k^qJiJ+iZ;wIZJX{$*ODi7jpE%UA5qSj;2y<7iXR2_05 zUdndSVn^0Bs^LwY3ENIxA71d1{P|Id1$|aYO1BXdwSqv*4NW?lhT>K9UX@na9K+kT zVh(*^;;x!t$nFP_U>Okl7&k*8Iac zgG0RfAc3Em&yh9di>6rYxHdvVL47@1U65DpQsO(?qJ^+uC*P5VcEXx@Qvg*_^=|w8UU62A zBkWu!JtTTrZIoyhdq0a|CkY{Ex&yG|gnn7D-7fO~pb@sIYQLYvTPp)6_0+xPE_IB~ zo=*?#8G$rc;o*1g*2h_~KVXYlF^_8E!nr|hoD3|qP&*n7M=X?-g8Fd!!P5znB8Z@F zDA^B1=@BL$#l=TpWg)=5TH)0K`O39us(_>fON8S>{a_a-uOWCH)4iPJA?WJ zw_qm0B2X#zx>+8DK21||>?0HVWX-bJkC!>-=y&#D<@W)Cx;*T=nK2Sb(Dh1jc)f#- z0k!yEZPgzWBa4;O#ox3lQR>b!c>Ojyi)Hv!T&im-*4Ykvq ze1t^IzuxG+xQXIIVm+%>zk95^Zkufp2I{pzx;;AQ`}Nr)7s>2o<>Y=2a@%XY8m7*Z#MJw&d99}& zxkb5O`#hi#Vr~8Kvm&*hQyl*-!)tI9TZOmR51_pTJ7uboHCb*ya1uHE*fICyFAYmH z?z0GvF!cp)s2o7_GR3Q3x?XrYqlXqGI@A)R(2BXn{#Hi~ghkIV_ysp;#LgF_C#PrJ zKk0{LkOGev_Vo|_kz4PEZo{{4X!Ez1-e2y8|2~ZWb9DWK8ck7C_@+i-e4G4057Q`P z$}7Ao_N*-?H%zRubh9fu&JJ9og@>$-M~Eo6R%pL`0K_Ge_gXAy)5Hk@fbjg|wiS(= zcSU=fTa{TGZzmTm=dYd?3^gpExB4ZE$|U(LR8~tD6sbio2+zhF)Q4S)?dG5@&dry0 zBj_DVy8ke{)UFLSsJhODSB)v2-hXSZsoq<44(Uo`$|PZSw-3g6+k=gU%LW9KIgrbe z?PFLSYgAOW@%Tw<%x8*-JzM5)!*L-};0!I=XuN$IQAc$JAfAg525Vjgrric(2}wMf zlQUTKj}Rqc(8@5v2SJRDfk8e`vpfl;#y+zr<#jQ-GRH8${0a3dYAA#HDn<_y2-@M` zpD|EpC(E&uP0$w0$hS2EDb*HeL}l>ffi+h((?EbP;adQE<9jh^PZ|a7K*|z$M>wNG zALmt5*v#iA4fr#G)1y#)D9Z=!BKhlhgoy@$c&AK8P$4^PWdj-iI2NjsFA)wo zO0a=Z0{yYcq~(S!RdH=bVye!|%wHJka5} z{RBO8yR$^K1hG%@Fmhpm(Da9ro|8Z*_e+tNo@&ZyDH9TDMW0@lChV)&I!gQLJE4JK zb^bvS%CfYr{f`7nZ7+rm<7H)O@A;lg0{hDzP=>6da_QuLrN%9S9Y{z>ol4pAN!YhlG6Q&-j<2cUf?WUU4#P;!)m~9JpT9 zxICLUR^RWo68CMvH4=4$(x8(-4dHSxp)F77||jIm?yOqvd# zOdxSU2p4yc`M!p z+Dhx^m~JC*R!U{W%tw;`d_MhiPa3UBjDCttyD-E!+Q!3$jNO!QpfcR3vDmyAz#_+^ zl9zkpbVg1W;8PWyteD*&n%faWCdYYOx&y2|0qY+oUo!wk=b#N~~HC;pv2-4S3EImIh@m#SvX zECCgd*ud0Lud<6&9hQ%HBIDVN3~w=^0v2(Tj+xlFJ9zTG6?VgX!U15G8)u-F#Z|apWW4l=`6-;#n>XA zkbmq?*Q@r;2E}aNT}2=Aq}a=*CrJv0)-ACz_~nu+VPxtO00Yy2T9D*6EPE5Zr@Xh| zuIh;2jfB8#xoV`993gF2^x>bimohTrx8&(&357r8-5qUI&_@+wl>O)O>jAsg<(g%D zJ2Si^gAv<}EvDJ#(XoXSpAFG8f*iI%K&k&n+KdNZXpjE9udA8EGrHQ*@(hR?S1m?; zeSrirGWKn*#kX99YY6`B4Odr^ysfZG@kK5MH4#uR2h7VWTiGmg5_C{w7qv!(0vfaO z$QNQ)BiMa~;^L~jyyFU8E05twzk0wLCWg2CiCnP3M(zfoWpAOugC~oGZWhh<=P*fP z59D~w%>I!<`IQK8w@!~J)Z(})U^wLS|;B~ zEr)5)uhYaH5|`O5_jI_WBmK}i zwqTY`o{tH27rT)ieVeNh;Gs6yA$livd!wJ&P7O*6$>6`>sh2<)?oIfDL%Y2$EZD$` zfIV&YbA*rZAC3$QuOPvj=qFXfWy@NJZ{Tp?zPdpb?z(oeN7L<^WZ|%I|djcm70OOytlT*V{!wjX}t};o|$g@jc_9zYb zIwIVwz_(;4n#7@}+pkFCCOT#3F^9^hl$o)PnQd6v_0E|t3JPg1`~IC9!erra`AbVb z{S6-eauffr+pK`;|28y;QJ%3~rAPL8Qq#7WMRuq6N`ItR7b#(Agx4vd`~X<`18EzB zvjT@q@aePUIxAqIKt$3%`S9lm8*dKkg%}g$4D)jt1LaqAsfv}3zgR7*HuRjmK{PBO zxz)4a9+V7uGmY#N>ZU;+r{|mgie7ojdM+Jph!s6!cJvU;;J5Ul%4&HPE_hKj(%*jy zFy{v*w&xm01a2}QVA~(n!;>!QPb8}|dw41sDJ>F&Aa#M72IazQ2!n|7WzqRy3^9ah zaQmDaY+5hPUj+9V4Jf(|8^9L+jVcS)iKd?S5OoR$D@#6~_XlfBCnmx;r$xuy3b0Z? zz(j@j0gdW|KFKI037O6DWi`9j2pxxAaD#=+Id_5~gN!YMteEpoolG^{a)A<@U4>v_ z`hB0NYh}2=NoxJnKDx^VOCz*Un#bK}I5A(3$3zqA)NIvP3AD(xjE}I3$(y99o~>s| zdu}=f70bhs+(%PmfBd+4;)()vT*>e~o3&Km2U;GWbN*0euF)~)8r97mC9I>duerj< zQG~Hma?ncPTA z^^dcKag^ev1wlgN6s{(-^M6o0AP5%+MBkxf{@sT07pwJ;&=ImWaB}(=+DuWFvit78 z=zLQ{K&L0>Am@VNqSi>Lf}O@~g%x=PM$c+mpiCqfkqE;7@+rczscRB2<^Pt-JmFiY zr1KgGY^zKTr7AQ=^Lg zibXRhlAKc7jED-|3OPuItigpdD-IhpP9wdwGj-eb)Xz@uH_kuEqoM|Q*@igF3e*gb znHr~cJ3LA|iNmgp9JjolFMbd#>Q=VJ{SRR4WOIfnA=&$NtLU$P1a5|_cR^}F5l#yx0shkO- z?pebH+=H?K??cOcJk9s@S1cP^!`q>4dF9a$Le4gh*SdwpG6%pTXB%Bn$vRzTv<5v;PrU|MhOX(2;UlV@Kp2 z>jGLNkTOB${PUV1Lpd^UYPDy*V0=j5=H)N^-GTT66R4pu^VV<6mRtOqLgAOS2cZf{ zg1>0t%!f-MB+ziAY}X725qHL$-W+=}8X4J+;{Z}=B&suqOnUsM7wIpFmPCR$I!j1i z1rD8>qRv~ijNqI0h_KToc%zZTbkWZ>;`}o=?>_|+vjksP5f^sR+^*+b-b zhh{Rz`HfNcFF@)FA&DTfZi)2+^IC`CID zpLXJsMSJgj{G2_0l?@s9*sZ`y4GPmPV|wNT)+Ev6B2Fr6&~`_YQ0EHrIVM~?cj5~w zV#r3QF1#ENb9lwfmp!TU&chdq31ybgK|H<#MQj5LX4s)GI_~R`&U886NoTg3En;5*noYr(}ODTB^pwnBgSnc_X%`w&C~{ij~aB3{p6{o`qELMR=1ml7Zd$PQ;y0-1)4}7A@XO!e@N%D{) zO%j3mPq|Z4!2pzQTIhn20N)c$H2?$f#233q!eGTTpy99__viC7#pb-iou&uC<0h<4 zQ1TT{Hic9f{ffT7XOMpAo?ei&REZ>A0np9fWw71DenrMtW3pqhlpLrbjJ!$X+JnFxQAXY0^KN z+sl;1-ry&F2I-B+pBalya%9o;3bi%02*99tAt-IZVPp#9@c8kpgndEf(}rVUA@+gg zM~S$%$Yku)_Z*n8{dH75-PD?Wr6rH&|L-Yo&azX8nO3r6=g4X#rds;PVEOUxK@4B>|CWS!ZC$_t~x(%pBz#c zne_jCeLUfVauoTsIxFV9-I*}o69hkIr~;i3>EZckSaUEFrZXx{z_pj(pU?IM+KFC2K|H-MbnY41o{b6sW%RofEAyEPeF<=z&#$f5qfyEw} zj9mSVg&gh{*DdGsd%i}?V1aQGN1I4stwqxaWqtUZ5s+@4vvM7iDkZlkG+3k)3F`9f z_^YOWUo?o1QI!xrJN25Xjl?SKpP%UV>uTSBHBU>;0~ZRT1gE(atk(WW3pn;#Je~U9 zR_qvDezx$l@hG!VeGk*F zX=R+sIsH0pnHsU9s4g&R_g*d1uzlT*V%qqI$Wn9V*eaB;&K2;@~WRz&UIs0vz zBT*GI2Pr3HT(C;@H%LO^m%K&{l*y|yb!*f<=NwlS{neU(w;XSG*F7%ds9)C zmS+P`A%d}hrh`S5*ILAA9CF%hpDJ3e`1Sbd_85f2TubrD+hEE$1v+_?P7wWPxU!qKI_pf0e>98%?F z%Zqk-Z6HV50|09|rrB4k#e4|KG(YRZ+G$>e|KoG{PuHKioGoH!>v&CSI0jmb7zNJ= z25Ye^vi>e|=cQ|c^31~Fc~Yj9zWXJay|XDsvoRJRQ?NF-e9x_OH=TOjh*)y_i#U%| zctb2M116C5<9VDb?yU`c5IgV#P!X%MvrT<@T1Nq4h65LI=9ITyIMc}SITSK>O%mNG zg`~Zc`E6d9%>o1JJ`+mvu(Cjz&ztchUK_ju7I&Z7dTSBy*=5Ke(+@gbeB}BI zFFt49Z~fAmECx>WH8#%N_F2e8ffw`b`=eElzkA|M?MA!1Qk8-Fs2H(V8!gKpm5vs{ z!lqTfghP$Z$q?y?x^H1zAyAp$?341at~((w;F+E21Bn*phUo}VK$unwtdQ#gHi}9>wKZ*xSp(R9H;1VE4Tu8*h-koSC-)Ae%6~Xk z>yFs!2K-vu)>Jcvoc!Yq`ZW-xcCQt}G56t4^d2d5Zz5s3k3p2I3A=n!N1wQ-nhfl5 z`nuCpfV`Pkw6X?b1}(Y46*IV@{nUX_=qt2z(;J2N(Hr&Aeb2jOLktp5VoHES znSS6#0JV)R=)q5F1uiG$GgoU-slRNYm#n)S^Y9-2F%8MPbj&6c*$8!)-f1#d7}wUH zS{|NrBtPGLXBm}2B8Q&;dqq8HcrM#7P{*Y@CDI98M zkdGS?*7t6cSL^}h8_h!!4duMYe!NsURqp$69+x~8ShWyT-){+6=pt?@z!e@}GMO>lo=Ik3A8{YJ|}qeV4x z-E|Y@t&txwe{yp-?j&e|rDsBFzl_>>Y1l{V8Y=l% zW1N@fN-MN%u+_=3$9EL0g;zOBXP*YcJ7hvWq%;$`P>g_6emey%7C)_SZ}lFaU}j0a z-POgo{^Tm|gk0F6GtVi_9v1zRBo)V!5+gJR5ol_o)+~E^m^ClSPL1oz@fw6zy5Iu> zPgqUvH1^^R<>U^JD$yB?sZ$IMoik9UByWk-&1{7bBnC}5mjkRuu-{5y%$^KuO_iaB z-~9tBK6N}I)Okc1b3Iv*l3KJWZ`wSd?%1So1W1E}=@l{y)Oa%m;OMT^Fy^ znp{;-jI^U1Wdv0{QkLWSj_LqFdWqS*8v}XLlMA(JR)zN$lRt>rhWtn*@^)vv?9vQC z0HW7$4Iy z*zqVZ!1Aj8>IL)-FN?sz%OPf>o*G|9&p-R4iWSa>l=1b8=J#0Qg zA^DyZVnu@n$TokKpOhVX#5HxRNFEh7kg%dvimV(cPK7Dk*DZLpU4su0O&s6lWMf?B-#U4$-#Qg4A^C!86Mxy@ts`6 zZWbufzGFyrkxR~eLggCdA{r8w+Yx+_HAC8yZ*QhTL+myMCLC>rR*K&Wv+R0{WYVh+ zy@Ag{e5$X&au0h;0o~c*QhEncfg?8Sv#_fP#-%QZRo?mbVID`Y&hC&$b{=U0hdqu$r0;abnTV?r z4X9HjDH>b3?rscvJYWnztbA8T4gn4tP_)c59HY!qQ0Ab9*4k6^Lbl6t6^Il5sCI3&+yD zZ`&l@+j_1oZD&0%_c=XFW}S$7SSEUi%9nMkmJ64BO*Upa^ZG1<%96=ir~s2Q4(AtMqBhc zbQ3;xy);}r!~Kmyt`qP5%4m#e&srzeAz_!z3h=NuWOVkEWL>h0V{kl{yEI6bFDDMP zw{Yp1jhB%06NLez`E?pO7ANPI_S{$`DP;n#*V`8I1I&-PNc z!RtS`J9%8ose^B67RC2T`S(*&(8Sd4e;X$&&BV^pBY01#RRjmGLjB>!$2Bii%$p@} z0Otg~X?J0*^oqqwvpf53GHr;S#A^!(MT-4<#66iSSYKUt%mW6vVfdaXay}AkU|13>`h?6u*!8H4wQTEJ_r63rOA4oYVn!EFn0#R{y^A}ogW7lZ%RGRu zXMVLR>%Vx)+P!o88O5q~mShLM6wkh1OTR1DAGb@KR3=}kxd`&Z-V6FASX>-ef!R2rT z4Ia7cGYl_M=pb!mYahQZ5 z=-mh^2sFW9JOK@rXQGJnt>CXa!yt`hq63p8RS~LgAghawj4b4R>cLP%whYtC-7o5j(_8TCT z{w0RZCm8;I_l%{H!97Ba@!2)(ZZ}032A>trr3221q2N#(wIBA2otAb&Q zqgmI>#47;e!tW~jVuKi4-kqP}as24&&2&(LXz_c_ZBMJrO(6^AcNwV6wgUQENIOap zx}GAKfi*m@g5nUW~Itz2Z=J7nJeBH6-gf zmL|TJFqDYfh(7AmWmEv{ei}PM`Ga|PA~qzayNQ45yl|L%y^Qr($a-H%$^_FOYB(aw@Cilb zP+3uks;RoK9Mijh`Ox&q!~W;oNb7Bg`tbUX(_)TRr2|gInW^01CM$A?<0jR_&UwF) zwQ@`otd4W^{kH5LK7wrvj#d?%!vufrFNq=f>8R!W`Rc$=%Ufv{Or!wj)7t>+yuk2I z0t%lj>5>;znL?BU@?1`J@yJ#%bzsc)mo}b`%)Spzlhja5nx_3}3rS=rzw1Z44Htt)$f= zbF)KlAu#cYz30hBA%SENQ3@VEh@3QIpv^b;pho_6D)ZUq@GSQ=_0zB2_wCSlCi6@A zH>m@9R5X!QHPg< zPU*}u8_o8@p7xQfq!S4_*W_oIMn8aKzve&f;_**$WOLGFLSIs7oFquMza3cnJ^Zc8 zjcLJ(`^9?Zrf0*{PjqL^=kMqo85o~tey>@$Ps-E=bJ=pO>*QPs9L3S1KD&4It_L+9 zEHVjq$;M3ZAh9{Q-6{ok`8hy|a^wDl(_2gO(%T;RKDcjp$GkatWwsWR+B$y13=BoR z9Kp|%{V^>Wjh|GM&j`&-JhXj>{_nf`*9hU%)#E(+@8aCa_s~)Nza8fP??DNb>NawF zq6nYo?~xQ_Iff8mueCkNj6gTv>tT^H5!Uw!98Ox*tJ7~(^y3m2fM%u zaWhZR{T5HYk1=2c;IAiwCQgLz{ir>b=nXElT{F@sYGA=lZ)H3ZWB;`lnGSi{p+k%Q#ph4e+)b^g84k+1{W z{iFc^6NApsvnpl15fI1Zd)D@>uaq=f2%!$~MGMT7Pd(}W?kJ=JF}gEO&t zJ+nedv}HeC7FVcafglW}aWQXzH=srjDa@Y>f@9d_*xT80zyrc!3-e0Sw^=n!sKP0< zAff?GdS_f?Y7EU0%k2>$g1dvV5C{PkB7Xr(9yxC+m1eaQ6KX`S$iEEEaO8NcPPjxy zApa<9<|o#+&2`CUiOV%MP!s?mMHY?jM<5t)4yuOlduuy6KD#&IZhiB44TIY%f)QFF{>RNa=I<+_gN^T@`skNwI znN6&oX54vyXJ5&1V-?h9EhH^=uV^LH@fZ^ajlqf9zf(nJ43m57_ug#P9x}ggKH(m9 z2+`DCY|UUzEM%-SqNK7~_;KbO{c2g~m`Sps4()^>McNc54O@k4Wt8Im&jJj_sFN^I zlxEJPDy!|*PQQX|qd(M+U?FuCfq~^P{xdRKVs2S9YgC?r3=& zO7<X3***rW8|xb%X4|faOy^8y6lp_VT9f<@~^nWAw19n+}VXAc{nZK_hH{f zuGR|Eji9arhf=q|U`XS)+PV}fOFh`ST=Y89cHue6$BN`s;w^i1RxR1q5JA0z>CA~K z%XX|WB$kOp2k3N|HI+mqig&qX71%DUswev=u3;`Z;hawB&;)-KLqDt#t_9Cm6)Yc; z8QBw>?AX2K3J+O}1>iyVp*5xE7S-oYPT-xPxOSycDTt;X9i8KN#Nv=_lzX4SzPjr0 z<5i=I5MvcS4)(0Od`@QPJC_Y#7Y(+b8dU-(M;a#&gdvg44A1k%Ht66%bd+LHIXviC z@TLqhjJW&!SuC=1)Tq80(cAsvo))Z9GSQexx}Ak)P!`Y3c#`w2_TLz_yOXA5F@%bJ z3cAQ=6rV|;Jg*S4L+=<19M%P zRqVjd4SxokkjaseX;0Z$~&rWD2}D8c%p3a#G;zi z)3X(=vCJOJ-Q?~9g3};Zp9@xm;M3?}MJ6lZ%;7QPnb51(_|i!VR_q3pS5mlCr0mP5pTpSXXAR1#*k{~J!!dX> z$JcAyfNXKc$u5wTwl6G!imB6wLp029t<7t<88vW~P z%jemfp>s5al^G+1$d`tM9yJx@UfSZ~D(}MEy@PJt4L4Fk;UZ$iiE>6$ywQ<7S>8iS zc7?-F2u)?ME>ds;6ld0b27fD)iypO)<;h3pdM_6`EJ}4|UNWIpA6jP&1}4PALs2D7 zicwb(L#>fw}7oQmWSZ+vdZuV;ythiPa*w4<5QuI?HtY8T^+R4S_aqE4N(* zCB=J#v$;&?LWEqo9#<3N^>f3!va~-cv?A9Qf74$+C~v5vZL4ldLMxx!qp3v50$7SCTrZ57 zI3Fncd_B)urp9=TU??-1qw7%FfVR2Xa8#}8AC#dIP zto~DfJcCQ$Izy+%t9(>_FosNso8lNgQHp!qR~nBd(fA^VGUksINp)O3m;j>t*4Ed; zDt%R3BrD-NoW;-ncJZlQHvmLG$^5lU*<7M%QT*WWGg!Z&>cW|(t~HINR55FFV;4q* zIP%YQ9e%inaE8yVIDy>V5LkC{&k>mW_Nro{CDbO{aD)5?D4e!jpNHoL0h$w0OFN65 zOLU?x^K&!bsLx&>+!&OVX3{O);uIETQHiCy@v0kKozA6xEE<`m5rZFeC5-!hlBnsp z5T~AJ@m_4FGProhpHU^6+8f&AW=C@Zc8Qw@pM8@*gV=Lqy8Jd^JXeI1$lz3^SWj#| z|ItiE$-4M+<{RTeeVYXS{cZWH9pPW_Hb&*jj*t!Eqx~I)NJWxBFiW`XH6I~!J*2GE zQOt$#!`9WTr)QaJZ45r=w##jhmD*mdiaaoe$M>&S#+oLwIGqTcYibLV<|A(|p?p;x z-p-K5k>s8mO%sc*otYDlN<05?PA4WPDnM^q37h9*s-`O@ap2PNT6vknF_dj-38y90 zfG3j{AvA=-fm!4zjBV$~D$}+C1-M^_qQy2^VAmtrsi~-2@9MClpM8k0f#l#L7%Q{} zwg039c(0cNbxp9Kc{;(eXi%O>uUjrE&LKUEK?YqoyAN2Tn%b;m_RQqkuWRqRx?_l3 z)nHoj0LpCYWc%2k%r=!1h<$u8$&m%vgr0D5p5QGsHHVTMlbNt4&CvV=wK2++MN#9F zp`+$}hsd|p!OAhk=Rc{Y57A}SrQ<(P<4f(UGc*f9(nvM0=kKg2Z?V!w@Y-D6COs_|`nzK-FSabpRrvd_}b%wFKg z&Kzx@z0Yto@S^RQSz?_B4#IM4Qn}L2zI?ar*tVB_#3FbGf!s`X?L<*ZW#leA3qiO3 zGJTZDivdJhMuD<405yqTJb>vZ?;-vG30=d4PNW8W%opAr1mla3NxCzf*hc-OV3JJb zS**e+F6Ed8mh-tXl$Qiy2x%M+>17?IsEVR#Il)Q^(TOm#ExN~>e>;qOPMX$-2NJH( z+oFL{JT7|b0VCzh;RN8Lnb1c3k{kGDrnBoh`z-O$!`$k;CuGw@YaPBBfg+9NbsB~= zQk{$^ZEEK{w6G3848W|@>Q=HUw$erPN9gqMmdo=J^xiQfc}Sp3kQol1C`dDGWcBWQ zydQ=R29Fq41nPD;fQH1WM{R*6w_Jo^h9P7$+y)Ai*oM|@g+IzeYqZ86U0hffNiX>$ z@a&R`t1DZ(u40u_NkzH~S&m|k(i$lzSUP#PIS=;n*UOdpsjhb4TwXuSCr)^Wezz{% z4zpXiy_26wB~Q9!#kcq@Gun`tnb|DGi7t%3B*xAsNU8-2##)#AM0cjyf`=_6PeO-G zS?JBlk|*J`j-BZt8A&FMDOQ+`@w=s#is{7!E0xHnc$Qj%K0dy!VQpywsW>?X%lz`G z9d6InGPa511+Ee+8-6Tp=18aYYJnb;nYpP-L(OTcWNS@KZ#>` zLsMTrv`j^7rLXBWQjOQvs@i~4W(rHQ+}iKB&$iLJANHJ!YH<9Dy9 ziS=J_+U5VKrT;VBYD}-E5Cr|*-~Gg}h(7=o(r_yh*WA*WDPJNWsvi0EDRGx@AT~)` zFvI)Kbko`b(g&Z5U-9C)17%#_-BO?y7((dTn$aLkl``mZBthQ_eP}D0aH=bvwf?Rd zdPy0|GQ~03U4)%X3+}40>ZiXZ(E{dt!i-$t!&?pBqB>|$fk17Ypnorwhj}F+OIvu$ zSzOc=<`&}BsnD{(V)u=l+W>?aT|YfVRZ1e>8p!EY>dh+>E|90plf2gDP12$*M`5^Q z0gK~It0jP3?+X6fQ*I-v)v94JnDhKYnX?fZ0=Yg+IfZ(w+H3=*oSh zKuQ6xFk|5b+8h9rCsvE}PQ05G=@D17or9^ZwiL|@h&NCJ7XmFo0YSQR$BmFfE6pQR z<$L~Q;`{_Ln_?Bo<#ZY>5}AE5jSy^<$EsX`PQIa3W_dP%rR=lo53c{N!3Pb-uzl6R zOczj3T@s-z>O1Ns^ByPZMwCS+oxTG843o&*vc3w)JV0b|%cEhdLd_+=3RBY7c+q7q z0>MuIyAjtg!Ann z2@#3JOKPP}@~XIa?3VtS)zFZboSl8n%8h^Oe>roW;yq963sw2^BAQlLYY+W3JYzDJX}Z^y)(PBbe1%0QI?cZa182-Os52Np{elt5q3lk?gq5t#qU)N`)y4H99G4fx1d|7}w z>llt~Fj(#$<$n>wLmd6ciMcu+(+_B zXmp|bpgmtnJBg;v&R|7|_4iw?#*`s%BoIyhiVC@=$~_f`F#9w1!>D7DGs$y~ zsk3zz$SM_-b5`=d1GZvwNgq3RskNFztOndYNkMeJMv7LONWD-i+P^wRMCMH(2|r+s zNtf$THbbWaQ>`_eu#U6_QNqcf^iKT*U4BJQ49u#F%4_>7~k=dv+a;+Og;$-b|D-xdJ0Y0(=i!$n+)YD-HQ5 zvoLFt8o41VJLD&8fw=-k{-HX zr&D}^1n$&w;e0A0)!_qABTns~5df*1$%=WfT-Lxn1aSP)J_<3HuZozm2;m>k9@IOj z9}QJyqmKPD2g<^%L=NB8!YB`-4g6>QA-a+XJzSSlW57zLIU2tvu+p-6d~8k_`U%YI z9L`17(4?V$i^-nN&yS%jBE3bLAAK(`;EdlunI8-b^Ifc(w0 zmUfgiay#jRr)%1`aKq_DYW2V`GZ*Dzxdt1S$`<~#L4cOCk*RnpPn$VbY-}gT6;>9# z!NO-W>Sk)Adny1%il)5hvDX@=zEPq5JPN&G+BVd9rVfb}OL32{pWL6q^*x>qFmb#RXt=ILq?`(^{ZiQ13E*|u6x)VbZdfk<@W6r+eTmZwKwP%=g4!>);%ra*s- z!VS3r)Nc2L>a%9TkFtbtESAN#N zHg^I|9Ud^brA-Uv%zS-8QlglSdDsy9?z+(*2KuO{#9$oED6pF&eLgG{A32f>6gaO% zrC4}HPZY=JGUYXXFl6$5NgB7L&g$S`kf}Scsvvu)vVIW=%~Cv9+x7RGr>Og#Ck1&{ z=I`?GHUTV9+wGlZT(;+z=CK25gS-|`-9&%0k$yX)iI$VK1=8e|*l3Q}!)NTH$S&bx zHS6cWX}6QbDn;*RGxpT&keu(h%8}k4AtEb-y1be#mu_4>nTq?mQ{t|a(leoRL=-li zbClCj%L_HBSqu4d2qb&=-FnSx0Fj}R8mT{)QGA|BegNUdUkiiCu zIM5#D5MEmtrxm}2e8cn>z{7F*h=1$f)KB(D)#zSL%_Z_AW@HvI@wz@qy|CCjgvPe= zA`VxvnBWVz9+2wT&629^FF)+p&n2h`Y{IZ|X1*aAUr( z2~Jo(^Xdy9uud}Kq9!8Fii^*A7UND4XNeB_H7;~VWC++15!m)UK~tZD(?WD-k zyZYKCqQx8!PJ6ElVbqWHgA_DJc#Wx7|Nf1vEBJ+%_u5Y{?vVpWz$?oVi)3B&aNv4Z z@UID9>ve2B%IP{Ev~dhpL&TPy8Pym=fxR>P~(H5r=*q$0>+u7`}fm>*S1-E~yxIpU}c zd6K~mGOPZw?Y%KO7&&?1n{``nDt;P=jf{`3m~3A*+Zl}U;UU5yN6IMofqqFs>SB+b zMJGcrY2~YZWjUPb{mJg4aoS2qhO>0QINnrb))#0UZ`CE~+H||}u|n2^+xD_9wIsJ0 zmlN|X^h3)PHDdg0d3-Oj#lWOhhra-MRhi7`ulRkt{t}6~rkO9D=_)sOznMBZdZY^# zMqJ!8syFkWc}DZ}vU|Fl3t)A(eEx>hipA2B%mc2N0dU>i|MOMb8GA5_I=I@JDL4Se zpBS5o0w7#*4^wkTm;VxLa!p`X1k7X%J({S!UfFUin?_&g3jl*Fuj}A;#+1sT`f3Sw z>OTTZMj;{C_4u}me1XdVMod3oV@wIUC^eQ70sijT-_H5v+#8f1ZwYN0?kE-OvOY-s zkSGDlA|dq~N2pi=d;FGferqodo;;o86`fW*_W)W{9$^rlb2IQ+Esl@ex(oh!}^D6M)wjazG99W z(=Tp^oIRdgu{4)It0B(pZw=SiLiBnZnpkD^A=Q7$-uwCUaZC)i1NBsRr{ZSieUrID zBxvbVd$u|Hc{=%2_iMAhnnoYY)TZZGHP!vhYHXXT?7PvXzF&!NtF8R3O=9zpQiQd| z{A7oi(h{!%5?HWxmAd)cm-?U7M$ccypU@4$pTPrqALwyu7n?7qc5 zgtEdD*Xc&U6X=$?N1r29VqV+b7d#TWq1~XCyLTI|sc1gy`k1Mi`)Q(~kVc%WdVl!9 z&Fr#sZK_qw4w7W(Li(DqdT3>s0K4mO5(J691m=L^AdYe?xk5XeS1eg+5z$uZPCXSY zETwwzfyuDoqtFrYPR+m75Yw@t!K!28fMd`En9yd(r$OqX(VtrXszA^9_UjouH!GR> z#Xl5LU$+4I_X;eo5chl17QxDCgumt?)Yggjg@CB}SIEQRXC~5#@lC9l@#=v03-)fe z7CWY>5*F8^wD2tS4wZ_4f^aB!0qwr|B=>e9pgD6GiF8kgST2MgX7j-g+K`K5YK6<7 zV~6rrK`*xB3Kg4XF0&lbDE4SDf1kC(MiXZ$b$&if zp!0n$7Lb38WGw6BK?WMq%5v4;-&-?D?dgU4BvLDAP$8>q+5V&1O3j`aY&O=WS$-ICtm8(uR+x3(a(w;2mM4P zY$!nM=sFBU0ut{@{1)!nxuO`tBin&+;j+V2pHf@Dbt)W=+alhZ@G`ygJp&Qu+*NY& zdoX|ZbSM*+=@aIB=BQh}ZIw{)SO05oQqRUg?%x_o z(wc2F6OB;nOX}WRft0J~4b#8Pat=NC3X1yJdKQHr^3Sax@j*HQA#aWfZ&im~0rSZA z#K`y_zCe3JaN6w*1-N=rdw_%v=6SWJ&W;u^fHg(LVn5>ZIksLa7&{>P{hXQ2l&Ibr z-ssP9k_C?)0@rZEC0=P4Y0q(DBk@2?(!YnIslIF$EXL5!y>Ue(r6!B^RRA_45j^Ad zn4TJCfL8C^oO z0Yy#Q1pQHR@^NCCgA^;>#O#aP!ncZ;CXzAXV(70dH`aHjyc>Pl)a;usdPc5NPt*-X z0nYL@D$$*l7VjY$OLpp0?K?{MU-Q%nfR~Y7_}3engLCbfJ1>%{P|v(@V&nGXN2cVY z;i&Plh-#kY+&$|WAk7!>h*eT&DBdLr`F38Q^JLlOOBX_Zya_B%P*j0IJ=kWcSD|C_ z(KoD0R;4>Zr6F^=yoJl_AR}l^wyw;bTC}=)GCYKb4uy)jZInmIqpMOmq*j^_CASBc zAi(O%7)RGXd`tjb(SK zjMZ2E`ha%wT?+>?b!IUXw|H{$V zvc2kPz21J__|rWqP6>*j65hQ$c1WyR6HPX96RVu9%gP$YDNp@LUuS4h_P~M<)BKYp zXu^UW`zDrQa-+&n8XCh*+TU#jt3i=6BqKG^&3bcjx*pe89%82@r*NCJolcOSxxVf` zzYIq~K!c-9jRsY6am^(gI58I*_Jn6{vb1s9Z~W}ZlJ%Rn%{W^?N^yoGm=DBBW3jD; zZocD5IPRi3iJ~6?V;yR~`rXgjc+%P;v=`XbVnUfZK>WWi?>9LO=Mm%dxxuYj5* z>$eisQGvqjI(BFR6;)Dw&-a6JGLW>>5H~wK-nm4oq)s?T$_wEn!V#_S{vdx%Qa#Eu z9%BL3WnyF?Ae#ScK$ZfGu5)nuGe1q$)YV+)Lh^I-3tgiOPyRMP5>|H}Xg+~4&Mow) zUyn|rL`Eom*uejM#S18r`#>uh$Q92``s5v!CLJQ)#UYnmHN46=Wz`=gS#=xFt0dYT z-}8r{|pIcsY?3|mWZ7QJewZqhsY-7h;&%S@!=o$J$IY1lR7R$>QT2<{R7XC9 z$nvCG|K(Qt_;2(XYU{CSD$LX`S1H{!2jHA(eGndPJwG^!y$>LmSVXCq7w4Ij>Pg(D zMsdJW{rd7^4sA>_>kXAZ>QE#vX`kl6+0&{z5eG#wuw*&SyS#O*EHGW6Qp{%PY8{89 z&%MQ8lN)qka+C4Q;M$63wu7vC$*{t5iEr!@4U>z1z9s5N^yY>Z(K37|5*gz)$v)_j z!>zl$eRB~;U;wfWvP5O_F0c%=^v8!~AS7|tZJ4(PJ!_-EvP84x1r->>p9gQbPB2px zlMZMvU9$4t6G9Zt~$k=Q8FXUzJCg;Mea?Vw~#@TE6YH_Yqfl13!T* zq{vY)X0CSxb59my)wPl)s*BE_h*Ugk?I3sDbTmDQtPr~qU9~~t4V1NKi2`Gl?q@Ml z5s4Gp+qVAJ`14FE`#uQz%UQ`qaeXvf6BEwD`q+*MNnL#-0>j4y4B_Q4sGiNe*{FTb z+(}rdLG0H%`fP`;oF*HqtzS+`^1aM&9_qoH5yw)}Q*vt{xe)x=AdlA8PCo>U#GQGh z4n;B#AzG4=rQPZ4v1HgW1v-sJ%0U~FfBr05b-S9eKuc*94Ve1135O!Ng`cRN^K)Yn2bQ`tUsEow4MG|-%aE2!Um z&;hdMDvf%5PyHp&(*|xt-`hl*@7tC=t($w|^OUQ_U;TH=piBabmtc}mBi*H}5vE3x zRvs5^j*GL%2T1SXfZnmXXW@(5dNZqMc;kPPHVG2vi(7UOaWWD?CTdv0$6_;Hq395C z3J4Y*&>||DItu)Pr#UHkR-!xR=?0njh6#87f^iBpBt7Uk5T$R%!M!#$JGg%3%w4H0 zO@l7dk4yIYdfwC;DSLDv@tm%lp-EbI zS1=tjIIkO7QS_(@t$YM@XLlc@@<+&a((vJ|ppOg&gb_wl-%V^VQJrUJu#Jlb_3S0(i zJd3h1&7shC{t?j*SuqJxuA4fH3)wB$Ec(6Zb0Elv!au~Y-nB6-9LC7yNvBczx2sZs zuNSGU-Mo$A|=McvO8z z5}bb%8GjVYs;{1m081-BEzTtG6A49@(>5#|5a6h56G_;EC+rm5jaf`b3ovRcXv^(&3 z%~7h+7m0FcS0`x5Ho+BvO~-`IuoUo)i~|0Uj`>A56rYIamLFF;_LP4Y1bPqc!lMT~ zMPmTvrhkJxIQ?S+r!(U}=i2@u*Zg0|g8~SEwsGY*6cQaO+7|6GFgS?nuXIX>Ci^2( z0oe4(U3blO&T_9{%^Gcp4Z%QXa*z0zQ_Pw+Pir?;+0M7u*48a)QY<)u#lh}mu zT+88(x5-LnQBq=TDkH`93gI(aj%d;ut@F*%#=R|15qj3v7^S%_*&C%7zP>@6RRWx4 zrAR9WZt0^6TX4AQQ~v;jRM!7Foc`Cz|3g33*u>WS|1}IXRc-x`$-=&I zJwfqK_1ssowXiyH0|5wjkHAq=WT$vz$>ns~bN+;`^_#`?b>Pr+;^7C}d`&#spDDCp zrkaaI%TY8Nu9k}s>|-qr$3C+58fexF*s|ADKN?g@Upgr}8#FE*_+4`^#|k$l+LFz27TnbwW*~Esz^Nd`$sY7{d z(L%nl^N47D35HJy1P^lWJgB2Wz-yU^FOY!g+?8uh&Z-$wG$!;b%Ne?@+lhBUpyy{o zL=H;gx)E=;d1#@qt#M~}Q{&*Pb>Rx0>dr=jpLjhew8=Q*X0m zCJ!q!LBU~;OsaDT))ukMov)EVz zXKxg6QY}JaTl~*>Sv)Ch)*}xtT(MFFy)FA^brpDo>}Nmdk3?zMM5j(q;d;B9uNe3q zs3aiU(p-L?uMvIqF*1?k4N-C4zC}$=Hnw6*%(znuv(^XcxbwPhn8stI7o4z7#&oX| zVX{Pbq(2IH?xLaZN84_`4fbXHN

8NJctzK3KDKl)p3T5%A>*c|ZNdH|pqmjC;2 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 nKc~%0!=qS~jDvdn4QnPE3@7p542J&!c*Wjp diff --git a/cots/org.junit/junit-4.10.jar b/cots/org.junit/junit-4.10.jar deleted file mode 100644 index bf5c0b9c6ad26f515407effa28232a3e05200868..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 253160 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 Yw@xWsR6GN7?^BUq&LVA^JqvL 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%0D;ifS?#HmxOc?~%#59-k`6GKjp6kN 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Ím7$ACoBz3?~BdtyH$C&Kj;+gbPIO7q9ojc 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'; + +-- Restore dashes from @@@ +update events.aggregate set grouping = regexp_replace(grouping, ' * * @author bphillip @@ -77,8 +85,19 @@ public class D2DParmIdCache { private static final Pattern RangeFilter = Pattern .compile("(.*?)\\d{1,2}hr"); + private static final Map WIND_COMP_PARMS; + static { + WIND_COMP_PARMS = new HashMap(); + WIND_COMP_PARMS.put("uw", "vw"); + WIND_COMP_PARMS.put("vw", "uw"); + WIND_COMP_PARMS.put("ws", "wd"); + WIND_COMP_PARMS.put("wd", "ws"); + } + /** Map containing the ParmIDs */ - private Map> parmIds; + private Map> parmIds; + + private Map> windComps; private static D2DParmIdCache instance; @@ -93,7 +112,8 @@ public class D2DParmIdCache { * Constructs a new D2DParmIdCache */ public D2DParmIdCache() { - parmIds = new HashMap>(); + parmIds = new HashMap>(); + windComps = new HashMap>(); } /** @@ -140,53 +160,18 @@ public class D2DParmIdCache { } private void putParmIDInternal(ParmID parmId) { + DatabaseID dbId = parmId.getDbId(); synchronized (parmIds) { + Set dbParms = parmIds.get(dbId); // Add the database entry to the map if it does not exist - if (!parmIds.containsKey(parmId.getDbId().toString())) { - parmIds.put(parmId.getDbId().toString(), new HashSet()); + if (dbParms == null) { + dbParms = new HashSet(); + parmIds.put(dbId, dbParms); } - // Insert the ParmID into the map - String parmStr = parmId.toString(); - // Ensure that the staticTopo parameter has the correct - // capitalization, or the smart init scripts will not be able to - // find it - String parmName = parmId.getParmName(); - if (parmName.equalsIgnoreCase("staticTopo")) { - parmStr = parmStr.replace("statictopo", "staticTopo"); - } else if (parmName.equalsIgnoreCase("staticspacing")) { - parmStr = parmStr.replace("staticspacing", "staticSpacing"); - } else if (parmName.equalsIgnoreCase("staticXspacing")) { - parmStr = parmStr.replace("staticxspacing", "staticXspacing"); - } else if (parmName.equalsIgnoreCase("staticYspacing")) { - parmStr = parmStr.replace("staticyspacing", "staticYspacing"); - } else if (parmName.equalsIgnoreCase("staticCoriolis")) { - parmStr = parmStr.replace("staticcoriolis", "staticCoriolis"); - } else { - String gfeParamName = null; - try { - gfeParamName = ParameterMapper.getInstance().lookupAlias( - parmId.getParmName(), "gfeParamName"); - } catch (MultipleMappingException e) { - statusHandler.handle(Priority.WARN, - e.getLocalizedMessage(), e); - gfeParamName = e.getArbitraryMapping(); - } - parmStr = parmStr.replaceFirst( - parmId.getParmName(), - gfeParamName); - } - parmIds.get(parmId.getDbId().toString()).add(parmStr); - } - } - /** - * Places a parmId into the cache - * - * @param parmId - * String representation of a ParmID - */ - public void putParmID(String parmId) { - putParmID(new ParmID(parmId)); + // Insert the ParmID into the map + dbParms.add(parmId); + } } /** @@ -209,18 +194,10 @@ public class D2DParmIdCache { * @return The ParmIDs in the given DatabaseID */ public List getParmIDs(DatabaseID dbId) { - Set parmStrings = null; + List parms = Collections.emptyList(); synchronized (parmIds) { if (parmIds.containsKey(dbId.toString())) { - parmStrings = new HashSet(parmIds.get(dbId.toString())); - } - } - - List parms = Collections.emptyList(); - if (parmStrings != null) { - parms = new ArrayList(parmStrings.size()); - for (String parmStr : parmStrings) { - parms.add(new ParmID(parmStr)); + parms = new ArrayList(parmIds.get(dbId)); } } return parms; @@ -244,14 +221,9 @@ public class D2DParmIdCache { * @return The list of DatabaseIDs */ public List getDatabaseIDs() { - Set dbStrs; + List dbIds = null; synchronized (parmIds) { - dbStrs = new HashSet(parmIds.keySet()); - } - - List dbIds = new ArrayList(dbStrs.size()); - for (String dbId : dbStrs) { - dbIds.add(new DatabaseID(dbId)); + dbIds = new ArrayList(parmIds.keySet()); } return dbIds; } @@ -382,6 +354,19 @@ public class D2DParmIdCache { for (DatabaseID dbId : dbsToRemove) { GridParmManager.removeDbFromMap(dbId); } + // purge the windComps + List wcToRemove = new ArrayList(); + synchronized (windComps) { + for (ParmID id : windComps.keySet()) { + if (dbsToRemove.contains(id.getDbId())) { + wcToRemove.add(id); + } + } + for (ParmID id : wcToRemove) { + windComps.remove(id); + } + } + statusHandler.handle(Priority.EVENTA, "Total time to build D2DParmIdCache for " + siteID + " took " + (System.currentTimeMillis() - start) @@ -397,7 +382,7 @@ public class D2DParmIdCache { public long getSize() { long size = 0; synchronized (parmIds) { - for (Set parms : parmIds.values()) { + for (Set parms : parmIds.values()) { size += parms.size(); } } @@ -410,4 +395,63 @@ public class D2DParmIdCache { buildCache(null); } } + + public void processGridUpdateNotification(GridUpdateNotification gun) { + ParmID parmId = gun.getParmId(); + + String otherCompName = WIND_COMP_PARMS.get(parmId.getParmName()); + if (otherCompName == null) { + // if it's not a wind component just add it to the cache + putParmID(parmId); + } else { + Set windTrs = null; + synchronized (windComps) { + // add this parms times to windComps map + Set trs = windComps.get(parmId); + if (trs == null) { + trs = new HashSet(); + windComps.put(parmId, trs); + } + trs.addAll(gun.getHistories().keySet()); + + // get the other components times + ParmID otherCompId = new ParmID(otherCompName, + parmId.getDbId(), parmId.getParmLevel()); + Set otherTrs = windComps.get(otherCompId); + + // if we have both components + if (otherTrs != null) { + // find times where we have both components + windTrs = new HashSet(trs); + windTrs.retainAll(otherTrs); + + // remove the matching times since we don't need them + // anymore + trs.removeAll(windTrs); + otherTrs.removeAll(windTrs); + } + } + + // if we found any matching times for both components + if (windTrs != null && !windTrs.isEmpty()) { + // add the wind parmId to the cache + ParmID windId = new ParmID("wind", parmId.getDbId(), + parmId.getParmLevel()); + putParmID(windId); + + // create GridUpdateNotifications for the wind parm + Map> history = new HashMap>(); + ArrayList guns = new ArrayList( + windTrs.size()); + for (TimeRange tr : windTrs) { + history.put(tr, Arrays.asList(new GridDataHistory( + GridDataHistory.OriginType.INITIALIZED, windId, tr, + null, (WsId) null))); + guns.add(new GridUpdateNotification(windId, tr, history, + null, windId.getDbId().getSiteId())); + } + SendNotifications.send(guns); + } + } + } } diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/cache/d2dparms/D2DParmIdFilter.java b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/cache/d2dparms/D2DParmIdFilter.java index eb523b9f93..c7096adedb 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/cache/d2dparms/D2DParmIdFilter.java +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/cache/d2dparms/D2DParmIdFilter.java @@ -34,7 +34,9 @@ import com.raytheon.uf.common.dataplugin.gfe.server.notify.GridUpdateNotificatio * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 1/10/09 1674 bphillip Initial creation - * 10/06/09 3172 njensen Based on grib notification + * 10/06/09 3172 njensen Based on grib notification + * 01/18/13 #1504 randerso Changed to send full GridUpdateNotification + * to D2DParmIdCache * * * @@ -53,8 +55,8 @@ public class D2DParmIdFilter { public void updateParmIdCache(List notifications) { for (GfeNotification notify : notifications) { if (notify instanceof GridUpdateNotification) { - D2DParmIdCache.getInstance().putParmID( - ((GridUpdateNotification) notify).getParmId()); + D2DParmIdCache.getInstance().processGridUpdateNotification( + (GridUpdateNotification) notify); } } } diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/db/dao/GFEDao.java b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/db/dao/GFEDao.java index 967a62f588..04ff02e012 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/db/dao/GFEDao.java +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/db/dao/GFEDao.java @@ -105,9 +105,11 @@ import com.raytheon.uf.edex.database.query.DatabaseQuery; * 08/07/09 #2763 njensen Refactored queryByD2DParmId * 09/10/12 DR15137 ryu Changed for MOSGuide D2D mxt/mnt grids for consistency * with A1. - * 10/10/12 #1260 randerso Added check to ensure db can be created before + * 10/10/12 #1260 randerso Added check to ensure db can be created before * adding it to the inventory * 12/06/12 #1394 rjpeter Optimized D2D grid access. + * 01/21/12 #1504 randerso Back ported change to use ParameterMapper into 13.1.2 + * * * * @author bphillip @@ -321,13 +323,13 @@ public class GFEDao extends DefaultPluginDao { } if (sess != null) { try { - sess.close(); + sess.close(); } catch (Exception e) { statusHandler.error( "Error occurred closing database session", e); - } } } + } return failedToSave.toArray(new GFERecord[failedToSave.size()]); @@ -460,9 +462,9 @@ public class GFEDao extends DefaultPluginDao { dataStore.delete(groupsToDelete); if (statusHandler.isPriorityEnabled(Priority.DEBUG)) { - statusHandler.handle(Priority.DEBUG, - "Deleted: " + Arrays.toString(groupsToDelete) - + " from " + hdf5File.getName()); + statusHandler.handle(Priority.DEBUG, + "Deleted: " + Arrays.toString(groupsToDelete) + + " from " + hdf5File.getName()); } } catch (Exception e) { statusHandler.handle( @@ -657,10 +659,10 @@ public class GFEDao extends DefaultPluginDao { s = getHibernateTemplate().getSessionFactory().openSession(); // TODO: clean up so we only make one db query SortedMap rawTimes = queryByD2DParmId(id, s); - List gribTimes = new ArrayList(); + List gribTimes = new ArrayList(); for (DataTime dt : rawTimes.keySet()) { gribTimes.add(dt.getValidPeriod()); - } + } try { if (isMos(id)) { @@ -670,26 +672,26 @@ public class GFEDao extends DefaultPluginDao { .getValidPeriod(); TimeRange time = info.getTimeConstraints() .constraintTime(gribTime.getEnd()); - if (timeRange.getEnd().equals(time.getEnd()) - || !info.getTimeConstraints().anyConstraints()) { + if (timeRange.getEnd().equals(time.getEnd()) + || !info.getTimeConstraints().anyConstraints()) { GridRecord retVal = (GridRecord) s.get( GridRecord.class, timeEntry.getValue()); - retVal.setPluginName(GridConstants.GRID); - return retVal; - } + retVal.setPluginName(GridConstants.GRID); + return retVal; + } } } else if (D2DGridDatabase.isNonAccumDuration(id, gribTimes)) { for (Map.Entry timeEntry : rawTimes .entrySet()) { TimeRange gribTime = timeEntry.getKey() .getValidPeriod(); - if (timeRange.getStart().equals(gribTime.getEnd()) - || timeRange.equals(gribTime)) { + if (timeRange.getStart().equals(gribTime.getEnd()) + || timeRange.equals(gribTime)) { GridRecord retVal = (GridRecord) s.get( GridRecord.class, timeEntry.getValue()); - retVal.setPluginName(GridConstants.GRID); - return retVal; - } + retVal.setPluginName(GridConstants.GRID); + return retVal; + } } } else { for (Map.Entry timeEntry : rawTimes @@ -698,15 +700,15 @@ public class GFEDao extends DefaultPluginDao { .getValidPeriod(); TimeRange time = info.getTimeConstraints() .constraintTime(gribTime.getStart()); - if ((timeRange.getStart().equals(time.getStart()) || !info - .getTimeConstraints().anyConstraints())) { + if ((timeRange.getStart().equals(time.getStart()) || !info + .getTimeConstraints().anyConstraints())) { GridRecord retVal = (GridRecord) s.get( GridRecord.class, timeEntry.getValue()); - retVal.setPluginName(GridConstants.GRID); - return retVal; - } + retVal.setPluginName(GridConstants.GRID); + return retVal; } } + } } catch (GfeConfigurationException e) { throw new DataAccessLayerException( "Error getting configuration for " @@ -720,7 +722,7 @@ public class GFEDao extends DefaultPluginDao { statusHandler.error( "Error occurred closing database session", e); } - } + } } return null; @@ -743,48 +745,48 @@ public class GFEDao extends DefaultPluginDao { @SuppressWarnings("unchecked") public SortedMap queryByD2DParmId(ParmID id, Session s) throws DataAccessLayerException { - String levelName = GridTranslator.getLevelName(id.getParmLevel()); + String levelName = GridTranslator.getLevelName(id.getParmLevel()); double[] levelValues = GridTranslator.getLevelValue(id.getParmLevel()); - boolean levelOnePresent = (levelValues[0] != Level - .getInvalidLevelValue()); - boolean levelTwoPresent = (levelValues[1] != Level - .getInvalidLevelValue()); - Level level = null; + boolean levelOnePresent = (levelValues[0] != Level + .getInvalidLevelValue()); + boolean levelTwoPresent = (levelValues[1] != Level + .getInvalidLevelValue()); + Level level = null; - // to have a level 2, must have a level one - try { - if (levelOnePresent && levelTwoPresent) { - level = LevelFactory.getInstance().getLevel(levelName, - levelValues[0], levelValues[1]); - } else if (levelOnePresent) { - level = LevelFactory.getInstance().getLevel(levelName, - levelValues[0]); - } else { - level = LevelFactory.getInstance().getLevel(levelName, 0.0); + // to have a level 2, must have a level one + try { + if (levelOnePresent && levelTwoPresent) { + level = LevelFactory.getInstance().getLevel(levelName, + levelValues[0], levelValues[1]); + } else if (levelOnePresent) { + level = LevelFactory.getInstance().getLevel(levelName, + levelValues[0]); + } else { + level = LevelFactory.getInstance().getLevel(levelName, 0.0); + } + } catch (CommunicationException e) { + logger.error(e.getLocalizedMessage(), e); } - } catch (CommunicationException e) { - logger.error(e.getLocalizedMessage(), e); - } - if (level == null) { - logger.warn("Unable to query D2D parms, ParmID " + id - + " does not map to a level"); + if (level == null) { + logger.warn("Unable to query D2D parms, ParmID " + id + + " does not map to a level"); return new TreeMap(); - } + } SQLQuery modelQuery = s.createSQLQuery(SQL_D2D_GRID_PARM_QUERY); modelQuery.setLong("level_id", level.getId()); DatabaseID dbId = id.getDbId(); - try { - IFPServerConfig config = IFPServerConfigManager - .getServerConfig(dbId.getSiteId()); + try { + IFPServerConfig config = IFPServerConfigManager + .getServerConfig(dbId.getSiteId()); modelQuery.setString(GridInfoConstants.DATASET_ID, config.d2dModelNameMapping(dbId.getModelName())); - } catch (GfeConfigurationException e) { - throw new DataAccessLayerException( - "Error occurred looking up model name mapping", e); - } + } catch (GfeConfigurationException e) { + throw new DataAccessLayerException( + "Error occurred looking up model name mapping", e); + } String abbreviation = null; try { @@ -793,38 +795,38 @@ public class GFEDao extends DefaultPluginDao { } catch (MultipleMappingException e) { statusHandler.handle(Priority.WARN, e.getLocalizedMessage(), e); abbreviation = e.getArbitraryMapping(); - } + } - abbreviation = abbreviation.toLowerCase(); + abbreviation = abbreviation.toLowerCase(); modelQuery.setString("abbrev", abbreviation); modelQuery.setString("hourAbbrev", abbreviation + "%hr"); List results = modelQuery.list(); Integer modelId = null; - if (results.size() == 0) { + if (results.size() == 0) { return new TreeMap(); - } else if (results.size() > 1) { - // hours matched, take hour with least number that matches exact - // param - Pattern p = Pattern.compile("^" + abbreviation + "(\\d+)hr$"); - int lowestHr = -1; + } else if (results.size() > 1) { + // hours matched, take hour with least number that matches exact + // param + Pattern p = Pattern.compile("^" + abbreviation + "(\\d+)hr$"); + int lowestHr = -1; for (Object[] rows : (List) results) { String param = ((String) rows[0]).toLowerCase(); - if (param.equals(abbreviation) && (lowestHr < 0)) { + if (param.equals(abbreviation) && (lowestHr < 0)) { modelId = (Integer) rows[1]; - } else { - Matcher matcher = p.matcher(param); - if (matcher.matches()) { - int hr = Integer.parseInt(matcher.group(1)); - if ((lowestHr < 0) || (hr < lowestHr)) { + } else { + Matcher matcher = p.matcher(param); + if (matcher.matches()) { + int hr = Integer.parseInt(matcher.group(1)); + if ((lowestHr < 0) || (hr < lowestHr)) { modelId = (Integer) rows[1]; - lowestHr = hr; + lowestHr = hr; + } } } } - } - } else { + } else { modelId = (Integer) ((Object[]) results.get(0))[1]; - } + } Query timeQuery = s.createQuery(HQL_D2D_GRID_TIME_QUERY); timeQuery.setInteger("info_id", modelId); @@ -832,7 +834,7 @@ public class GFEDao extends DefaultPluginDao { List timeResults = timeQuery.list(); if (timeResults.isEmpty()) { return new TreeMap(); - } + } SortedMap dataTimes = new TreeMap(); for (Object[] rows : timeResults) { @@ -848,7 +850,7 @@ public class GFEDao extends DefaultPluginDao { try { s = getHibernateTemplate().getSessionFactory().openSession(); - if (id.getParmName().equalsIgnoreCase("wind")) { + if (id.getParmName().equalsIgnoreCase("wind")) { String idString = id.toString(); Matcher idWindMatcher = WIND_PATTERN.matcher(idString); @@ -858,53 +860,53 @@ public class GFEDao extends DefaultPluginDao { List uTimeList = new ArrayList( results.size()); for (DataTime o : results.keySet()) { - uTimeList.add(new TimeRange(o.getValidPeriod().getStart(), - 3600 * 1000)); - } + uTimeList.add(new TimeRange(o.getValidPeriod().getStart(), + 3600 * 1000)); + } ParmID vWindId = new ParmID(idWindMatcher.replaceAll("vW")); results = queryByD2DParmId(vWindId, s); Set vTimeList = new HashSet( results.size(), 1); for (DataTime o : results.keySet()) { - vTimeList.add(new TimeRange(o.getValidPeriod().getStart(), - 3600 * 1000)); - } + vTimeList.add(new TimeRange(o.getValidPeriod().getStart(), + 3600 * 1000)); + } - for (TimeRange tr : uTimeList) { - if (vTimeList.contains(tr)) { - timeList.add(new TimeRange(tr.getStart(), tr.getStart())); - } + for (TimeRange tr : uTimeList) { + if (vTimeList.contains(tr)) { + timeList.add(new TimeRange(tr.getStart(), tr.getStart())); } + } - if (!timeList.isEmpty()) { - return timeList; - } + if (!timeList.isEmpty()) { + return timeList; + } ParmID sWindId = new ParmID(idWindMatcher.replaceAll("ws")); results = queryByD2DParmId(sWindId, s); List sTimeList = new ArrayList( results.size()); for (DataTime o : results.keySet()) { - sTimeList.add(new TimeRange(o.getValidPeriod().getStart(), - 3600 * 1000)); - } + sTimeList.add(new TimeRange(o.getValidPeriod().getStart(), + 3600 * 1000)); + } ParmID dWindId = new ParmID(idWindMatcher.replaceAll("wd")); results = queryByD2DParmId(dWindId, s); Set dTimeList = new HashSet( results.size(), 1); for (DataTime o : results.keySet()) { - dTimeList.add(new TimeRange(o.getValidPeriod().getStart(), - 3600 * 1000)); - } + dTimeList.add(new TimeRange(o.getValidPeriod().getStart(), + 3600 * 1000)); + } - for (TimeRange tr : sTimeList) { - if (dTimeList.contains(tr)) { - timeList.add(new TimeRange(tr.getStart(), tr.getStart())); - } + for (TimeRange tr : sTimeList) { + if (dTimeList.contains(tr)) { + timeList.add(new TimeRange(tr.getStart(), tr.getStart())); } - } else { + } + } else { SortedMap results = queryByD2DParmId(id, s); if (isMos(id)) { for (DataTime o : results.keySet()) { @@ -913,10 +915,10 @@ public class GFEDao extends DefaultPluginDao { } } else { for (DataTime o : results.keySet()) { - timeList.add(o.getValidPeriod()); - } + timeList.add(o.getValidPeriod()); } } + } } finally { if (s != null) { try { diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/notify/GfeIngestNotificationFilter.java b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/notify/GfeIngestNotificationFilter.java index 3a6e179a37..b7347a811b 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/notify/GfeIngestNotificationFilter.java +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/notify/GfeIngestNotificationFilter.java @@ -21,7 +21,6 @@ package com.raytheon.edex.plugin.gfe.server.notify; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -54,10 +53,13 @@ import com.raytheon.uf.common.dataplugin.gfe.server.notify.GridUpdateNotificatio import com.raytheon.uf.common.dataplugin.grid.GridRecord; import com.raytheon.uf.common.dataplugin.satellite.SatelliteRecord; import com.raytheon.uf.common.message.WsId; +import com.raytheon.uf.common.parameter.mapping.ParameterMapper; import com.raytheon.uf.common.serialization.SerializationUtil; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.TimeRange; +import com.raytheon.uf.common.util.mapping.MultipleMappingException; import com.raytheon.uf.edex.core.EDEXUtil; /** @@ -71,6 +73,8 @@ import com.raytheon.uf.edex.core.EDEXUtil; * ------------ ---------- ----------- -------------------------- * Aug 12, 2011 dgilling Initial creation * Sep 19, 2012 jdynina DR 15442 fix + * Jan 18, 2013 #1504 randerso Moved D2D to GFE parameter name translation from + * D2DParmIdCache to GfeIngestNotificationFilter * * * @@ -80,7 +84,7 @@ import com.raytheon.uf.edex.core.EDEXUtil; public class GfeIngestNotificationFilter { - private static final transient IUFStatusHandler handler = UFStatus + private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(GfeIngestNotificationFilter.class); private SmartInitQueue smartInitQueue = null; @@ -106,8 +110,7 @@ public class GfeIngestNotificationFilter { } } - public void filterGridRecords(List gridRecords, - Date arrivalTime) + public void filterGridRecords(List gridRecords, Date arrivalTime) throws Exception { StringBuilder initNameBuilder = new StringBuilder(120); @@ -126,7 +129,8 @@ public class GfeIngestNotificationFilter { try { config = IFPServerConfigManager.getServerConfig(site); } catch (GfeConfigurationException e) { - handler.error("Unable to retrieve site config for " + site, e); + statusHandler.error("Unable to retrieve site config for " + + site, e); continue; } for (GridRecord grid : gridRecords) { @@ -152,24 +156,33 @@ public class GfeIngestNotificationFilter { } String abbrev = grid.getParameter().getAbbreviation(); - String level = GridTranslator.getShortLevelName( -grid + String gfeParmName = null; + try { + gfeParmName = ParameterMapper.getInstance() + .lookupAlias(abbrev, "gfeParamName"); + } catch (MultipleMappingException e) { + statusHandler.handle(Priority.WARN, + e.getLocalizedMessage(), e); + gfeParmName = e.getArbitraryMapping(); + } + + String level = GridTranslator.getShortLevelName(grid .getLevel().getMasterLevel().getName(), grid .getLevel().getLevelonevalue(), grid.getLevel() .getLeveltwovalue()); - ParmID parmID = new ParmID(abbrev, dbId, level); + ParmID parmID = new ParmID(gfeParmName, dbId, level); - if (!gridInv.containsKey(parmID)) { - gridInv.put(parmID, new ArrayList()); + List trs = gridInv.get(parmID); + if (trs == null) { + trs = new ArrayList(); + gridInv.put(parmID, trs); } TimeRange validPeriod = grid.getDataTime().getValidPeriod(); if (validPeriod.getDuration() > 0) { - gridInv.get(parmID).add(validPeriod); + trs.add(validPeriod); } else { - gridInv.get(parmID).add( - new TimeRange(grid.getDataTime() - .getValidPeriod().getStart(), - 3600 * 1000)); + trs.add(new TimeRange(grid.getDataTime() + .getValidPeriod().getStart(), 3600 * 1000)); } List siteInitModules = config.initModels(gfeModel); @@ -201,31 +214,29 @@ grid // DR 15442 - move last for loop out of the for loop at line 110 for (ParmID parmId : gridInv.keySet()) { - Map> hist = new HashMap>(); try { List trs = gridInv.get(parmId); - Collections.sort(trs); for (TimeRange time : trs) { List histList = new ArrayList(); histList.add(new GridDataHistory( - GridDataHistory.OriginType.INITIALIZED, - parmId, time, null, (WsId) null)); + GridDataHistory.OriginType.INITIALIZED, parmId, + time, null, (WsId) null)); + Map> hist = new HashMap>(); hist.put(time, histList); + guns.add(new GridUpdateNotification(parmId, time, hist, + null, parmId.getDbId().getSiteId())); } - guns.add(new GridUpdateNotification(parmId, - new TimeRange(trs.get(0).getStart(), trs.get( - trs.size() - 1).getEnd()), hist, null, - parmId.getDbId().getSiteId())); } catch (Exception e) { - handler.error("Unable to retrieve grid history for " + statusHandler.error("Unable to retrieve grid history for " + parmId.toString(), e); } } - + try { sendNotifications(guns); } catch (Exception e) { - handler.error("Unable to send grib ingest notifications", e); + statusHandler.error("Unable to send grib ingest notifications", + e); } smartInitQueue.addInits(inits.values()); @@ -233,8 +244,7 @@ grid } public void filterSatelliteRecords(List records, - Date arrivalTime) - throws Exception { + Date arrivalTime) throws Exception { StringBuilder initNameBuilder = new StringBuilder(120); Set activeSites = GFESiteActivation.getInstance() @@ -249,7 +259,8 @@ grid try { config = IFPServerConfigManager.getServerConfig(site); } catch (GfeConfigurationException e) { - handler.error("Error retrieiving site config for " + site, e); + statusHandler.error( + "Error retrieiving site config for " + site, e); continue; } @@ -298,8 +309,8 @@ grid try { sendNotifications(guns); } catch (Exception e) { - handler.error("Unable to send satellite ingest notifications", - e); + statusHandler.error( + "Unable to send satellite ingest notifications", e); } smartInitQueue.addInits(inits.values()); diff --git a/edexOsgi/com.raytheon.edex.plugin.grib/GribDecoder.py b/edexOsgi/com.raytheon.edex.plugin.grib/GribDecoder.py index 47d00f2970..9da78b1cab 100644 --- a/edexOsgi/com.raytheon.edex.plugin.grib/GribDecoder.py +++ b/edexOsgi/com.raytheon.edex.plugin.grib/GribDecoder.py @@ -593,19 +593,19 @@ class GribDecoder(): # Special case handling for specific PDS Templates if pdsTemplateNumber == 1 or pdsTemplateNumber == 11: - typeEnsemble = Integer(pdsTemplate[15]) - perturbationNumber = Integer(pdsTemplate[16]) + typeEnsemble = Integer(pdsTemplate[15]).intValue() + perturbationNumber = Integer(pdsTemplate[16]).intValue() pdsFields['numForecasts'] = Integer(pdsTemplate[17]) if(typeEnsemble == 0): - pdsFields['ensembleId'] = "ctlh" + perturbationNumber; + pdsFields['ensembleId'] = "ctlh" + str(perturbationNumber); elif(typeEnsemble == 1): - pdsFields['ensembleId'] = "ctll" + perturbationNumber; + pdsFields['ensembleId'] = "ctll" + str(perturbationNumber); elif(typeEnsemble == 2): - pdsFields['ensembleId'] = "n" + perturbationNumber; + pdsFields['ensembleId'] = "n" + str(perturbationNumber); elif(typeEnsemble == 3): - pdsFields['ensembleId'] = "p" + perturbationNumber; + pdsFields['ensembleId'] = "p" + str(perturbationNumber); else: - pdsFields['ensembleId'] = typeEnsemble + "." + perturbationNumber; + pdsFields['ensembleId'] = str(typeEnsemble) + "." + str(perturbationNumber); if pdsTemplateNumber == 11: endTime = GregorianCalendar(pdsTemplate[18], pdsTemplate[19] - 1, pdsTemplate[20], pdsTemplate[21], pdsTemplate[22], pdsTemplate[23]) diff --git a/edexOsgi/com.raytheon.edex.plugin.radar/src/com/raytheon/edex/plugin/radar/RadarDecoder.java b/edexOsgi/com.raytheon.edex.plugin.radar/src/com/raytheon/edex/plugin/radar/RadarDecoder.java index 55dcefe7b6..c7f7bba8f4 100644 --- a/edexOsgi/com.raytheon.edex.plugin.radar/src/com/raytheon/edex/plugin/radar/RadarDecoder.java +++ b/edexOsgi/com.raytheon.edex.plugin.radar/src/com/raytheon/edex/plugin/radar/RadarDecoder.java @@ -22,6 +22,7 @@ package com.raytheon.edex.plugin.radar; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.HashMap; import java.util.List; @@ -95,6 +96,30 @@ public class RadarDecoder extends AbstractDecoder { private static final IUFStatusHandler theHandler = UFStatus .getHandler(RadarDecoder.class); + // radar server sends messages from edex to cave, handle that here + private final String EDEX = "EDEX"; + + /* + * Constants having to do with certain products + */ + + private final List LEVEL_TWO_IDENTS = new ArrayList( + Arrays.asList("ARCH", "AR2V")); + + private final String NOUS = "NOUS"; + + private final int USER_ALERT_MESSAGE = 73; + + private final int FREE_TEXT_MESSAGE = 75; + + private final int USER_SELECT_ACCUM = 173; + + private final int CLUTTER_FILTER_CONTROL = 34; + + /* + * End constants + */ + private String traceId = ""; private RadarInfoDict infoDict; @@ -103,9 +128,6 @@ public class RadarDecoder extends AbstractDecoder { private final String RADAR = "RADAR"; - // radar server sends messages from edex to cave, handle that here - private final String EDEX = "EDEX"; - public RadarDecoder() throws DecoderException { String dir = ""; @@ -146,11 +168,11 @@ public class RadarDecoder extends AbstractDecoder { String arch = new String(messageData, 0, 4); try { // for level2 data, this does not happen very often - if ("ARCH".equals(arch) || "AR2V".equals(arch)) { + if (LEVEL_TWO_IDENTS.contains(arch)) { decodeLevelTwoData(messageData, recordList); } // for free text messages, which come in with the following wmo - else if ("NOUS".equals(arch)) { + else if (NOUS.equals(arch)) { decodeFreeTextMessage(messageData, headers); } else { if (headers.get("header") != null) { @@ -208,24 +230,19 @@ public class RadarDecoder extends AbstractDecoder { // -- some product specific decode functionality -- // the general status message product - if (l3Radar.getMessageCode() == 2) { + if (l3Radar.getMessageCode() == l3Radar.GSM_MESSAGE) { record.setGsmMessage(l3Radar.getGsmBlock().getMessage()); record.setPrimaryElevationAngle(0.0); record.setTrueElevationAngle(0.0f); handleRadarStatus(record); } // the product request response product - else if (l3Radar.getMessageCode() == 3) { + else if (l3Radar.getMessageCode() == l3Radar.PRODUCT_REQUEST_RESPONSE_MESSAGE) { // do nothing with this, it will get excessive otherwise! - // EDEXUtil.sendMessageAlertViz(Priority.VERBOSE, - // RadarConstants.PLUGIN_ID, EDEX, RADAR, - // record.getIcao() - // + ": Response Request Message Received", - // l3Radar.getRequestResponseMessage(), null); return new PluginDataObject[0]; } // the user alert message product - else if (l3Radar.getMessageCode() == 73) { + else if (l3Radar.getMessageCode() == USER_ALERT_MESSAGE) { EDEXUtil.sendMessageAlertViz(Priority.VERBOSE, RadarConstants.PLUGIN_ID, EDEX, RADAR, record.getIcao() + ": User Alert Message Received", @@ -233,21 +250,19 @@ public class RadarDecoder extends AbstractDecoder { return new PluginDataObject[0]; } // handle the other case for free text message - else if (l3Radar.getMessageCode() == 75) { + else if (l3Radar.getMessageCode() == FREE_TEXT_MESSAGE) { // product already stored to the text database, so just send // to alertviz - EDEXUtil.sendMessageAlertViz( - Priority.SIGNIFICANT, - RadarConstants.PLUGIN_ID, - EDEX, - RADAR, + String formattedMsg = l3Radar.getTabularBlock().toString() + .replace("Page 1\n\t", ""); + EDEXUtil.sendMessageAlertViz(Priority.SIGNIFICANT, + RadarConstants.PLUGIN_ID, EDEX, RADAR, record.getIcao() + ": Free Text Message Received", - l3Radar.getTabularBlock().toString() - .replace("Page 1\n\t", ""), null); + formattedMsg, null); return new PluginDataObject[0]; } // the alert adaptations parameters product - else if (l3Radar.getMessageCode() == 6) { + else if (l3Radar.getMessageCode() == l3Radar.ALERT_ADAPTATION_PARAMETERS) { record.setAapMessage(l3Radar.getAapMessage()); record.setPrimaryElevationAngle(0.0); record.setTrueElevationAngle(0.0f); @@ -261,7 +276,7 @@ public class RadarDecoder extends AbstractDecoder { l3Radar.getAapMessage().toString(), null); } // the alert message product - else if (l3Radar.getMessageCode() == 9) { + else if (l3Radar.getMessageCode() == l3Radar.ALERT_MESSAGE) { record.setPrimaryElevationAngle(0.0); record.setTrueElevationAngle(0.0f); AlertMessage msg = l3Radar.getAlertMessage(); @@ -291,6 +306,8 @@ public class RadarDecoder extends AbstractDecoder { record.setOperationalMode(l3Radar.getOperationalMode()); record.setElevationNumber(l3Radar.getElevationNumber()); + // some products don't have real elevation angles, 0 is a + // default value if (record.getElevationNumber() == 0) { record.setTrueElevationAngle(0f); } else { @@ -320,13 +337,13 @@ public class RadarDecoder extends AbstractDecoder { } // code specific for clutter filter control - if (record.getProductCode() == 34) { + if (record.getProductCode() == CLUTTER_FILTER_CONTROL) { int segment = ((int) (Math.log(l3Radar .getProductDependentValue(0)) / Math.log(2))); record.setLayer((double) segment); } // code specific for user select accum - else if (record.getProductCode() == 173) { + else if (record.getProductCode() == USER_SELECT_ACCUM) { int layer = 0; // Default to zero int timeSpan = l3Radar.getProductDependentValue(1); @@ -491,7 +508,8 @@ public class RadarDecoder extends AbstractDecoder { String[] splits = temp.split(" "); AFOSProductId afos = new AFOSProductId( - RadarTextProductUtil.createAfosId(75, splits[1].substring(1))); + RadarTextProductUtil.createAfosId(FREE_TEXT_MESSAGE, + splits[1].substring(1))); // store the product to the text database Calendar cal = (TimeTools.allowArchive() ? header.getHeaderDate() @@ -510,7 +528,9 @@ public class RadarDecoder extends AbstractDecoder { record.setPluginName("radar"); record.constructDataURI(); record.setInsertTime(TimeTools.getSystemCalendar()); - if (record.getProductCode() == 2) { + // for GSM, we want all the messages as they have the possibility of + // being different + if (record.getProductCode() == Level3BaseRadar.GSM_MESSAGE) { record.setOverwriteAllowed(true); } else { record.setOverwriteAllowed(false); @@ -669,7 +689,8 @@ public class RadarDecoder extends AbstractDecoder { } } catch (Exception e) { - e.printStackTrace(); + theHandler.handle(Priority.ERROR, + "Unable to query for the radar station", e); } return station; diff --git a/edexOsgi/com.raytheon.edex.plugin.radar/src/com/raytheon/edex/plugin/radar/level3/Level3BaseRadar.java b/edexOsgi/com.raytheon.edex.plugin.radar/src/com/raytheon/edex/plugin/radar/level3/Level3BaseRadar.java index 74311c15fa..96234440ff 100644 --- a/edexOsgi/com.raytheon.edex.plugin.radar/src/com/raytheon/edex/plugin/radar/level3/Level3BaseRadar.java +++ b/edexOsgi/com.raytheon.edex.plugin.radar/src/com/raytheon/edex/plugin/radar/level3/Level3BaseRadar.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.InputStream; import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.List; @@ -178,6 +179,21 @@ public class Level3BaseRadar { private RadarInfoDict dict = null; + private final List SPECIAL_PRODS = new ArrayList( + Arrays.asList(73, 62, 75, 77, 82)); + + public static final int GSM_MESSAGE = 2; + + public final int PRODUCT_REQUEST_RESPONSE_MESSAGE = 3; + + public final int ALERT_ADAPTATION_PARAMETERS = 6; + + public final int PRODUCT_LIST = 8; + + public final int RADAR_CODED_MESSAGE = 74; + + public final int ALERT_MESSAGE = 9; + /** * This baseradar constructor accepts a radar file contained within a * java.io.File object. @@ -251,16 +267,16 @@ public class Level3BaseRadar { this.parseRadarHeader(); // Handle the message contents - if (this.theMessageCode == 6) { + if (this.theMessageCode == ALERT_ADAPTATION_PARAMETERS) { // Alert Adaptation Params this.parseAAP(); - } else if (this.theMessageCode == 3) { + } else if (this.theMessageCode == PRODUCT_REQUEST_RESPONSE_MESSAGE) { this.parseRequestResponse(); - } else if (this.theMessageCode == 8) { + } else if (this.theMessageCode == PRODUCT_LIST) { this.parseProductList(headers); - } else if (this.theMessageCode == 2) { + } else if (this.theMessageCode == GSM_MESSAGE) { this.parseGeneralStatusMessage(); - } else if (this.theMessageCode == 9) { + } else if (this.theMessageCode == ALERT_MESSAGE) { this.parseAlertMessage(headers); } else { this.parseRadarMessage(headers); @@ -593,8 +609,13 @@ public class Level3BaseRadar { byte[] buf = new byte[lineLen]; theRadarData.readFully(buf); String temp = new String(buf); + // PSM is found in all products that have useful Site Adaptation + // Parameters. For this reason, we are dropping every other set of + // Site Adaptation Parameters. if (temp.contains("PSM")) { temp = temp.substring(temp.indexOf("PSM")); + } else { + temp = ""; } return temp; } else { @@ -795,15 +816,13 @@ public class Level3BaseRadar { } } - if (this.theProductCode == 73 || this.theProductCode == 62 - || this.theProductCode == 75 || this.theProductCode == 77 - || this.theProductCode == 82) { + if (SPECIAL_PRODS.contains(this.theProductCode)) { // The first offset will be to the tabular block tabularBlock = readStandaloneTabular(symbologyBlockOffset); // The second offset will be to a symbology block with no header symbologyBlock = readPseudoSymbologyBlock(graphicBlockOffset); // tabularBlock.getPages().toString(); - } else if (this.theProductCode == 74) { + } else if (this.theProductCode == RADAR_CODED_MESSAGE) { tabularBlock = readRadarCodedMessage(symbologyBlockOffset); } else { symbologyBlock = readSymbologyBlock(symbologyBlockOffset); diff --git a/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/AbstractPrivilegedLocalizationRequestHandler.java b/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/AbstractPrivilegedLocalizationRequestHandler.java index e5709ca09a..d8cadca0bb 100644 --- a/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/AbstractPrivilegedLocalizationRequestHandler.java +++ b/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/AbstractPrivilegedLocalizationRequestHandler.java @@ -19,13 +19,16 @@ **/ package com.raytheon.edex.services; -import java.io.File; +import java.util.HashSet; +import java.util.Set; import com.raytheon.uf.common.auth.exception.AuthorizationException; import com.raytheon.uf.common.auth.req.AbstractPrivilegedRequest; import com.raytheon.uf.common.auth.user.IUser; +import com.raytheon.uf.common.localization.IPathManager; import com.raytheon.uf.common.localization.LocalizationContext; import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel; +import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType; import com.raytheon.uf.edex.auth.AuthManager; import com.raytheon.uf.edex.auth.AuthManagerFactory; import com.raytheon.uf.edex.auth.req.AbstractPrivilegedRequestHandler; @@ -51,87 +54,85 @@ import com.raytheon.uf.edex.auth.roles.IRoleStorage; */ public abstract class AbstractPrivilegedLocalizationRequestHandler extends AbstractPrivilegedRequestHandler { - + + private static final String PATH_SEPARATOR = IPathManager.SEPARATOR; + + private static final String SEPARATOR = "."; + + private static final String ROLE_PREFIX = "com.raytheon.localization"; + private static final String APPLICATION = "Localization"; protected AuthorizationResponse getAuthorizationResponse(IUser user, - LocalizationContext context, LocalizationLevel level, - String fileName, String myContextName) + LocalizationContext context, String fileName, String myContextName) throws AuthorizationException { String contextName = context.getContextName(); - + LocalizationLevel level = context.getLocalizationLevel(); + LocalizationType type = context.getLocalizationType(); + boolean contextsMatch = (myContextName != null && myContextName + .equals(contextName)); if (level.isSystemLevel()) { return new AuthorizationResponse(false, "Modification to system level configuration is prohibited."); - } else if (myContextName != null - && myContextName.equals(contextName) - && (context.getLocalizationLevel() == LocalizationLevel.USER || context - .getLocalizationLevel() == LocalizationLevel.WORKSTATION)) { - // If context names match and we are user or workstation file - // request, that is ok + } else if (level == LocalizationLevel.USER && contextsMatch) { + // Don't prevent users from modifying own files return new AuthorizationResponse(true); } AuthManager manager = AuthManagerFactory.getInstance().getManager(); IRoleStorage roleStorage = manager.getRoleStorage(); - String roleId = ""; + String[] permissions = roleStorage + .getAllDefinedPermissions(APPLICATION); + Set definedPermissions = new HashSet(); + for (String permission : permissions) { + definedPermissions.add(permission.toLowerCase()); + } + String absoluteRoleId = buildRoleId(level, type, contextName, fileName); // First round check com.raytheon.localization.level // Second round check com.raytheon.localization.level.name for (int i = 0; i < 2; ++i) { - roleId = "com.raytheon.localization." - + context.getLocalizationLevel().name() - + "/" + context.getLocalizationType().name(); - if (i > 0) { - if (contextName != null) { - roleId += "." + contextName; - } else { - // We already checked this case - break; - } - } - + String contextNameToUse = i > 0 ? contextName : null; + String roleId = buildRoleId(level, type, contextNameToUse, fileName); + // check most specific to least specific // com.raytheon.localization..(.)/type/path/name/ - int minIndex = roleId.length(); - roleId += File.separator + fileName; - int index = roleId.length(); - - while (index > minIndex) { - roleId = roleId.substring(0, index); - - if (roleStorage.isAuthorized(roleId, user.uniqueId().toString(), APPLICATION)) { + int minLength = roleId.length() - fileName.length() - 1; + do { + if (roleStorage.isAuthorized(roleId, + user.uniqueId().toString(), APPLICATION)) { return new AuthorizationResponse(true); + } else if (definedPermissions.contains(roleId.toLowerCase())) { + // User not authorized and this roleId is explicitly defined + return notAuthorized(user, absoluteRoleId); } - index = roleId.lastIndexOf(File.separator, index - 1); - } - - roleId = "com.raytheon.localization." - + context.getLocalizationLevel().name(); - if (i > 0) { - if (contextName != null) { - roleId += "." + contextName; - } else { - // We already checked this case - break; - } - } - - // com.raytheon.localization..() - if (roleStorage.isAuthorized(roleId, user.uniqueId().toString(), APPLICATION)) { - return new AuthorizationResponse(true); - } - - // com.raytheon.localization..(.)/type - roleId += "/" + context.getLocalizationType().name(); - - if (roleStorage.isAuthorized(roleId, user.uniqueId().toString(), APPLICATION)) { - return new AuthorizationResponse(true); - } - + roleId = roleId.substring(0, + roleId.lastIndexOf(PATH_SEPARATOR, roleId.length())); + } while (roleId.length() >= minLength); } - + + if (level == LocalizationLevel.WORKSTATION && contextsMatch) { + // If no rule found and user is attempting to modify workstation + // they are using, default to allow + return new AuthorizationResponse(true); + } + + return notAuthorized(user, absoluteRoleId); + } + + private String buildRoleId(LocalizationLevel level, LocalizationType type, + String contextName, String fileName) { + String roleId = ROLE_PREFIX + SEPARATOR + level; + if (contextName != null) { + roleId += SEPARATOR + contextName; + } + roleId += PATH_SEPARATOR + type; + roleId += PATH_SEPARATOR + fileName; + return roleId; + } + + private AuthorizationResponse notAuthorized(IUser user, String roleId) { return new AuthorizationResponse(false, "User, " + user.uniqueId() + ", is not authorized to perform request needing role: " + roleId); diff --git a/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/LocalizationStreamHandler.java b/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/LocalizationStreamHandler.java index 08d8319ffa..0182e96717 100644 --- a/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/LocalizationStreamHandler.java +++ b/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/LocalizationStreamHandler.java @@ -294,9 +294,8 @@ public class LocalizationStreamHandler return new AuthorizationResponse(true); } else if (request instanceof LocalizationStreamPutRequest) { LocalizationContext context = request.getContext(); - LocalizationLevel level = context.getLocalizationLevel(); String fileName = request.getFileName(); - return getAuthorizationResponse(user, context, level, fileName, + return getAuthorizationResponse(user, context, fileName, request.getMyContextName()); } return new AuthorizationResponse(true); diff --git a/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/PrivilegedUtilityHandler.java b/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/PrivilegedUtilityHandler.java index a4b9df6d99..13fedf2ea9 100644 --- a/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/PrivilegedUtilityHandler.java +++ b/edexOsgi/com.raytheon.edex.utilitysrv/src/com/raytheon/edex/services/PrivilegedUtilityHandler.java @@ -6,7 +6,6 @@ import java.util.List; import com.raytheon.uf.common.auth.exception.AuthorizationException; import com.raytheon.uf.common.auth.user.IUser; import com.raytheon.uf.common.localization.LocalizationContext; -import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel; import com.raytheon.uf.common.localization.msgs.AbstractPrivilegedUtilityCommand; import com.raytheon.uf.common.localization.msgs.AbstractUtilityResponse; import com.raytheon.uf.common.localization.msgs.DeleteUtilityCommand; @@ -73,10 +72,9 @@ public class PrivilegedUtilityHandler AbstractPrivilegedUtilityCommand[] commands = request.getCommands(); for (AbstractPrivilegedUtilityCommand abstractUtilityCommand : commands) { LocalizationContext context = abstractUtilityCommand.getContext(); - LocalizationLevel level = context.getLocalizationLevel(); String filename = abstractUtilityCommand.getFilename(); AuthorizationResponse resp = getAuthorizationResponse(user, - context, level, filename, + context, filename, abstractUtilityCommand.getMyContextName()); if (resp.isAuthorized() == false) { // If we are not authorized for any of the commands, break early diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/src/com/raytheon/uf/common/datadelivery/bandwidth/data/BandwidthGraphData.java b/edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/src/com/raytheon/uf/common/datadelivery/bandwidth/data/BandwidthGraphData.java index 0c4be4b3cd..7d045becea 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/src/com/raytheon/uf/common/datadelivery/bandwidth/data/BandwidthGraphData.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/src/com/raytheon/uf/common/datadelivery/bandwidth/data/BandwidthGraphData.java @@ -27,23 +27,25 @@ import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; /** * Response object for the GraphDataRequest. - * + * *

- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Nov 25, 2012    1269    lvenable    Initial creation.
  * Dec 06, 2012    1397    djohnson    Add dynamic serialize class annotation.
- *
+ * Jan 25, 2013   1528     djohnson    Subscription priority is now an enum.
+ * 
  * 
- * + * * @author lvenable * @version 1.0 */ @@ -55,7 +57,7 @@ public class BandwidthGraphData { /** Subscription Name -> Subscription Priority */ @DynamicSerializeElement - private Map priorityMap; + private Map priorityMap; /** Bin duration in minutes */ @DynamicSerializeElement @@ -81,7 +83,7 @@ public class BandwidthGraphData { public BandwidthGraphData(int binTimeMins) { this.binTimeInMins = binTimeMins; dataMap = new HashMap>(); - priorityMap = new HashMap(); + priorityMap = new HashMap(); } /** @@ -102,7 +104,7 @@ public class BandwidthGraphData { /** * @return the priorityMap */ - public Map getPriorityMap() { + public Map getPriorityMap() { return priorityMap; } @@ -110,7 +112,7 @@ public class BandwidthGraphData { * @param priorityMap * the priorityMap to set */ - public void setPriorityMap(Map priorityMap) { + public void setPriorityMap(Map priorityMap) { this.priorityMap = priorityMap; } @@ -145,7 +147,8 @@ public class BandwidthGraphData { * @param priority * @param dataArray */ - public void addGraphDataArray(String subscriptionName, int priority, + public void addGraphDataArray(String subscriptionName, + SubscriptionPriority priority, List dataArray) { dataMap.put(subscriptionName, dataArray); priorityMap.put(subscriptionName, priority); @@ -206,14 +209,15 @@ public class BandwidthGraphData { * The subscription name. * @return The priority number. */ - public int getPriority(String subscriptionName) { + public SubscriptionPriority getPriority(String subscriptionName) { if (priorityMap.containsKey(subscriptionName)) { return priorityMap.get(subscriptionName); } - // This should never occur. A low priority number is being return rather - // than a null. - return 99; + // This should never occur. + throw new IllegalArgumentException( + "Unable to find a priority for subscription [" + + subscriptionName + "]"); } /** diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/utility/common_static/base/datadelivery/systemManagement/rules/latencyRules.xml b/edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/utility/common_static/base/datadelivery/systemManagement/rules/latencyRules.xml index ab09f88dfb..f686a0eda8 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/utility/common_static/base/datadelivery/systemManagement/rules/latencyRules.xml +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/utility/common_static/base/datadelivery/systemManagement/rules/latencyRules.xml @@ -1,19 +1,19 @@ - + Dataset Frequency Hourly-Products <= Hrs 1 40 - - + + Dataset Frequency MultiHour-Products > Hrs 1 115 - + diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rtofsLevelLookup.xml b/edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/utility/common_static/base/datadelivery/systemManagement/rules/priorityRules.xml similarity index 52% rename from edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rtofsLevelLookup.xml rename to edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/utility/common_static/base/datadelivery/systemManagement/rules/priorityRules.xml index 1cb435de22..36fe07252c 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rtofsLevelLookup.xml +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.bandwidth/utility/common_static/base/datadelivery/systemManagement/rules/priorityRules.xml @@ -1,4 +1,4 @@ - - 1.0 - \ No newline at end of file + + + diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.datadelivery.event/META-INF/MANIFEST.MF index 772a6e8dbc..2ffd2f8400 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.event/META-INF/MANIFEST.MF @@ -17,4 +17,5 @@ Require-Bundle: javax.persistence;bundle-version="1.0.0", com.raytheon.uf.common.event;bundle-version="1.0.0", com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174", com.raytheon.uf.common.time;bundle-version="1.12.1174", - com.raytheon.uf.common.stats;bundle-version="1.0.0" + com.raytheon.uf.common.stats;bundle-version="1.0.0", + com.raytheon.uf.common.registry.ebxml;bundle-version="1.0.0" diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/META-INF/MANIFEST.MF index e5cd0a4626..9a73f1811e 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/META-INF/MANIFEST.MF @@ -23,7 +23,8 @@ Require-Bundle: com.raytheon.uf.common.registry.schemas.ebxml;bundle-version="1. com.raytheon.uf.common.gridcoverage;bundle-version="1.0.0", com.raytheon.uf.common.dataplugin;bundle-version="1.12.1174", com.raytheon.uf.common.geospatial;bundle-version="1.12.1174", - javax.measure;bundle-version="1.0.0" + javax.measure;bundle-version="1.0.0", + com.raytheon.uf.common.datadelivery.request;bundle-version="1.0.0" Export-Package: com.raytheon.uf.common.datadelivery.registry, com.raytheon.uf.common.datadelivery.registry.ebxml, com.raytheon.uf.common.datadelivery.registry.handlers diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/DataLevelType.java b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/DataLevelType.java index 000eb39f8e..24d3ed4b42 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/DataLevelType.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/DataLevelType.java @@ -31,6 +31,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; * Code clean up. * Set 06, 2012 1121 mpduff Added a unique key. * Nov 19, 2012 1166 djohnson Clean up JAXB representation of registry objects. + * Jan 24, 2013 1527 dhladky Changed 0DEG to FRZ * * * @@ -110,7 +111,7 @@ public class DataLevelType implements ISerializableObject, Serializable { "Cloud Level", 110), SIGL("sigma", "Sigma Level", 111), PVL( "pv", "PV Level", 111), CTL("top", "Top Level", 112), MSL( "mean", "Mean Sea Level", 113), EA("entire", - "Entire Atmosphere (As Single Layer)", 114), ODEG("0c", + "Entire Atmosphere (As Single Layer)", 114), FRZ("0c", "0c isotherm", 115), LCY("low", "Low Cloud Bottom Level", 116), MCY( "middle", "Middle Cloud Level", 117), HCY("high", "High Cloud Level", 118), PBL("planetary", @@ -175,11 +176,8 @@ public class DataLevelType implements ISerializableObject, Serializable { break; } } - - // special case since enums can't start with integers - if (rval == LevelType.ODEG) { - return "0DEG"; - } else if (rval == LevelType.U || rval == LevelType.V) { + + if (rval == LevelType.U || rval == LevelType.V) { return LevelType.MAXW.toString(); } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Ensemble.java b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Ensemble.java index d53cd8625a..3d9047cea0 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Ensemble.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Ensemble.java @@ -1,5 +1,9 @@ package com.raytheon.uf.common.datadelivery.registry; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; @@ -30,67 +34,161 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @DynamicSerialize public class Ensemble implements ISerializableObject { + /** + * names of the various ensemble members + */ + @DynamicSerializeElement + @XmlAttribute + private List members; + + /** + * which members to request. + */ + @DynamicSerializeElement + @XmlAttribute + private List selectedMembers; + public Ensemble() { } - /** - * ensemble models set this - */ - @DynamicSerializeElement - @XmlAttribute - private String name; + public Ensemble(Ensemble other) { + if (other.members != null) { + members = new ArrayList(other.members); + } + if (other.selectedMembers != null) { + selectedMembers = new ArrayList(other.selectedMembers); + } + } + + public List getMembers() { + return members; + } + + public void setMembers(List members) { + this.members = members; + } + + public List getSelectedMembers() { + return selectedMembers; + } + + public void setSelectedMembers(List selectedMembers) { + this.selectedMembers = selectedMembers; + } + + public int getMemberCount() { + if (members == null) { + // if no members are defined then assume a single unnamed member. + return 1; + } else { + return members.size(); + } + } + + public int getSelectedMemberCount() { + if (members == null) { + // if no members are defined then assume a single unnamed member + // which is automatically selected + return 1; + } else if (selectedMembers == null) { + return 0; + } else { + return selectedMembers.size(); + } + } + + public boolean hasSelection() { + return selectedMembers != null && !selectedMembers.isEmpty(); + } /** - * ensemble models set this + * + * Get the range of indices of the selected members, inclusively. This + * method should usually be used after a split operation to guarantee that + * selected ensembles are consecutive + * + * @return a int[2] representing the start and end indices of the ensemble + * members + * @throws IllegalStateException + * if the selected member are non consecutive. */ - @DynamicSerializeElement - @XmlAttribute - private String length; + public int[] getSelectedRange() { + int[] result = new int[2]; + int[] indexes = getSortedIndexes(); + if (indexes == null) { + return result; + } + result[0] = indexes[0]; + result[1] = result[0] - 1; + for (int index : indexes) { + result[1] += 1; + if (result[1] != index) { + throw new IllegalStateException( + "Cannot get selected range for nonconsecutive ensemble members\nMembers " + + members + "\nSelected" + selectedMembers); + } + } + return result; + } /** - * ensemble models set this + * Split this ensemble into multiple Ensembles each with consecutive + * members. Used in cases where multiple ensembles can be requested at once + * if they are consecutive. + * + * @param maxEnsembles + * The mazximum number of consecutive members in any Ensemble + * @return */ - @DynamicSerializeElement - @XmlAttribute - private String init; - - /** - * ensemble models set this - */ - @DynamicSerializeElement - @XmlAttribute - private Integer size; - - public void setName(String name) { - this.name = name; + public List split(int maxEnsembles) { + int[] indexes = getSortedIndexes(); + if (indexes == null) { + return Arrays.asList(new Ensemble(this)); + } + List result = new ArrayList(); + List selected = new ArrayList(selectedMembers.size()); + int start = indexes[0]; + int end = start - 1; + for (int index : indexes) { + end += 1; + if (index != end || (end - start) >= maxEnsembles) { + // Either we have run out of consecutive indexes or we have the + // max consecutive. so split off and start the next one. + Ensemble e = new Ensemble(this); + e.setSelectedMembers(new ArrayList(selected)); + selected.clear(); + result.add(e); + start = index; + end = start; + } + selected.add(members.get(index)); + } + Ensemble e = new Ensemble(this); + e.setSelectedMembers(selected); + result.add(e); + return result; } - public String getName() { - return name; + private int[] getSortedIndexes() { + if (!hasSelection()) { + return null; + } + int[] indexes = new int[selectedMembers.size()]; + int c = 0; + for (String selected : selectedMembers) { + int index = members.indexOf(selected); + if (index >= 0) { + indexes[c++] = index; + } + } + if (c == 0) { + return null; + } else if (c < indexes.length) { + indexes = Arrays.copyOf(indexes, c); + } + Arrays.sort(indexes); + return indexes; } - public void setSize(Integer size) { - this.size = size; - } - - public Integer getSize() { - return size; - } - - public void setLength(String length) { - this.length = length; - } - - public String getLength() { - return length; - } - - public void setInit(String init) { - this.init = init; - } - - public String getInit() { - return init; - } } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GriddedDataSet.java b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GriddedDataSet.java index 69dc1aaba9..39c50ecf39 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GriddedDataSet.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GriddedDataSet.java @@ -20,6 +20,7 @@ package com.raytheon.uf.common.datadelivery.registry; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.xml.bind.annotation.XmlAccessType; @@ -59,6 +60,10 @@ public abstract class GriddedDataSet extends DataSet { @DynamicSerializeElement protected Set forecastHours = new HashSet(); + @DynamicSerializeElement + @XmlElement + private Ensemble ensemble; + /** * @return the cycles */ @@ -89,6 +94,14 @@ public abstract class GriddedDataSet extends DataSet { this.forecastHours = forecastHours; } + public Ensemble getEnsemble() { + return ensemble; + } + + public void setEnsemble(Ensemble ensemble) { + this.ensemble = ensemble; + } + /** * {@inheritDoc} */ @@ -100,6 +113,15 @@ public abstract class GriddedDataSet extends DataSet { GriddedDataSet other = (GriddedDataSet) toCombine; this.getCycles().addAll(other.getCycles()); this.getForecastHours().addAll(other.getForecastHours()); + if (this.getEnsemble() != null) { + List mine = this.getEnsemble().getSelectedMembers(); + List theirs = other.getEnsemble().getSelectedMembers(); + if (mine == null) { + ensemble.setSelectedMembers(theirs); + } else if (theirs != null) { + mine.addAll(theirs); + } + } } } } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GriddedDataSetMetaData.java b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GriddedDataSetMetaData.java index bd620a29c4..70466a535c 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GriddedDataSetMetaData.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GriddedDataSetMetaData.java @@ -6,7 +6,6 @@ import java.util.Map; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @@ -60,13 +59,6 @@ public abstract class GriddedDataSetMetaData extends @SlotAttribute(CYCLE_SLOT) private int cycle = NO_CYCLE; - /** - * ensemble models set this - */ - @DynamicSerializeElement - @XmlElement - private Ensemble ensemble; - public void setLevelTypes(Map levelTypes) { this.levelTypes = levelTypes; } @@ -92,11 +84,4 @@ public abstract class GriddedDataSetMetaData extends return cycle; } - public void setEnsemble(Ensemble ensemble) { - this.ensemble = ensemble; - } - - public Ensemble getEnsemble() { - return ensemble; - } } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GroupDefinitionServiceRequest.java b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GroupDefinitionServiceRequest.java new file mode 100644 index 0000000000..1bb6016c1e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/GroupDefinitionServiceRequest.java @@ -0,0 +1,85 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.datadelivery.registry; + +import com.raytheon.uf.common.auth.req.AbstractPrivilegedRequest; +import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; + +/** + * Service request for {@link GroupDefinition}s. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 18, 2013 1441       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@DynamicSerialize +public class GroupDefinitionServiceRequest extends AbstractPrivilegedRequest { + + public static enum Type { + DELETE; + } + + @DynamicSerializeElement + private GroupDefinition group; + + @DynamicSerializeElement + private Type type; + + /** + * @return the type + */ + public Type getType() { + return type; + } + + /** + * @param type + * the type to set + */ + public void setType(Type type) { + this.type = type; + } + + /** + * @return the group + */ + public GroupDefinition getGroup() { + return group; + } + + /** + * @param group + * the group to set + */ + public void setGroup(GroupDefinition group) { + this.group = group; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Levels.java b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Levels.java index 4407a8b0f2..a8eec4aa03 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Levels.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Levels.java @@ -25,6 +25,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; * Feb 08, 2011 191 dhladky Initial creation * Jul 24, 2012 955 djohnson Use List instead of ArrayList. * Nov 19, 2012 1166 djohnson Clean up JAXB representation of registry objects. + * Jan 28, 2013 1530 djohnson Never return null for selected level indices. * * * @author dhladky @@ -67,7 +68,7 @@ public class Levels implements ISerializableObject, Serializable { @XmlElements({ @XmlElement(name = "selectedLevelIndices", type = Integer.class) }) @DynamicSerializeElement - private List selectedLevelIndices; + private List selectedLevelIndices = new ArrayList(); /** * Copy constructor diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Parameter.java b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Parameter.java index d21c2dfa57..f92747fedd 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Parameter.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Parameter.java @@ -92,10 +92,6 @@ public class Parameter implements ISerializableObject, Serializable { @DynamicSerializeElement private String fillValue; - @XmlAttribute - @DynamicSerializeElement - private Integer ensemble; - @XmlAttribute @DynamicSerializeElement private String baseType; @@ -124,7 +120,6 @@ public class Parameter implements ISerializableObject, Serializable { this.dataType = copy.dataType; this.missingValue = copy.missingValue; this.fillValue = copy.fillValue; - this.ensemble = copy.ensemble; this.baseType = copy.baseType; // deep copy @@ -265,14 +260,6 @@ public class Parameter implements ISerializableObject, Serializable { return levels; } - public void setEnsemble(Integer ensemble) { - this.ensemble = ensemble; - } - - public Integer getEnsemble() { - return ensemble; - } - public void setFillValue(String fillValue) { this.fillValue = fillValue; } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Provider.java b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Provider.java index f2775c04a3..5ec9a26b7f 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Provider.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Provider.java @@ -3,11 +3,8 @@ package com.raytheon.uf.common.datadelivery.registry; import static com.google.common.base.Preconditions.checkNotNull; import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.persistence.Transient; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; @@ -22,6 +19,8 @@ import com.raytheon.uf.common.registry.annotations.SlotAttribute; import com.raytheon.uf.common.serialization.ISerializableObject; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; +import com.raytheon.uf.common.time.domain.Durations; +import com.raytheon.uf.common.time.domain.api.IDuration; /** * @@ -62,8 +61,9 @@ public class Provider implements ISerializableObject { * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Feb 16, 2012 dhladky Initial creation + * Feb 16, 2012 dhladky Initial creation * Nov 19, 2012 1166 djohnson Clean up JAXB representation of registry objects. + * Jan 14, 2013 1286 djohnson Extracted {@link IDuration}. * * * @@ -167,16 +167,9 @@ public class Provider implements ISerializableObject { @SlotAttribute private ServiceType serviceType; - // NOTE: The @XmlElement is on the getter because JAXB must call the setter - // for this value + @XmlElement @DynamicSerializeElement - private String postedFileDelay; - - @Transient - private int postedFileDelayValue = 0; - - @Transient - private TimeUnit postedFileDelayUnits = TimeUnit.HOURS; + private IDuration postedFileDelay = Durations.ZERO; /** * The amount of time that should elapse between HTTP requests while @@ -225,29 +218,10 @@ public class Provider implements ISerializableObject { /** * @return the postedFileDelay */ - @XmlElement(name = "postedFileDelay") - public String getPostedFileDelay() { + public IDuration getPostedFileDelay() { return postedFileDelay; } - /** - * Return the {@link TimeUnit} for the posted file delay. - * - * @return the {@link TimeUnit} - */ - public TimeUnit getPostedFileDelayUnits() { - return postedFileDelayUnits; - } - - /** - * Return the value of the posted file delay. - * - * @return the value - */ - public int getPostedFileDelayValue() { - return postedFileDelayValue; - } - public List getProjection() { return projection; } @@ -321,25 +295,10 @@ public class Provider implements ISerializableObject { * if the string value cannot be parsed into a value and/or * units */ - public void setPostedFileDelay(String postedFileDelay) { + public void setPostedFileDelay(IDuration postedFileDelay) { checkNotNull(postedFileDelay, "postedFileDelay cannot be null!"); this.postedFileDelay = postedFileDelay; - - Matcher matcher = POSTED_FILE_DELAY_PATTERN.matcher(postedFileDelay); - if (matcher.matches()) { - postedFileDelayValue = Integer.parseInt(matcher.group(1)); - String units = matcher.group(2); - postedFileDelayUnits = TimeUnit.valueOf(units); - - if (postedFileDelayUnits == null) { - throw new IllegalArgumentException(units - + " cannot be parsed into a valid units instance!"); - } - } else { - throw new IllegalArgumentException(postedFileDelay - + " cannot be parsed into a valid value and units!"); - } } public void setProjection(List projection) { diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Subscription.java b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Subscription.java index a7eb9581e0..d04aec0db3 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Subscription.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.registry/src/com/raytheon/uf/common/datadelivery/registry/Subscription.java @@ -11,6 +11,8 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlEnumValue; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSeeAlso; @@ -50,6 +52,7 @@ import com.raytheon.uf.common.time.util.TimeUtil; * Nov 20, 2012 1286 djohnson Add unscheduled. * Dec 12, 2012 1433 bgonzale Refactored Subscription copy ctor into two ctors. * Jan 03, 2013 1441 djohnson Default to no group. + * Jan 25, 2013 1528 djohnson Subscription priority is now an enum. * * * @@ -66,6 +69,73 @@ import com.raytheon.uf.common.time.util.TimeUtil; Subscription.DATA_SET_SLOT, Subscription.OWNER_SLOT }) public class Subscription implements ISerializableObject, Serializable { + /** Enumeration to use for subscription priorities */ + @XmlEnum + public static enum SubscriptionPriority { + /** High Priority */ + @XmlEnumValue("High") + HIGH("High", 1), + /** Default Priority */ + @XmlEnumValue("Normal") + NORMAL("Normal", 2), + /** Low Priority */ + @XmlEnumValue("Low") + LOW("Low", 3); + + /** Priority Setting */ + private final String priorityName; + + /** Numeric Value of the priority */ + private int priorityValue; + + private SubscriptionPriority(String priorityName, Integer priorityValue) { + this.priorityName = priorityName; + this.priorityValue = priorityValue; + } + + /** + * Get column name. + * + * @return Priority Name + */ + public String getPriorityName() { + return priorityName; + } + + /** + * Get the integer value of the priority + * + * @return The integer value of the priority. + */ + public int getPriorityValue() { + return priorityValue; + } + + @Override + public String toString() { + return priorityName; + } + + /** + * Retrieve the {@link SubscriptionPriority} by its string + * representation. + * + * @param string + * the string representation + * @return the {@link SubscriptionPriority} + */ + public static SubscriptionPriority fromPriorityName(String string) { + for (SubscriptionPriority potential : SubscriptionPriority.values()) { + if (potential.getPriorityName().equals(string)) { + return potential; + } + } + throw new IllegalArgumentException( + "Unable to find priority with priority name [" + string + + "]"); + } + } + private static final long serialVersionUID = -6422673887457060034L; /** Dataset Name slot */ @@ -133,6 +203,7 @@ public class Subscription implements ISerializableObject, Serializable { this.setDataSetType(sub.getDataSetType()); this.setRoute(sub.getRoute()); this.setLatencyInMinutes(sub.getLatencyInMinutes()); + this.setEnsemble(sub.getEnsemble()); } @XmlAttribute @@ -166,7 +237,7 @@ public class Subscription implements ISerializableObject, Serializable { @XmlAttribute @DynamicSerializeElement - private Integer priority; + private SubscriptionPriority priority = SubscriptionPriority.NORMAL; @XmlAttribute @DynamicSerializeElement @@ -243,6 +314,10 @@ public class Subscription implements ISerializableObject, Serializable { @DynamicSerializeElement private ArrayList parameter; + @XmlElement + @DynamicSerializeElement + private Ensemble ensemble; + @XmlAttribute @DynamicSerializeElement private boolean deleted; @@ -359,7 +434,7 @@ public class Subscription implements ISerializableObject, Serializable { * * @return subscription name */ - public Integer getPriority() { + public SubscriptionPriority getPriority() { return priority; } @@ -369,7 +444,7 @@ public class Subscription implements ISerializableObject, Serializable { * @param priority * priority */ - public void setPriority(Integer priority) { + public void setPriority(SubscriptionPriority priority) { this.priority = priority; } @@ -920,4 +995,13 @@ public class Subscription implements ISerializableObject, Serializable { public int getLatencyInMinutes() { return latencyInMinutes; } + + public Ensemble getEnsemble() { + return ensemble; + } + + public void setEnsemble(Ensemble ensemble) { + this.ensemble = ensemble; + } + } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.request/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.datadelivery.request/META-INF/MANIFEST.MF index ff054aa358..9c6d895d32 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.request/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.request/META-INF/MANIFEST.MF @@ -8,4 +8,5 @@ Require-Bundle: com.raytheon.uf.common.auth;bundle-version="1.12.1174", com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174", com.raytheon.uf.common.util;bundle-version="1.12.1174" Export-Package: com.raytheon.uf.common.datadelivery.request;uses:="com.raytheon.uf.common.auth.req,com.raytheon.uf.common.serialization", - com.raytheon.uf.common.datadelivery.request.user;uses:="com.raytheon.uf.common.auth.user" + com.raytheon.uf.common.datadelivery.request.user;uses:="com.raytheon.uf.common.auth.user", + com.raytheon.uf.common.datadelivery.service diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.request/src/com/raytheon/uf/common/datadelivery/service/BaseDataDeliveryService.java b/edexOsgi/com.raytheon.uf.common.datadelivery.request/src/com/raytheon/uf/common/datadelivery/service/BaseDataDeliveryService.java new file mode 100644 index 0000000000..0eec53b63b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.request/src/com/raytheon/uf/common/datadelivery/service/BaseDataDeliveryService.java @@ -0,0 +1,69 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.datadelivery.service; + +import java.rmi.RemoteException; + +import com.raytheon.uf.common.auth.req.AbstractPrivilegedRequest; +import com.raytheon.uf.common.auth.resp.SuccessfulExecution; +import com.raytheon.uf.common.datadelivery.request.DataDeliveryConstants; +import com.raytheon.uf.common.serialization.ExceptionWrapper; +import com.raytheon.uf.common.serialization.comm.RequestRouter; +import com.raytheon.uf.common.serialization.comm.response.ServerErrorResponse; + +/** + * Base class for services that send requests to the data delivery server. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 18, 2013 1441       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +public class BaseDataDeliveryService { + + /** + * Send a request to the data delivery server. + * + * @param request + * @return + * @throws Exception + */ + protected Object sendRequest(T request) throws Exception { + Object object = RequestRouter.route(request, + DataDeliveryConstants.DATA_DELIVERY_SERVER); + if (object instanceof SuccessfulExecution) { + SuccessfulExecution response = (SuccessfulExecution) object; + return response.getResponse(); + } else { + throw new RemoteException("Error communicating with the server!", + ExceptionWrapper + .unwrapThrowable(((ServerErrorResponse) object) + .getException())); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/util/DataSizeUtils.java b/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/util/DataSizeUtils.java index 0c14d7da1c..0d5b656b19 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/util/DataSizeUtils.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/util/DataSizeUtils.java @@ -26,6 +26,7 @@ import org.geotools.geometry.jts.ReferencedEnvelope; import com.raytheon.uf.common.datadelivery.registry.Coverage; import com.raytheon.uf.common.datadelivery.registry.DataSet; +import com.raytheon.uf.common.datadelivery.registry.Ensemble; import com.raytheon.uf.common.datadelivery.registry.GriddedCoverage; import com.raytheon.uf.common.datadelivery.registry.GriddedDataSet; import com.raytheon.uf.common.datadelivery.registry.Levels; @@ -102,6 +103,8 @@ public class DataSizeUtils { /** Number of forecast hours */ private int numFcstHours = 0; + private int numEnsembleMembers = 0; + /** Envelope */ private ReferencedEnvelope envelope = null; @@ -153,6 +156,7 @@ public class DataSizeUtils { public long getDataSetSizeInBytes() { long l = numRequestedGrids * numFcstHours + * numEnsembleMembers * dataSet.getServiceType().getRequestBytesPerParameterPerLevel( numberOfGridCells); return l; @@ -181,8 +185,15 @@ public class DataSizeUtils { long numCells = griddedCov.getGridCoverage().getNx() * griddedCov.getGridCoverage().getNy(); // Default to 1 forecast hour if not a gridded data set - long fcstHrs = dataSet instanceof GriddedDataSet ? ((GriddedDataSet) dataSet) - .getForecastHours().size() : 1; + long numEns = 1; + long fcstHrs = 1; + if (dataSet instanceof GriddedDataSet) { + GriddedDataSet gDataSet = (GriddedDataSet) dataSet; + fcstHrs = gDataSet.getForecastHours().size(); + if (gDataSet.getEnsemble() != null) { + numEns = gDataSet.getEnsemble().getMemberCount(); + } + } Map paramMap = dataSet.getParameters(); // get the number of grids available @@ -196,7 +207,8 @@ public class DataSizeUtils { numGridsAvailable += (numLevels > 0 ? numLevels : 1); } - fullSize = fcstHrs + fullSize = numEns + * fcstHrs * numGridsAvailable * dataSet.getServiceType() .getRequestBytesPerParameterPerLevel( @@ -295,4 +307,13 @@ public class DataSizeUtils { this.numRequestedGrids = numGrids; } + + public void setNumEnsembleMembers(Ensemble ensemble) { + if (ensemble == null) { + this.numEnsembleMembers = 1; + } else { + this.numEnsembleMembers = ensemble.getSelectedMemberCount(); + } + + } } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/util/LookupManager.java b/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/util/LookupManager.java index 20e4bfed21..8fca5267ef 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/util/LookupManager.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/util/LookupManager.java @@ -42,8 +42,10 @@ import com.raytheon.uf.common.serialization.SerializationUtil; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.util.CollectionUtil; import com.raytheon.uf.common.util.ServiceLoaderUtil; + /** * Lookup table manager * @@ -54,6 +56,7 @@ import com.raytheon.uf.common.util.ServiceLoaderUtil; * ------------ ---------- ----------- -------------------------- * Mar 7, 2011 357 dhladky Initial creation * Oct 27, 2012 1163 dhladky Improved, dynamically create files, Added Units + * Jan 18, 2013 1513 dhladky Level lookup refit. * * * @@ -381,10 +384,9 @@ public class LookupManager { * @throws Exception */ public void modifyLevelLookups(String modelName, double dz, float min, - float max) throws Exception { + float max, List levs) throws Exception { LevelLookup ll = null; - List levs = null; if (levelLookupExists(modelName)) { ll = getLevelsFromFile(modelName); @@ -397,25 +399,33 @@ public class LookupManager { ll = new LevelLookup(); } - if (levs == null) { + boolean gen = false; + + + if (CollectionUtil.isNullOrEmpty(levs)) { ll.setLevelXml(new ArrayList()); levs = ll.getLevelXml(); + gen = true; + } else { + ll.setLevelXml(levs); } - int diff = (int) (max - min); - int total = (int) Math.abs((diff / dz)); - // These add simple place holder level - // identifiers. It is up to the admin - // to add the real values - if (diff < 0) { - for (int i = 0; i <= total; i++) { - double lev = max + i * dz; - levs.add(lev); - } - } else { - for (int i = 0; i <= total; i++) { - double lev = min + i * dz; - levs.add(lev); + if (gen) { + int diff = (int) (max - min); + int total = (int) Math.abs((diff / dz)); + // These add simple place holder level + // identifiers. It is up to the admin + // to add the real values + if (diff < 0) { + for (int i = 0; i <= total; i++) { + double lev = max + i * dz; + levs.add(lev); + } + } else { + for (int i = 0; i <= total; i++) { + double lev = min + i * dz; + levs.add(lev); + } } } @@ -551,4 +561,6 @@ public class LookupManager { return unitXml; } + + } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/xml/RetrievalAttribute.java b/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/xml/RetrievalAttribute.java index c5f48a70ff..860d87acee 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/xml/RetrievalAttribute.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.retrieval/src/com/raytheon/uf/common/datadelivery/retrieval/xml/RetrievalAttribute.java @@ -29,6 +29,7 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import com.raytheon.uf.common.datadelivery.registry.Coverage; import com.raytheon.uf.common.datadelivery.registry.CoverageAdapter; +import com.raytheon.uf.common.datadelivery.registry.Ensemble; import com.raytheon.uf.common.datadelivery.registry.Parameter; import com.raytheon.uf.common.datadelivery.registry.Time; import com.raytheon.uf.common.serialization.ISerializableObject; @@ -100,6 +101,10 @@ public class RetrievalAttribute implements ISerializableObject, Serializable { @DynamicSerializeElement private Time time; + @XmlElement + @DynamicSerializeElement + private Ensemble ensemble; + @XmlElement(name = "provider") @DynamicSerializeElement private String provider; @@ -156,4 +161,12 @@ public class RetrievalAttribute implements ISerializableObject, Serializable { return subName; } + public Ensemble getEnsemble() { + return ensemble; + } + + public void setEnsemble(Ensemble ensemble) { + this.ensemble = ensemble; + } + } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.service/.classpath b/edexOsgi/com.raytheon.uf.common.datadelivery.service/.classpath new file mode 100644 index 0000000000..5fb20a28e5 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.service/.project b/edexOsgi/com.raytheon.uf.common.datadelivery.service/.project new file mode 100644 index 0000000000..0cee36f7f5 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.common.datadelivery.service + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.service/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.common.datadelivery.service/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..28b23bdfac --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Tue Feb 14 11:27:19 CST 2012 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.service/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.datadelivery.service/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..242708d98c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/META-INF/MANIFEST.MF @@ -0,0 +1,20 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: com.raytheon.uf.common.datadelivery.service +Bundle-SymbolicName: com.raytheon.uf.common.datadelivery.service +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Import-Package: javax.persistence +Require-Bundle: + com.raytheon.uf.common.serialization;bundle-version="1.12.1174", + com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174", + com.raytheon.uf.common.datadelivery.registry;bundle-version="1.0.0", + com.raytheon.uf.common.status;bundle-version="1.12.1174", + com.raytheon.uf.common.datadelivery.request;bundle-version="1.0.0", + com.raytheon.uf.common.registry.ebxml;bundle-version="1.0.0", + com.raytheon.uf.common.auth;bundle-version="1.12.1174" +Export-Package: + com.raytheon.uf.common.datadelivery.service + + diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.service/build.properties b/edexOsgi/com.raytheon.uf.common.datadelivery.service/build.properties new file mode 100644 index 0000000000..9f81850f2c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/build.properties @@ -0,0 +1,6 @@ +source.. = src/,\ + res/ +output.. = bin/ +bin.includes = META-INF/,\ + res/,\ + . \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.service/com.raytheon.uf.common.datadelivery.service.ecl b/edexOsgi/com.raytheon.uf.common.datadelivery.service/com.raytheon.uf.common.datadelivery.service.ecl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.service/res/spring/datadelivery-service.xml b/edexOsgi/com.raytheon.uf.common.datadelivery.service/res/spring/datadelivery-service.xml new file mode 100644 index 0000000000..67c539da2f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/res/spring/datadelivery-service.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/ApprovedPendingSubscriptionNotificationRequest.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/ApprovedPendingSubscriptionNotificationRequest.java similarity index 96% rename from edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/ApprovedPendingSubscriptionNotificationRequest.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/ApprovedPendingSubscriptionNotificationRequest.java index 3cae3fca16..3f28d090b0 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/ApprovedPendingSubscriptionNotificationRequest.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/ApprovedPendingSubscriptionNotificationRequest.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.event.notification; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/ApprovedPendingSubscriptionNotificationResponse.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/ApprovedPendingSubscriptionNotificationResponse.java similarity index 95% rename from edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/ApprovedPendingSubscriptionNotificationResponse.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/ApprovedPendingSubscriptionNotificationResponse.java index 97abe5e0d1..af357e0b26 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/ApprovedPendingSubscriptionNotificationResponse.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/ApprovedPendingSubscriptionNotificationResponse.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.event.notification; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/BaseSubscriptionNotificationRequest.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/BaseSubscriptionNotificationRequest.java similarity index 97% rename from edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/BaseSubscriptionNotificationRequest.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/BaseSubscriptionNotificationRequest.java index 99cbd26efe..3670927e41 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/BaseSubscriptionNotificationRequest.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/BaseSubscriptionNotificationRequest.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.event.notification; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.serialization.ISerializableObject; diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/BaseSubscriptionNotificationResponse.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/BaseSubscriptionNotificationResponse.java similarity index 82% rename from edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/BaseSubscriptionNotificationResponse.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/BaseSubscriptionNotificationResponse.java index bdc515c04a..b879907bc9 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/BaseSubscriptionNotificationResponse.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/BaseSubscriptionNotificationResponse.java @@ -17,9 +17,10 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.event.notification; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.handlers.IBaseSubscriptionHandler; import com.raytheon.uf.common.serialization.ISerializableObject; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @@ -27,17 +28,18 @@ import com.raytheon.uf.common.serialization.comm.IServerRequest; /** * Base abstract class for the subscription notification response. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Sep 20, 2012    1157    mpduff      Initial creation
- *
+ * Jan 17, 2013 1501       djohnson     Allow a response to specify the subscription handler.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -85,4 +87,11 @@ public abstract class BaseSubscriptionNotificationResponse getSubscriptionHandler(); } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/DeniedPendingSubscriptionNotificationRequest.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/DeniedPendingSubscriptionNotificationRequest.java similarity index 96% rename from edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/DeniedPendingSubscriptionNotificationRequest.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/DeniedPendingSubscriptionNotificationRequest.java index 08dcacf8da..d5183fa270 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/DeniedPendingSubscriptionNotificationRequest.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/DeniedPendingSubscriptionNotificationRequest.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.event.notification; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/DeniedPendingSubscriptionNotificationResponse.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/DeniedPendingSubscriptionNotificationResponse.java similarity index 96% rename from edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/DeniedPendingSubscriptionNotificationResponse.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/DeniedPendingSubscriptionNotificationResponse.java index 3a3c60722f..cb7cfc7971 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/DeniedPendingSubscriptionNotificationResponse.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/DeniedPendingSubscriptionNotificationResponse.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.event.notification; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/GroupDefinitionService.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/GroupDefinitionService.java new file mode 100644 index 0000000000..ed7777375d --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/GroupDefinitionService.java @@ -0,0 +1,75 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.datadelivery.service; + +import com.raytheon.uf.common.datadelivery.registry.GroupDefinition; +import com.raytheon.uf.common.datadelivery.registry.GroupDefinitionServiceRequest; +import com.raytheon.uf.common.datadelivery.registry.GroupDefinitionServiceRequest.Type; +import com.raytheon.uf.common.registry.handler.RegistryHandlerException; + +/** + * Base implementation of {@link IGroupDefinitionService}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 18, 2013 1441       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public class GroupDefinitionService extends + BaseDataDeliveryService implements + IGroupDefinitionService { + + /** + * {@inheritDoc} + * @throws Exception + */ + @Override + public void deleteGroupDefinition(GroupDefinition group) + throws RegistryHandlerException { + GroupDefinitionServiceRequest request = new GroupDefinitionServiceRequest(); + request.setGroup(group); + request.setType(Type.DELETE); + + sendRequest(request); + } + + /** + * {@inheritDoc} + */ + @Override + protected Object sendRequest(GroupDefinitionServiceRequest request) + throws RegistryHandlerException { + try { + return super.sendRequest(request); + } catch (Exception e) { + throw new RegistryHandlerException(e); + } + } + +} diff --git a/tests/unit/com/raytheon/uf/common/datadelivery/retrieval/util/NullXmlWriter.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/IGroupDefinitionService.java similarity index 57% rename from tests/unit/com/raytheon/uf/common/datadelivery/retrieval/util/NullXmlWriter.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/IGroupDefinitionService.java index 38a044e069..d99f0a96bb 100644 --- a/tests/unit/com/raytheon/uf/common/datadelivery/retrieval/util/NullXmlWriter.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/IGroupDefinitionService.java @@ -17,44 +17,36 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.retrieval.util; +package com.raytheon.uf.common.datadelivery.service; -import com.raytheon.uf.common.datadelivery.retrieval.xml.LevelLookup; -import com.raytheon.uf.common.datadelivery.retrieval.xml.ParameterLookup; +import com.raytheon.uf.common.datadelivery.registry.GroupDefinition; +import com.raytheon.uf.common.registry.handler.RegistryHandlerException; /** - * Makes parser created XML not write out in test + * Defines the service to interact with {@link GroupDefinition} objects. * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Jan 10, 2013            djohnson     Initial creation
- *
+ * Jan 18, 2013 1441       djohnson     Initial creation
+ * 
  * 
- * + * * @author djohnson - * @version 1.0 + * @version 1.0 */ -public class NullXmlWriter implements LevelXmlWriter, ParameterXmlWriter { - +public interface IGroupDefinitionService { /** - * {@inheritDoc} + * Delete the group definition. + * + * @param group + * the group + * @throws RegistryHandlerException */ - @Override - public void writeParameterXml(ParameterLookup pl, String modelName) - throws Exception { - } - - /** - * {@inheritDoc} - */ - @Override - public void writeLevelXml(LevelLookup ll, String modelName) - throws Exception { - } - + void deleteGroupDefinition(GroupDefinition group) + throws RegistryHandlerException; } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/ISubscriptionNotificationService.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/ISubscriptionNotificationService.java similarity index 98% rename from cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/ISubscriptionNotificationService.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/ISubscriptionNotificationService.java index 98216ec787..4394219ff2 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/ISubscriptionNotificationService.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/ISubscriptionNotificationService.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.viz.datadelivery.subscription; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.datadelivery.registry.InitialPendingSubscription; import com.raytheon.uf.common.datadelivery.registry.Subscription; diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/PendingSubscriptionNotificationRequest.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/PendingSubscriptionNotificationRequest.java similarity index 96% rename from edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/PendingSubscriptionNotificationRequest.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/PendingSubscriptionNotificationRequest.java index a531ea5629..af4cc15ad5 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/PendingSubscriptionNotificationRequest.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/PendingSubscriptionNotificationRequest.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.event.notification; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.datadelivery.registry.InitialPendingSubscription; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/PendingSubscriptionNotificationResponse.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/PendingSubscriptionNotificationResponse.java similarity index 71% rename from edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/PendingSubscriptionNotificationResponse.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/PendingSubscriptionNotificationResponse.java index 46b9f011b7..f88a77832f 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/PendingSubscriptionNotificationResponse.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/PendingSubscriptionNotificationResponse.java @@ -17,24 +17,27 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.event.notification; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.datadelivery.registry.InitialPendingSubscription; +import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; +import com.raytheon.uf.common.datadelivery.registry.handlers.IBaseSubscriptionHandler; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; /** * PendingSubscriptionNotificationResponse object. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Sep 20, 2012            mpduff     Initial creation
- *
+ * Jan 17, 2013 1501       djohnson     Allow a response to specify the subscription handler.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -42,4 +45,12 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; public class PendingSubscriptionNotificationResponse extends BaseSubscriptionNotificationResponse { + /** + * {@inheritDoc} + */ + @Override + public IBaseSubscriptionHandler getSubscriptionHandler() { + return DataDeliveryHandlers.getPendingSubscriptionHandler(); + } + } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SendToServerSubscriptionNotificationService.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/SendToServerSubscriptionNotificationService.java similarity index 88% rename from cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SendToServerSubscriptionNotificationService.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/SendToServerSubscriptionNotificationService.java index 8206745bcf..ef4645d3e2 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/subscription/SendToServerSubscriptionNotificationService.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/SendToServerSubscriptionNotificationService.java @@ -17,20 +17,15 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.viz.datadelivery.subscription; +package com.raytheon.uf.common.datadelivery.service; -import com.raytheon.uf.common.datadelivery.event.notification.ApprovedPendingSubscriptionNotificationRequest; -import com.raytheon.uf.common.datadelivery.event.notification.BaseSubscriptionNotificationRequest; -import com.raytheon.uf.common.datadelivery.event.notification.DeniedPendingSubscriptionNotificationRequest; -import com.raytheon.uf.common.datadelivery.event.notification.PendingSubscriptionNotificationRequest; -import com.raytheon.uf.common.datadelivery.event.notification.SubscriptionNotificationRequest; import com.raytheon.uf.common.datadelivery.registry.InitialPendingSubscription; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.request.DataDeliveryConstants; +import com.raytheon.uf.common.serialization.comm.RequestRouter; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; -import com.raytheon.uf.viz.core.exception.VizException; -import com.raytheon.uf.viz.core.requests.ThriftClient; /** * Implementation of {@link ISubscriptionNotificationService} that sends the @@ -42,7 +37,9 @@ import com.raytheon.uf.viz.core.requests.ThriftClient; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Jan 4, 2013 1441 djohnson Initial creation + * Jan 04, 2013 1441 djohnson Initial creation + * Jan 17, 2013 1501 djohnson Route to datadelivery. + * Jan 21, 2013 1501 djohnson Include subscription on all requests. * * * @@ -181,6 +178,7 @@ public class SendToServerSubscriptionNotificationService implements req.setCategory("Subscription Approval Denied"); req.setPriority(2); req.setId(subscription.getId()); + req.setSubscription(subscription); sendRequest(req); } @@ -207,13 +205,13 @@ public class SendToServerSubscriptionNotificationService implements */ @Override public void sendSubscriptionActivatedNotification( - Subscription subscription, - String username) { + Subscription subscription, String username) { SubscriptionNotificationRequest req = new SubscriptionNotificationRequest(); req.setUserId(username); req.setCategory("Subscription"); req.setPriority(3); req.setMessage(subscription.getName() + " Activated"); + req.setSubscription(subscription); sendRequest(req); } @@ -223,13 +221,13 @@ public class SendToServerSubscriptionNotificationService implements */ @Override public void sendSubscriptionDeactivatedNotification( - Subscription subscription, - String username) { + Subscription subscription, String username) { SubscriptionNotificationRequest req = new SubscriptionNotificationRequest(); req.setUserId(username); req.setCategory("Subscription"); req.setPriority(3); req.setMessage(subscription.getName() + " Deactivated"); + req.setSubscription(subscription); sendRequest(req); } @@ -241,8 +239,9 @@ public class SendToServerSubscriptionNotificationService implements */ private void sendRequest(BaseSubscriptionNotificationRequest req) { try { - ThriftClient.sendRequest(req); - } catch (VizException e) { + RequestRouter + .route(req, DataDeliveryConstants.DATA_DELIVERY_SERVER); + } catch (Exception e) { statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e); } } diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/SubscriptionNotificationRequest.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/SubscriptionNotificationRequest.java similarity index 96% rename from edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/SubscriptionNotificationRequest.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/SubscriptionNotificationRequest.java index 18774bdd64..261aade582 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/SubscriptionNotificationRequest.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/SubscriptionNotificationRequest.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.event.notification; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; diff --git a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/SubscriptionNotificationResponse.java b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/SubscriptionNotificationResponse.java similarity index 72% rename from edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/SubscriptionNotificationResponse.java rename to edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/SubscriptionNotificationResponse.java index 61239fe9e9..b0c5d73482 100644 --- a/edexOsgi/com.raytheon.uf.common.datadelivery.event/src/com/raytheon/uf/common/datadelivery/event/notification/SubscriptionNotificationResponse.java +++ b/edexOsgi/com.raytheon.uf.common.datadelivery.service/src/com/raytheon/uf/common/datadelivery/service/SubscriptionNotificationResponse.java @@ -17,28 +17,39 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.common.datadelivery.event.notification; +package com.raytheon.uf.common.datadelivery.service; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; +import com.raytheon.uf.common.datadelivery.registry.handlers.IBaseSubscriptionHandler; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; /** * SubscriptionNotificationResponse object. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Jun 25, 2012            mpduff     Initial creation.
  * Aug 21, 2012     712    mpduff     Add a Subscription Object.
+ * Jan 17, 2013 1501       djohnson     Allow a response to specify the subscription handler.
  * 
- * + * * @author mpduff * @version 1.0 */ @DynamicSerialize public class SubscriptionNotificationResponse extends BaseSubscriptionNotificationResponse{ + + /** + * {@inheritDoc} + */ + @Override + public IBaseSubscriptionHandler getSubscriptionHandler() { + return DataDeliveryHandlers.getSubscriptionHandler(); + } } diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject index 63d9a8ae0f..441e54b68a 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/META-INF/services/com.raytheon.uf.common.serialization.ISerializableObject @@ -1,8 +1,2 @@ com.raytheon.uf.common.dataplugin.ffmp.FFMPRecord -com.raytheon.uf.common.dataplugin.ffmp.FFMPBasin -com.raytheon.uf.common.dataplugin.ffmp.FFMPVirtualGageBasin -com.raytheon.uf.common.dataplugin.ffmp.FFMPGuidanceBasin -com.raytheon.uf.common.dataplugin.ffmp.FFMPBasinData -com.raytheon.uf.common.dataplugin.ffmp.SourceBinList -com.raytheon.uf.common.dataplugin.ffmp.SourceBin -com.raytheon.uf.common.dataplugin.ffmp.SourceBinEntry \ No newline at end of file + diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPAggregateRecord.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPAggregateRecord.java new file mode 100644 index 0000000000..fc056e83a5 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPAggregateRecord.java @@ -0,0 +1,104 @@ +package com.raytheon.uf.common.dataplugin.ffmp; + +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.raytheon.uf.common.serialization.ISerializableObject; +import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; + +/** + * Cache Record implementation for FFMP plugin + * Eventually this will become a full record implementation + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * 01/27/13     1478        D. Hladky   Created to reduce memory and disk read/writes for FFMP
+ * 
+ * 
+ * + * @author dhladky + * @version 1 + */ + +@DynamicSerialize +public class FFMPAggregateRecord implements ISerializableObject { + + + private static final long serialVersionUID = 76774564363471L; + + /** + * + */ + public FFMPAggregateRecord() { + + } + + @DynamicSerializeElement + private HashMap basinsMap = new HashMap(); + + @DynamicSerializeElement + private List times = new ArrayList(); + + public void setTimes(List times) { + this.times = times; + } + + public List getTimes() { + return times; + } + + public void setBasinsMap(HashMap basinsMap) { + this.basinsMap = basinsMap; + } + + public HashMap getBasinsMap() { + return basinsMap; + } + + /** + * Add a basin Data Cache object + * @param cacheData + */ + public void setBasinData(FFMPBasinData cacheData) { + basinsMap.put(cacheData.getHucLevel(), cacheData); + } + + /** + * Gets the BasinData object + * @param huc + * @return + */ + public FFMPBasinData getBasinData(String huc) { + if (basinsMap.containsKey(huc)) { + return basinsMap.get(huc); + } + return null; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPBasin.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPBasin.java index 273200bba5..74c4d874de 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPBasin.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPBasin.java @@ -22,14 +22,11 @@ package com.raytheon.uf.common.dataplugin.ffmp; import java.util.ArrayList; import java.util.Comparator; import java.util.Date; +import java.util.List; import java.util.Map.Entry; import java.util.TreeMap; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; +import javax.persistence.Transient; import com.raytheon.uf.common.serialization.ISerializableObject; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; @@ -45,30 +42,49 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 06/22/09 2152 D. Hladky Initial release + * 01/27/13 1478 D. Hladky Added support for writing aggregate record cache * * * * @author dhladky * @version 1 */ -@XmlRootElement -@XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize public class FFMPBasin implements ISerializableObject, Cloneable { /** pfafstetter id(key) in GIS **/ @DynamicSerializeElement - @XmlElement protected Long pfaf; /** boolean aggregator **/ @DynamicSerializeElement - @XmlAttribute protected boolean aggregated = false; - @DynamicSerializeElement - @XmlElement + /** object used in calculations + * not serialized + **/ + @Transient protected TreeMap values; + + /** object used for serialization **/ + @DynamicSerializeElement + public float[] cacheValues; + + /** + * Get the float array of serialized values + * @return + */ + public float[] getCacheValues() { + return cacheValues; + } + + /** + * Set the serialized array of cache values + * @param cacheValues + */ + public void setCacheValues(float[] cacheValues) { + this.cacheValues = cacheValues; + } /** * @return the pfaf_id @@ -326,14 +342,23 @@ public class FFMPBasin implements ISerializableObject, Cloneable { } /** - * No arg hibernate constructor + * No arg serial constructor */ public FFMPBasin() { + values = new TreeMap(new Comparator() { + @Override + public int compare(Date o1, Date o2) { + // Null checks? + return (int)(o2.getTime() - o1.getTime()) ; + } + }); } /** - * useful constructor + * Useful constructor + * @param pfaf + * @param aggregated */ public FFMPBasin(Long pfaf, boolean aggregated) { setPfaf(pfaf); @@ -342,11 +367,45 @@ public class FFMPBasin implements ISerializableObject, Cloneable { @Override public int compare(Date o1, Date o2) { // Null checks? - return (int)Math.signum(o2.getTime() - o1.getTime()) ; + return (int)(o2.getTime() - o1.getTime()) ; } }); } + + /** + * Populates the values from the cache + * + * @param times + */ + public void populate(List times) { + // safe to avoid Array Index Exceptions / shouldn't happen but..... + + if (cacheValues != null && (times.size() == cacheValues.length)) { + + int i = 0; + for (Long time : times) { + values.put(new Date(time), cacheValues[i]); + i++; + } + //System.out.println("populated :"+i+" pfaf : "+pfaf); + } + } + + /** + * populates the serialized array + */ + public void setCache() { + + cacheValues = new float[values.size()]; + int i = 0; + + for (Date date: values.descendingKeySet()) { + cacheValues[i] = values.get(date); + i++; + } + //System.out.println("wrote :"+i+" pfaf : "+pfaf); + } /** * purge out old entries diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPBasinData.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPBasinData.java index 3255488b3d..0800b8b008 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPBasinData.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPBasinData.java @@ -22,11 +22,7 @@ package com.raytheon.uf.common.dataplugin.ffmp; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; import com.raytheon.uf.common.serialization.ISerializableObject; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; @@ -42,14 +38,13 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 06/22/09 2152 D. Hladky Initial release + * 01/27/13 1478 D. Hladky Added support for write of aggregate record cache * * * * @author dhladky * @version 1 */ -@XmlRootElement -@XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize public class FFMPBasinData implements ISerializableObject { @@ -62,11 +57,9 @@ public class FFMPBasinData implements ISerializableObject { // defaults @DynamicSerializeElement - @XmlElement private String hucLevel; @DynamicSerializeElement - @XmlElement private HashMap basins = new HashMap(); /** @@ -86,7 +79,7 @@ public class FFMPBasinData implements ISerializableObject { } /** - * Used only internally + * get the basin map * * @return */ @@ -95,7 +88,7 @@ public class FFMPBasinData implements ISerializableObject { } /** - * DONT USE THIS EVER!!!!! + * Sets the basin map * * @param basins */ @@ -545,5 +538,25 @@ public class FFMPBasinData implements ISerializableObject { basin.purgeData(date); } } + + /** + * populates data from the cache + * + * @param times + */ + public void populate(List times) { + for (FFMPBasin basin : basins.values()) { + basin.populate(times); + } + } + + /** + * populates the serialized array/objects + */ + public void setCache() { + for (FFMPBasin basin : basins.values()) { + basin.setCache(); + } + } } diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPCacheRecord.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPCacheRecord.java index 400167c282..bccf12b826 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPCacheRecord.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPCacheRecord.java @@ -1,4 +1,23 @@ package com.raytheon.uf.common.dataplugin.ffmp; +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ import java.awt.Point; import java.io.IOException; @@ -210,16 +229,16 @@ public class FFMPCacheRecord extends FFMPRecord { } /** - * Buddy File reader + * Cache File reader * * @param basins * @param hucName */ - public void setBasinBuddyData(FFMPBasinData basins, String hucName) { + public void setCacheData(FFMPBasinData basins, String hucName) { if (getBasinData(hucName) != null) { basins = getBasinData(hucName, true); - //System.out.println("Adding pieces Buddy Data: "+hucName+" "+getSourceName()); + //System.out.println("Adding Cache Data: "+hucName+" "+getSourceName()); synchronized (basins) { for (Entry entry : basins.getBasins() @@ -442,8 +461,7 @@ public class FFMPCacheRecord extends FFMPRecord { } catch (Throwable e) { statusHandler.handle(Priority.PROBLEM, "ERROR Retrieving Map for URI: " + uri - + "..." + huc); - e.printStackTrace(); + + "..." + huc, e); } } } diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPDataContainer.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPDataContainer.java index dc84912457..3cfecdc66d 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPDataContainer.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPDataContainer.java @@ -20,9 +20,9 @@ package com.raytheon.uf.common.dataplugin.ffmp; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -33,7 +33,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; /** - * FFTI Data Container + * FFMP Data Container * *
  * 
@@ -43,7 +43,8 @@ import com.raytheon.uf.common.status.UFStatus;
  * ------------ ----------  ----------- --------------------------
  * 03/31/11     5489     D. Hladky   Initial release
  * 07/31/12     578      D.Hladky    finished it
- * 09/27/12		DR 15471  G.Zhang	 Fixed ConcurrentModificationException
+ * 09/27/12		DR 15471 G.Zhang	 Fixed ConcurrentModificationException
+ * 01/27/13     1478     D. Hladky   Re-worked to help with memory size and NAS read write stress
  * 
* * @author dhladky @@ -62,15 +63,24 @@ public class FFMPDataContainer { private String filePath = null; public FFMPDataContainer() { - // public unused constructor + } + /** + * Usual constructor + * @param sourceName + */ public FFMPDataContainer(String sourceName) { this.sourceName = sourceName; basinDataMap.put("ALL", new FFMPBasinData("ALL")); // System.out.println("Creating source: " + sourceName); } + /** + * special constuctor + * @param sourceName + * @param hucs + */ public FFMPDataContainer(String sourceName, ArrayList hucs) { // System.out.println("Creating source with hucs: " + sourceName); this.sourceName = sourceName; @@ -78,6 +88,21 @@ public class FFMPDataContainer { basinDataMap.put(huc, new FFMPBasinData(huc)); } } + /** + * new container first time read in from cache + * @param sourceName + * @param hucs + * @param record + */ + public FFMPDataContainer(String sourceName, ArrayList hucs, FFMPAggregateRecord record) { + // System.out.println("Creating source with hucs: " + sourceName); + this.sourceName = sourceName; + for (String huc : hucs) { + FFMPBasinData basinData = record.getBasinData(huc); + basinData.populate(record.getTimes()); + basinDataMap.put(huc, basinData); + } + } /** * Adds to the cache @@ -400,7 +425,7 @@ public class FFMPDataContainer { * @param barrierTime * @return */ - public ArrayList getOrderedTimes(Date barrierTime) { + public List getOrderedTimes(Date barrierTime) { ArrayList orderedTimes = new ArrayList(); try { HashMap basins = getBasinData("ALL").getBasins(); @@ -414,7 +439,32 @@ public class FFMPDataContainer { } } - Collections.reverse(orderedTimes); + return orderedTimes; + } + } + } catch (Exception e) { + statusHandler.debug("No ordered times available..." + + getSourceName()); + } + + return null; + } + + /** + * Gets the list of times for serialization + * @return + */ + public List getOrderedTimes() { + ArrayList orderedTimes = new ArrayList(); + try { + HashMap basins = getBasinData("ALL").getBasins(); + + synchronized (basins) { + for (Entry entry : basins.entrySet()) { + FFMPBasin basin = entry.getValue(); + for (Date time : basin.getValues().descendingKeySet()) { + orderedTimes.add(time.getTime()); + } return orderedTimes; } @@ -422,18 +472,22 @@ public class FFMPDataContainer { } catch (Exception e) { statusHandler.debug("No ordered times available..." + getSourceName()); - return null; } return null; } + /** + * Gets the source name for this Data Container + * @return + */ public String getSourceName() { return sourceName; } - /* - * clean up old junk + /** + * Clean up old junk + * @param backDate */ public void purge(Date backDate) { for (String huc : basinDataMap.keySet()) { @@ -442,27 +496,33 @@ public class FFMPDataContainer { } /** - * maybe this will work + * Sets the Cache data for this container * - * @param basins - * @param hucName + * @param cacheRecord */ - public void setBasinBuddyData(FFMPBasinData basins, String hucName) { + public void setCacheData(FFMPAggregateRecord cacheRecord) { - for (Entry entry : basins.getBasins().entrySet()) { - FFMPBasin basin = getBasinData(hucName).get(entry.getKey()); - if (basin != null) { - if (basin instanceof FFMPGuidanceBasin) { - FFMPGuidanceBasin gbasin = (FFMPGuidanceBasin) basin; - gbasin.getGuidValues().putAll( - ((FFMPGuidanceBasin) entry.getValue()) - .getGuidValues()); + // create a record from the cache record + FFMPRecord record = new FFMPRecord(cacheRecord); + + for (Entry dentry : record.getBasinsMap() + .entrySet()) { + for (Entry entry : dentry.getValue().getBasins() + .entrySet()) { + FFMPBasin basin = entry.getValue(); + if (basin != null) { + if (basin instanceof FFMPGuidanceBasin) { + FFMPGuidanceBasin gbasin = (FFMPGuidanceBasin) basin; + gbasin.getGuidValues().putAll( + ((FFMPGuidanceBasin) entry.getValue()) + .getGuidValues()); + } else { + basin.getValues().putAll(entry.getValue().getValues()); + } } else { - basin.getValues().putAll(entry.getValue().getValues()); + syncPut(getBasinData(dentry.getKey()), entry.getKey(), + entry.getValue()); } - } else { - syncPut(getBasinData(hucName), entry.getKey(), entry.getValue()); - //getBasinData(hucName).put(entry.getKey(), entry.getValue()); } } } @@ -523,4 +583,13 @@ public class FFMPDataContainer { basins.put(key, value); } } + + /** + * Gets the basin data map + * @return + */ + public ConcurrentHashMap getBasinMap() { + return basinDataMap; + } + } diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGap.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGap.java index 3e97903f0d..d0490fec2d 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGap.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGap.java @@ -1,4 +1,23 @@ package com.raytheon.uf.common.dataplugin.ffmp; +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ /** * gap for FFMP @@ -10,6 +29,7 @@ package com.raytheon.uf.common.dataplugin.ffmp; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 03/03/11 7334 D. Hladky Initial release + * 01/27/13 1478 D. Hladky Added use of constants for calculations * * * @@ -19,6 +39,9 @@ package com.raytheon.uf.common.dataplugin.ffmp; import java.util.ArrayList; import java.util.Date; +import java.util.List; + +import com.raytheon.uf.common.time.util.TimeUtil; public class FFMPGap { @@ -62,21 +85,25 @@ public class FFMPGap { } /** - * Gets the GAP calculation for an FFMP source + * Get the gaps in the FFMP data * - * @return Array of Gap data + * @param times + * @param expirationTime + * @param barrierTime + * @param mostRecentTime + * @return */ - public static ArrayList getGaps(ArrayList times, + public static List getGaps(List times, long expirationTime, Date barrierTime, Date mostRecentTime) { ArrayList gaps = new ArrayList(); - long gapStep = expirationTime * 60 * 1000; + long gapStep = expirationTime * TimeUtil.MILLIS_PER_MINUTE; Date prevTime = null; // System.out.println("Calling getGaps()...Recent Time: " + mostRecentTime // + " BarrierTime: " + barrierTime); if (times.size() == 1) { FFMPGap gap = new FFMPGap(); long totalMillis = mostRecentTime.getTime() - barrierTime.getTime() - gapStep; - float gapMinutes = (totalMillis)/(60 * 1000); + float gapMinutes = totalMillis/TimeUtil.MILLIS_PER_MINUTE; if (gapMinutes < 0.0) { gapMinutes = 0.0f; } @@ -100,7 +127,7 @@ public class FFMPGap { FFMPGap gap = new FFMPGap(prevTime, time); // convert to minutes and set gap // Need to subtract the expirationTime from the gapTime as well - gap.setGap((gapTime - gapStep) / (60 * 1000)); + gap.setGap((gapTime - gapStep) / TimeUtil.MILLIS_PER_MINUTE); gaps.add(gap); } prevTime = time; diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGuidanceBasin.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGuidanceBasin.java index 3366acac1c..7b0c124115 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGuidanceBasin.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGuidanceBasin.java @@ -4,13 +4,10 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.TreeMap; import javax.persistence.Transient; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; import com.raytheon.uf.common.monitor.config.FFFGDataMgr; import com.raytheon.uf.common.serialization.ISerializableObject; @@ -27,22 +24,21 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 08/22/10 3437 D. Hladky Initial release + * 01/17/13 1478 D. Hladky Removed un-needed XML attributes * * * * @author dhladky * @version 1 */ -@XmlRootElement -@XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize public class FFMPGuidanceBasin extends FFMPBasin implements ISerializableObject { + public FFMPGuidanceBasin() { } @DynamicSerializeElement - @XmlElement protected TreeMap> guidValues; @Transient @@ -411,7 +407,10 @@ public class FFMPGuidanceBasin extends FFMPBasin implements ISerializableObject } /** - * useful constructor + * Constructor used in producing a new GuidanceBasin + * + * @param pfaf + * @param aggregated */ public FFMPGuidanceBasin(Long pfaf, boolean aggregated) { setPfaf(pfaf); @@ -457,5 +456,15 @@ public class FFMPGuidanceBasin extends FFMPBasin implements ISerializableObject } return buff.toString(); } - + + public void populate(List times) { + // does nothing here, don't need to populate anything. + } + + /** + * populates the serialized array + */ + public void setCache() { + // does nothing here, this class is serialized as is. + } } diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGuidanceInterpolation.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGuidanceInterpolation.java index a82f203b9a..1bc43a46d4 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGuidanceInterpolation.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPGuidanceInterpolation.java @@ -30,6 +30,7 @@ import com.raytheon.uf.common.monitor.config.FFMPSourceConfigurationManager; import com.raytheon.uf.common.monitor.xml.ProductRunXML; import com.raytheon.uf.common.monitor.xml.ProductXML; import com.raytheon.uf.common.monitor.xml.SourceXML; +import com.raytheon.uf.common.time.util.TimeUtil; /** * Guidance Interpolation @@ -39,6 +40,7 @@ import com.raytheon.uf.common.monitor.xml.SourceXML; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 29 Jan, 2010 3915 dhladky Initial creation + * 01/27/13 1478 dhladky Added use of constants * * * @author dhladky @@ -258,7 +260,7 @@ public class FFMPGuidanceInterpolation { getSource(orderedHours.get(index)), null, manager.getSource(source).getExpirationMinutes( - siteKey) * 60 * 1000); + siteKey) * TimeUtil.MILLIS_PER_MINUTE); if (dman.isExpired() == false) { thisVal = dman.adjustValue(thisVal, diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPRecord.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPRecord.java index 402d1937eb..08d86bde13 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPRecord.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPRecord.java @@ -25,6 +25,7 @@ import java.io.FileNotFoundException; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map.Entry; import javax.persistence.Column; @@ -66,6 +67,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 06/03/09 2521 D. Hladky Initial release + * 01/27/13 1478 D. Hladky OUN memory help * * * @@ -758,5 +760,39 @@ public class FFMPRecord extends ServerSpecificPersistablePluginDataObject public String getSiteKey() { return siteKey; } + + /** + * Get the fully cache ready object + * @param fileName + * @return + */ + public FFMPAggregateRecord getCacheRecord() { + FFMPAggregateRecord fdcr = new FFMPAggregateRecord(); + + for (Entry entry: basinsMap.entrySet()) { + fdcr.setBasinData(entry.getValue()); + } + + return fdcr; + } + + /** + * Creates and populates a version of this record from a cache record + * + * @param fdcr + */ + public FFMPRecord(FFMPAggregateRecord fdcr) { + + List times = fdcr.getTimes(); + + for (Entry entry : fdcr.getBasinsMap() + .entrySet()) { + + FFMPBasinData fbd = entry.getValue(); + // Keep in mind times can be null, Guidance basins are like that + fbd.populate(times); + setBasinData(fbd, fbd.getHucLevel()); + } + } } diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPVirtualGageBasin.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPVirtualGageBasin.java index 1fa7301a13..2547fa428b 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPVirtualGageBasin.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/FFMPVirtualGageBasin.java @@ -1,13 +1,28 @@ package com.raytheon.uf.common.dataplugin.ffmp; +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ import java.util.Comparator; import java.util.Date; import java.util.TreeMap; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlRootElement; - import com.raytheon.uf.common.serialization.ISerializableObject; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @@ -21,14 +36,13 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 02may10 3937 dhladky Setup + * 01/27/13 1478 dhladky Removed un-needed XML annotations * * * * @author dhladky * @version 1.0 */ -@XmlRootElement -@XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize public class FFMPVirtualGageBasin extends FFMPBasin implements ISerializableObject { diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBin.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBin.java index 940fec8a20..1982944bdb 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBin.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBin.java @@ -1,12 +1,26 @@ package com.raytheon.uf.common.dataplugin.ffmp; +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ import java.util.ArrayList; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - import com.raytheon.uf.common.serialization.ISerializableObject; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @@ -22,28 +36,25 @@ import com.vividsolutions.jts.geom.Coordinate; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 10/22/10 6581 D. Hladky Initial release + * 01/27/13 1478 D. Hladky Removed un needed XML annotations * * * * @author dhladky * @version 1 */ -@XmlRootElement -@XmlAccessorType(XmlAccessType.NONE) + @DynamicSerialize public class SourceBin implements ISerializableObject { /** sourceName and dataKey **/ @DynamicSerializeElement - @XmlElement public double[] lats; @DynamicSerializeElement - @XmlElement public double[] lons; @DynamicSerializeElement - @XmlElement public double[] areaPercent; public SourceBin() { diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBinEntry.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBinEntry.java index 8618eeb16a..1e8ae77c38 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBinEntry.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBinEntry.java @@ -1,24 +1,53 @@ package com.raytheon.uf.common.dataplugin.ffmp; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; import com.vividsolutions.jts.geom.Coordinate; +/** + * FFMP source binning entry object + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * 01/27/13     1478        D. Hladky   Removed un needed XML annotations
+ * 
+ * 
+ * + * @author dhladky + * @version 1 + */ + @DynamicSerialize -@XmlAccessorType(XmlAccessType.NONE) public class SourceBinEntry { /** sourceName and dataKey **/ @DynamicSerializeElement - @XmlElement public Coordinate coor; @DynamicSerializeElement - @XmlElement public double area; public Coordinate getCoor() { diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBinList.java b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBinList.java index d8b2d1b2ac..96bfdff689 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBinList.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.ffmp/src/com/raytheon/uf/common/dataplugin/ffmp/SourceBinList.java @@ -1,12 +1,26 @@ package com.raytheon.uf.common.dataplugin.ffmp; +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ import java.util.HashMap; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - import com.raytheon.uf.common.serialization.ISerializableObject; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @@ -22,24 +36,21 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 10/22/10 6581 D. Hladky Initial release + * 01/27/13 1478 D. Hladky Removed un needed XML annotations * * * * @author dhladky * @version 1 */ -@XmlRootElement -@XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize public class SourceBinList implements ISerializableObject { /** sourceName and dataKey **/ @DynamicSerializeElement - @XmlElement public String sourceId; @DynamicSerializeElement - @XmlElement public HashMap sourceMap; public SourceBinList() { diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.gfe/src/com/raytheon/uf/common/dataplugin/gfe/db/objects/DatabaseID.java b/edexOsgi/com.raytheon.uf.common.dataplugin.gfe/src/com/raytheon/uf/common/dataplugin/gfe/db/objects/DatabaseID.java index 9cdce457d8..3e1e00fb62 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.gfe/src/com/raytheon/uf/common/dataplugin/gfe/db/objects/DatabaseID.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.gfe/src/com/raytheon/uf/common/dataplugin/gfe/db/objects/DatabaseID.java @@ -50,6 +50,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeTypeAdap * 8/19/09 2899 njensen Rewrote equals() for performance * 5/08/12 #600 dgilling Implement clone(). * 6/25/12 #766 dgilling Fix isValid(). + * 01/18/13 #1504 randerso Removed setters since class should be immutable * * * @@ -487,42 +488,6 @@ public class DatabaseID implements Serializable, Comparable, return date; } - public void setSiteId(String siteId) { - this.siteId = siteId; - } - - public void setFormat(DataType format) { - this.format = format; - } - - public void setFormat(String format) { - if (format.equals("GRID")) { - this.format = DataType.GRID; - } else { - this.format = DataType.NONE; - } - } - - public void setDbType(String dbType) { - this.dbType = dbType; - } - - public void setModelName(String modelName) { - this.modelName = modelName; - } - - public void setModelTime(String modelTime) { - this.modelTime = modelTime; - } - - public void setModelId(String modelId) { - this.modelId = modelId.intern(); - } - - public void setShortModelId(String shortModelId) { - this.shortModelId = shortModelId; - } - public Date getModelTimeAsDate() { if (this.modelTime.equals(NO_MODEL_TIME)) { return new Date(0); diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.gfe/src/com/raytheon/uf/common/dataplugin/gfe/db/objects/ParmID.java b/edexOsgi/com.raytheon.uf.common.dataplugin.gfe/src/com/raytheon/uf/common/dataplugin/gfe/db/objects/ParmID.java index 5ad9ff1aeb..e8503c2226 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.gfe/src/com/raytheon/uf/common/dataplugin/gfe/db/objects/ParmID.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.gfe/src/com/raytheon/uf/common/dataplugin/gfe/db/objects/ParmID.java @@ -47,6 +47,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeTypeAdap * ------------ ---------- ----------- -------------------------- * 3/6/08 875 bphillip Initial Creation * 5/8/12 #600 dgilling Implement clone(). + * 01/18/13 #1504 randerso Removed setters since class should be immutable * * * @@ -95,12 +96,7 @@ public class ParmID implements Comparable, Serializable, @Override public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append(parmName).append("_"); - buffer.append(parmLevel).append(":"); - buffer.append(dbId.toString()); - - return buffer.toString(); + return this.parmId; } /* @@ -140,7 +136,6 @@ public class ParmID implements Comparable, Serializable, this.parmName = parmName; this.parmLevel = defaultLevel(); this.dbId = new DatabaseID(parmModel); - this.compositeName = parmName + "_" + defaultLevel(); encodeIdentifier(); } @@ -158,7 +153,6 @@ public class ParmID implements Comparable, Serializable, this.parmName = parmName; this.parmLevel = level; this.dbId = new DatabaseID(parmModel); - this.compositeName = parmName + "_" + level; encodeIdentifier(); } @@ -170,7 +164,6 @@ public class ParmID implements Comparable, Serializable, */ public ParmID(String parmIdentifier) { decodeIdentifier(parmIdentifier); - this.compositeName = this.parmName + "_" + this.parmLevel; encodeIdentifier(); } @@ -186,7 +179,6 @@ public class ParmID implements Comparable, Serializable, this.parmName = parmName; this.parmLevel = defaultLevel(); this.dbId = dbId; - this.compositeName = parmName + "_" + defaultLevel(); encodeIdentifier(); } @@ -204,7 +196,6 @@ public class ParmID implements Comparable, Serializable, this.parmName = parmName; this.parmLevel = level; this.dbId = dbId; - this.compositeName = parmName + "_" + level; encodeIdentifier(); } @@ -333,11 +324,9 @@ public class ParmID implements Comparable, Serializable, */ private void encodeIdentifier() { + this.compositeName = this.parmName + "_" + this.parmLevel; shortParmId = this.compositeName + ":" + dbId.getShortModelId(); - - if (parmId == null || parmId.length() == 0) { - parmId = this.compositeName + ":" + dbId.getModelId(); - } + parmId = this.compositeName + ":" + dbId.getModelId(); } /** @@ -442,30 +431,6 @@ public class ParmID implements Comparable, Serializable, return true; } - public void setParmName(String parmName) { - this.parmName = parmName; - } - - public void setParmLevel(String parmLevel) { - this.parmLevel = parmLevel; - } - - public void setDbId(DatabaseID dbId) { - this.dbId = dbId; - } - - public void setCompositeName(String compositeName) { - this.compositeName = compositeName; - } - - public void setShortParmId(String shortParmId) { - this.shortParmId = shortParmId; - } - - public void setParmId(String parmId) { - this.parmId = parmId; - } - /* * (non-Javadoc) * diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/GeospatialFactory.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/GeospatialFactory.java index faf88b060d..d52333e894 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/GeospatialFactory.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/GeospatialFactory.java @@ -44,6 +44,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; /** @@ -61,7 +62,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; * Apr 11, 2012 #14691 Qinglu Lin For marine warnings, getFeAreaField() returns null. * So, do not add the returned value of getFeAreaField() * to areaFields. - * Jan 9, 2013 15600 Qinglu Lin Execute "timezones = myTimeZones;" even if timezones != null. + * Jan 9, 2013 15600 Qinglu Lin Execute "timezones = myTimeZones;" even if timezones != null. * * * @@ -87,13 +88,12 @@ public class GeospatialFactory { boolean generate = true; if (lastRunTime != null) { System.out.println("Loading areas from disk"); - // load from disk try { long t0 = System.currentTimeMillis(); dataSet = loadAreaGeoData(site, lastRunTime); System.out.println("Loading areas from disk took " - + (System.currentTimeMillis() - t0)); + + (System.currentTimeMillis() - t0) + "ms"); } catch (Exception e) { statusHandler.handle(Priority.WARN, "Failed to load area geometry files from disk", e); @@ -119,7 +119,7 @@ public class GeospatialFactory { GeospatialData[] parentAreas = dataSet.getParentAreas(); GeospatialData[] myTimeZones = dataSet.getTimezones(); if (myTimeZones != null && myTimeZones.length > 0) { - timezones = myTimeZones; + timezones = myTimeZones; for (GeospatialData tz : myTimeZones) { tz.prepGeom = PreparedGeometryFactory.prepare(tz.geometry); @@ -138,7 +138,6 @@ public class GeospatialFactory { list.add(data); } - GeospatialData[] uniqueAreas = new GeospatialData[uniqueAreasMap.size()]; int index = 0; for (String key : uniqueAreasMap.keySet()) { @@ -148,34 +147,15 @@ public class GeospatialFactory { // if multiple areas share a common fips ID, the smaller areas will // have to merge will the largest area if (list.size() > 1) { - double maxArea = -1; - for (GeospatialData item : list) { - double area = item.getGeometry().getArea(); - if (area > maxArea) { - data = item; - maxArea = area; - } - } - - // collect all individual geometries that are not a part - // of the maxArea + // collect all individual geometries List geometries = new ArrayList(); for (GeospatialData item : list) { - if (data != item) { - GeometryUtil.buildGeometryList(geometries, - item.geometry); - } - } - - for (int i = 0; i < geometries.size(); i++) { - // convexHull will remove any side location conflicts - // convexHull the geometries individually because they are - // usually not next to each other. - // data.geometry = data.geometry.union(geometries.get(i) - // .convexHull()); - data.geometry = data.geometry.union(geometries.get(i) - .convexHull()); + GeometryUtil.buildGeometryList(geometries, item.geometry); } + // Create multi geometry out of combined areas + data.geometry = new GeometryFactory() + .createGeometryCollection(geometries + .toArray(new Geometry[0])); } uniqueAreas[index] = data; index++; @@ -204,7 +184,7 @@ public class GeospatialFactory { // Prepare the geometries for (GeospatialData data : areas) { - data.prepGeom = PreparedGeometryFactory.prepare(data.geometry); + data.prepGeom = new PreparedGeometryCollection(data.geometry); } return areas; diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/PreparedGeometryCollection.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/PreparedGeometryCollection.java new file mode 100644 index 0000000000..8b6188438e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/PreparedGeometryCollection.java @@ -0,0 +1,246 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.dataplugin.warning.gis; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.prep.PreparedGeometry; +import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; + +/** + * {@link PreparedGeometry} implementation that can handle + * {@link GeometryCollection} objects + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 28, 2013            mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ + +public class PreparedGeometryCollection implements PreparedGeometry { + + private Geometry geometry; + + private PreparedGeometry[] prepared; + + public PreparedGeometryCollection(Geometry geometry) { + this.geometry = geometry; + int numGeoms = geometry.getNumGeometries(); + if (geometry.getClass() == GeometryCollection.class) { + prepared = new PreparedGeometry[numGeoms]; + for (int i = 0; i < numGeoms; ++i) { + prepared[i] = PreparedGeometryFactory.prepare(geometry + .getGeometryN(i)); + } + } else { + prepared = new PreparedGeometry[] { PreparedGeometryFactory + .prepare(geometry) }; + } + } + + /* + * (non-Javadoc) + * + * @see com.vividsolutions.jts.geom.prep.PreparedGeometry#getGeometry() + */ + @Override + public Geometry getGeometry() { + return geometry; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#contains(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean contains(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.contains(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#containsProperly(com + * .vividsolutions.jts.geom.Geometry) + */ + @Override + public boolean containsProperly(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.containsProperly(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see com.vividsolutions.jts.geom.prep.PreparedGeometry#coveredBy(com. + * vividsolutions.jts.geom.Geometry) + */ + @Override + public boolean coveredBy(Geometry geom) { + boolean coveredBy = true; + for (PreparedGeometry pg : prepared) { + if (pg.coveredBy(geom) == false) { + coveredBy = false; + break; + } + } + return coveredBy; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#covers(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean covers(Geometry geom) { + throw new UnsupportedOperationException( + "PreparedGeometryCollection does not support PreparedGeometry.covers"); + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#crosses(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean crosses(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.crosses(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#disjoint(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean disjoint(Geometry geom) { + boolean disjoint = true; + for (PreparedGeometry pg : prepared) { + if (pg.disjoint(geom) == false) { + disjoint = false; + break; + } + } + return disjoint; + } + + /* + * (non-Javadoc) + * + * @see com.vividsolutions.jts.geom.prep.PreparedGeometry#intersects(com. + * vividsolutions.jts.geom.Geometry) + */ + @Override + public boolean intersects(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.intersects(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#overlaps(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean overlaps(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.overlaps(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#touches(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean touches(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.touches(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#within(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean within(Geometry geom) { + boolean within = true; + for (PreparedGeometry pg : prepared) { + if (pg.within(geom) == false) { + within = false; + break; + } + } + return within; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/util/GeometryUtil.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/util/GeometryUtil.java index 0ce2c7f5f2..a3765c3876 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/util/GeometryUtil.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/util/GeometryUtil.java @@ -1,24 +1,38 @@ package com.raytheon.uf.common.dataplugin.warning.util; import java.util.ArrayList; -import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; -import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Polygon; -import com.vividsolutions.jts.geom.TopologyException; import com.vividsolutions.jts.geom.prep.PreparedGeometry; import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; import com.vividsolutions.jts.operation.overlay.snap.GeometrySnapper; -import com.vividsolutions.jts.operation.polygonize.Polygonizer; +/** + * + * Performs common geometry operations taking geometry collections into + * account for counties. Makes certain assumptions about these geometries that + * only apply to warngen + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 15, 2010            mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ public class GeometryUtil { private static final String SEPARATOR = "_"; @@ -41,7 +55,7 @@ public class GeometryUtil { } for (int i = 0; i < list1.size(); ++i) { - if (list1.get(i).buffer(0).equals(list2.get(i).buffer(0)) == false) { + if (list1.get(i).equals(list2.get(i)) == false) { return false; } } @@ -190,12 +204,15 @@ public class GeometryUtil { } if ((g1Name == null || g2Name == null || g2Name .startsWith(prefix))) { - Geometry section = g1.intersection(g2); - if (section.isEmpty() == false) { - section = section.buffer(0); - setUserData(section, (CountyUserData) g2.getUserData()); - section.setUserData(g2.getUserData()); - intersections.add(section); + if (g1.isValid() && g2.isValid()) { + Geometry section = g1.intersection(g2); + if (section.isEmpty() == false) { + section = section.buffer(0); + setUserData(section, + (CountyUserData) g2.getUserData()); + section.setUserData(g2.getUserData()); + intersections.add(section); + } } } } @@ -209,64 +226,31 @@ public class GeometryUtil { intersection(g1.getGeometryN(i), pg, intersections); } } else { - Geometry g2 = pg.getGeometry(); - String g1Name = toString(g1.getUserData()); - String g2Name = toString(g2.getUserData()); - String prefix = null; - if (g1Name != null && g2Name != null) { - prefix = getPrefix(g1Name); - } - if (g1Name == null || g2Name == null || g2Name.startsWith(prefix)) { - if (pg.intersects(g1)) { - Geometry section = null; - try { - section = g1.intersection(g2); - } catch (TopologyException e) { - // This exception is due to g2 having interior - // intersections - section = clean(g1).intersection(g2.buffer(0)); - } - - if (section != null) { - setUserData(section, (CountyUserData) g2.getUserData()); - section.setUserData(g2.getUserData()); - intersections.add(section); + if (pg.intersects(g1)) { + Geometry g2 = pg.getGeometry(); + List sections = new ArrayList(); + for (int n = 0; n < g2.getNumGeometries(); n++) { + Geometry section = g1.intersection(g2.getGeometryN(n)); + if (section.isEmpty() == false) { + sections.add(section); } } + Geometry section = null; + if (sections.size() == 1) { + section = sections.get(0); + } else if (sections.size() > 0) { + section = new GeometryFactory() + .createGeometryCollection(sections + .toArray(new Geometry[0])); + } + if (section != null && section.isEmpty() == false) { + setUserData(section, (CountyUserData) g2.getUserData()); + intersections.add(section); + } } } } - /** - * Returns a geometry from the noded line strings of g. - * - * @param g - * geometry to be cleaned up - * @return - */ - private static Geometry clean(Geometry g) { - Coordinate[] coords = g.getCoordinates(); - - // create a line string - GeometryFactory gf = new GeometryFactory(); - LineString ls = gf.createLineString(coords); - - // node the line string (insert vertices where lines cross) - com.vividsolutions.jts.geom.Point pt = gf.createPoint(ls - .getCoordinate()); - Geometry nodedLines = ls.union(pt); - - // create the polygon(s) from the noded line - Polygonizer polygonizer = new Polygonizer(); - polygonizer.add(nodedLines); - Collection polygons = polygonizer.getPolygons(); - - g = gf.createMultiPolygon( - polygons.toArray(new Polygon[polygons.size()])).buffer(0); - - return g; - } - /** * Get the difference between the 2 geometries * diff --git a/edexOsgi/com.raytheon.uf.common.dataquery/src/com/raytheon/uf/common/dataquery/responses/DbQueryResponse.java b/edexOsgi/com.raytheon.uf.common.dataquery/src/com/raytheon/uf/common/dataquery/responses/DbQueryResponse.java index 8d60a25624..62fcae6ef6 100644 --- a/edexOsgi/com.raytheon.uf.common.dataquery/src/com/raytheon/uf/common/dataquery/responses/DbQueryResponse.java +++ b/edexOsgi/com.raytheon.uf.common.dataquery/src/com/raytheon/uf/common/dataquery/responses/DbQueryResponse.java @@ -19,6 +19,8 @@ **/ package com.raytheon.uf.common.dataquery.responses; +import java.lang.reflect.Array; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -47,15 +49,31 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @DynamicSerialize public class DbQueryResponse implements ISerializableObject { + public static final String ENTITY_RESULT_KEY = null; + @DynamicSerializeElement private List> results; public List> getResults() { - return results; + return results == null ? new ArrayList>() : results; } public void setResults(List> results) { this.results = results; } + public int getNumResults() { + return getResults().size(); + } + + @SuppressWarnings("unchecked") + public T[] getEntityObjects(Class entityType) { + List> results = getResults(); + T[] entities = (T[]) Array.newInstance(entityType, results.size()); + int i = 0; + for (Map result : results) { + entities[i++] = entityType.cast(result.get(ENTITY_RESULT_KEY)); + } + return entities; + } } diff --git a/edexOsgi/com.raytheon.uf.common.localization/src/com/raytheon/uf/common/localization/LocalizationFile.java b/edexOsgi/com.raytheon.uf.common.localization/src/com/raytheon/uf/common/localization/LocalizationFile.java index 811ccdc6f1..08b78508a8 100644 --- a/edexOsgi/com.raytheon.uf.common.localization/src/com/raytheon/uf/common/localization/LocalizationFile.java +++ b/edexOsgi/com.raytheon.uf.common.localization/src/com/raytheon/uf/common/localization/LocalizationFile.java @@ -29,6 +29,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import javax.xml.bind.JAXBException; + import com.raytheon.uf.common.localization.FileLocker.Type; import com.raytheon.uf.common.localization.ILocalizationAdapter.ListResponse; import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel; @@ -80,6 +82,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority; * This was added as part of an effort to improve * localization performance but caused updated * files on the server not to be retrieved. + * Jan 17, 2013 1412 djohnson Add jaxbMarshal. * * * @author njensen @@ -635,6 +638,25 @@ public final class LocalizationFile implements Comparable { return null; } + /** + * Marshal the specified object into this file. + * + * @param obj + * the object to marshal + * + * @param jaxbManager + * the jaxbManager + */ + public void jaxbMarshal(Object obj, JAXBManager jaxbManager) throws LocalizationException{ + try { + String xml = jaxbManager.marshalToXml(obj); + write(xml.getBytes()); + } catch (JAXBException e) { + throw new LocalizationException( + "Unable to marshal the object to the file.", e); + } + } + @Override public String toString() { return context + IPathManager.SEPARATOR + path; diff --git a/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/META-INF/MANIFEST.MF index 76e9413bb9..57095e23d0 100644 --- a/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/META-INF/MANIFEST.MF @@ -10,7 +10,8 @@ Require-Bundle: com.raytheon.uf.common.serialization;bundle-version="1.12.2", com.raytheon.uf.common.auth;bundle-version="1.12.1174", com.raytheon.uf.common.status;bundle-version="1.12.1174", com.raytheon.uf.common.localization;bundle-version="1.12.1174", - com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174" + com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174", + org.apache.commons.lang;bundle-version="2.3.0" Export-Package: com.raytheon.uf.common.plugin.nwsauth, com.raytheon.uf.common.plugin.nwsauth.exception, com.raytheon.uf.common.plugin.nwsauth.user, diff --git a/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/NwsRoleData.java b/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/NwsRoleData.java index 6dd1df05b6..8194b50017 100644 --- a/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/NwsRoleData.java +++ b/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/NwsRoleData.java @@ -302,4 +302,21 @@ public class NwsRoleData implements ISerializableObject { return false; } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Application:").append(this.getApplication()).append("\n\n"); + sb.append("Users:\n").append(this.getUserList()).append("\n\n"); + sb.append("Permissions:\n").append(this.getPermissionList()) + .append("\n\n"); + sb.append("Roles:\n").append(this.getRoleList()).append("\n\n"); + + return sb.toString(); + } } diff --git a/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/PermissionXML.java b/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/PermissionXML.java index 824f9af8de..1966f492ea 100644 --- a/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/PermissionXML.java +++ b/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/PermissionXML.java @@ -94,4 +94,16 @@ public class PermissionXML implements ISerializableObject { public void setDescription(String description) { this.description = (description == null) ? null : description.trim(); } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("id:").append(this.getId()); + sb.append("\ndescription:").append(this.getDescription()); + + return sb.toString(); + } } diff --git a/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/RoleXML.java b/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/RoleXML.java index d17db43ea3..5802aa8118 100644 --- a/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/RoleXML.java +++ b/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/RoleXML.java @@ -117,4 +117,19 @@ public class RoleXML implements ISerializableObject { public void addPermission(String permission) { this.permissionList.add(permission); } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("roleId:").append(this.getRoleId()); + sb.append("\nroleDescription:").append(this.getRoleDescription()); + sb.append("\npermissionList:").append(this.getPermissionList()); + + return sb.toString(); + } } diff --git a/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/UserXML.java b/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/UserXML.java index aa8089901e..61f9a5d19e 100644 --- a/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/UserXML.java +++ b/edexOsgi/com.raytheon.uf.common.plugin.nwsauth/src/com/raytheon/uf/common/plugin/nwsauth/xml/UserXML.java @@ -28,6 +28,9 @@ import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElements; +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; + import com.raytheon.uf.common.auth.user.IAuthenticationData; import com.raytheon.uf.common.auth.user.IUser; import com.raytheon.uf.common.auth.user.IUserId; @@ -66,6 +69,17 @@ public class UserXML implements IUser, ISerializableObject { @XmlElements({ @XmlElement(name = "userRole", type = String.class) }) private List roleList = new ArrayList(); + public UserXML() { + + } + + /** + * @param userId + */ + public UserXML(String userId) { + setUserId(userId); + } + /** * @return the userId */ @@ -129,6 +143,30 @@ public class UserXML implements IUser, ISerializableObject { } } + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof UserXML) { + UserXML that = (UserXML) obj; + + EqualsBuilder builder = new EqualsBuilder(); + builder.append(this.getUserId(), that.getUserId()); + return builder.isEquals(); + + } + return super.equals(obj); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return new HashCodeBuilder().append(this.getUserId()).toHashCode(); + } + /* * (non-Javadoc) * @@ -136,17 +174,10 @@ public class UserXML implements IUser, ISerializableObject { */ @Override public String toString() { - final String nl = "\n"; StringBuilder sb = new StringBuilder(); - sb.append(this.getUserId()).append(nl); - - for (String role : this.roleList) { - sb.append(" ").append(role).append(nl); - } - - for (String perm : permissionList) { - sb.append(" ").append(perm).append(nl); - } + sb.append("userId:").append(this.getUserId()); + sb.append("\nroles:").append(this.getRoleList()); + sb.append("\npermissions:").append(this.getPermissionList()); return sb.toString(); } diff --git a/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/ExtensibleObjectType.java b/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/ExtensibleObjectType.java index 85ed507ab1..4907aeac36 100644 --- a/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/ExtensibleObjectType.java +++ b/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/ExtensibleObjectType.java @@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; +import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; @@ -39,6 +40,7 @@ import oasis.names.tc.ebxml.regrep.xsd.rs.v4.RegistryExceptionType; import oasis.names.tc.ebxml.regrep.xsd.rs.v4.RegistryRequestType; import oasis.names.tc.ebxml.regrep.xsd.rs.v4.RegistryResponseType; +import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; @@ -82,10 +84,11 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; RegistryResponseType.class, RegistryRequestType.class }) @DynamicSerialize @MappedSuperclass -@Cache(region="registryObjects",usage = CacheConcurrencyStrategy.TRANSACTIONAL, include = "all") +@Cache(region = "registryObjects", usage = CacheConcurrencyStrategy.TRANSACTIONAL, include = "all") public abstract class ExtensibleObjectType { - @ManyToMany(cascade = CascadeType.ALL) + @BatchSize(size = 500) + @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinTable(inverseJoinColumns = @JoinColumn(name = "child_slot_key")) @XmlElement(name = "Slot") @DynamicSerializeElement diff --git a/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/RegistryObjectType.java b/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/RegistryObjectType.java index ddffcce84f..5e566b091f 100644 --- a/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/RegistryObjectType.java +++ b/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/RegistryObjectType.java @@ -100,45 +100,45 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; RoleType.class }) @DynamicSerialize @Entity -@Cache(region="registryObjects",usage = CacheConcurrencyStrategy.TRANSACTIONAL, include = "all") +@Cache(region = "registryObjects", usage = CacheConcurrencyStrategy.TRANSACTIONAL, include = "all") @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @Table(name = "RegistryObject") public class RegistryObjectType extends IdentifiableType { @XmlElement(name = "Name") @DynamicSerializeElement - @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) protected InternationalStringType name; @XmlElement(name = "Description") @DynamicSerializeElement - @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) protected InternationalStringType description; @XmlElement(name = "VersionInfo") @DynamicSerializeElement @Cascade(value = { org.hibernate.annotations.CascadeType.DETACH }) - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) protected VersionInfoType versionInfo; @XmlElement(name = "Classification") @DynamicSerializeElement @Cascade(value = { org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DETACH }) - @ManyToMany + @ManyToMany(fetch = FetchType.LAZY) protected Set classification; @XmlElement(name = "ExternalIdentifier") @DynamicSerializeElement @Cascade(value = { org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DETACH }) - @ManyToMany + @ManyToMany(fetch = FetchType.LAZY) protected Set externalIdentifier; @XmlElement(name = "ExternalLink") @DynamicSerializeElement @Cascade(value = { org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DETACH }) - @ManyToMany + @ManyToMany(fetch = FetchType.LAZY) protected Set externalLink; @XmlAttribute diff --git a/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/SlotType.java b/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/SlotType.java index b006e5d63b..b3416a82e8 100644 --- a/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/SlotType.java +++ b/edexOsgi/com.raytheon.uf.common.registry.schemas.ebxml/src/oasis/names/tc/ebxml/regrep/xsd/rim/v4/SlotType.java @@ -24,6 +24,7 @@ import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; @@ -83,7 +84,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; // "slot_join_slot", joinColumns = @JoinColumn(name = "parent_slot_key", // referencedColumnName = "key"), inverseJoinColumns = @JoinColumn(name = // "child_slot_key", referencedColumnName = "key"))) -@Cache(region="registryObjects",usage = CacheConcurrencyStrategy.TRANSACTIONAL, include = "all") +@Cache(region = "registryObjects", usage = CacheConcurrencyStrategy.TRANSACTIONAL, include = "all") @Table(name = "Slot") public class SlotType extends ExtensibleObjectType implements Serializable { @@ -94,7 +95,7 @@ public class SlotType extends ExtensibleObjectType implements Serializable { @XmlTransient private Integer key; - @ManyToOne(cascade = CascadeType.ALL) + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @XmlElement(name = "SlotValue") @DynamicSerializeElement protected ValueType slotValue; diff --git a/edexOsgi/com.raytheon.uf.common.stats/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.stats/META-INF/MANIFEST.MF index 81c3d897a6..3ecb4c506e 100644 --- a/edexOsgi/com.raytheon.uf.common.stats/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.stats/META-INF/MANIFEST.MF @@ -17,4 +17,6 @@ Require-Bundle: com.raytheon.uf.common.time;bundle-version="1.12.1174", com.raytheon.uf.common.event;bundle-version="1.0.0", com.google.guava;bundle-version="1.0.0", com.raytheon.uf.common.util;bundle-version="1.12.1174", - com.raytheon.uf.common.status;bundle-version="1.12.1174" + com.raytheon.uf.common.status;bundle-version="1.12.1174", + javax.measure;bundle-version="1.0.0", + com.raytheon.uf.common.units;bundle-version="1.0.0" diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/AggregateRecord.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/AggregateRecord.java index fba2d6127d..9ffbc05a71 100644 --- a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/AggregateRecord.java +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/AggregateRecord.java @@ -37,17 +37,18 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; /** * Record class for an aggregate result. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Aug 21, 2012            jsanchez     Initial creation
  * Nov 12, 2012            dhladky      Updates some things for stats
- *
+ * Jan 15, 2013 1487       djohnson     Increase length of grouping to 1024.
+ * 
  * 
- * + * * @author jsanchez * @version 1.0 */ @@ -56,7 +57,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize -public class AggregateRecord extends PersistableDataObject { +public class AggregateRecord extends PersistableDataObject { private static final long serialVersionUID = -4553588456131256014L; @GeneratedValue(strategy = GenerationType.AUTO) @@ -77,6 +78,7 @@ public class AggregateRecord extends PersistableDataObject { private String eventType; @DynamicSerializeElement + @Column(length = 1024) private String grouping; @Column(nullable = false) diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/GraphDataRequest.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/GraphDataRequest.java index 340fb9ff9b..0803581c90 100644 --- a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/GraphDataRequest.java +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/GraphDataRequest.java @@ -36,6 +36,7 @@ import com.raytheon.uf.common.time.TimeRange; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Sep 11, 2012 728 mpduff Initial creation + * Jan 17, 2013 1357 mpudff Javadoc update. * * * @@ -139,6 +140,8 @@ public class GraphDataRequest implements IServerRequest { } /** + * The time step of the data in minutes. + * * @param timeStep * the timeStep to set */ @@ -147,6 +150,8 @@ public class GraphDataRequest implements IServerRequest { } /** + * Get the time step in minute. + * * @return the timeStep */ public int getTimeStep() { diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/StatsGrouping.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/StatsGrouping.java new file mode 100644 index 0000000000..3995883cbc --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/StatsGrouping.java @@ -0,0 +1,101 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.stats; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Contains a grouping for statistics. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 15, 2013 1487       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class StatsGrouping { + + @XmlAttribute(required = true) + private String name; + + @XmlAttribute(required = true) + private String value; + + /** + * Constructor. + */ + public StatsGrouping() { + this(null, null); + } + + /** + * Constructor. + * + * @param name + * @param value + */ + public StatsGrouping(String name, String value) { + this.name = name; + this.value = value; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the value + */ + public String getValue() { + return value; + } + + /** + * @param value + * the value to set + */ + public void setValue(String value) { + this.value = value; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/StatsGroupingColumn.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/StatsGroupingColumn.java new file mode 100644 index 0000000000..b63902407a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/StatsGroupingColumn.java @@ -0,0 +1,87 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.stats; + +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import com.google.common.collect.Lists; + +/** + * Contains a list of groupings for statistics. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 15, 2013 1487       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@XmlRootElement(name = "stat") +@XmlAccessorType(XmlAccessType.NONE) +public class StatsGroupingColumn { + + @XmlElement + private List group = Lists.newArrayList(); + + /** + * @return the group + */ + public List getGroup() { + return group; + } + + /** + * @param group + * the group to set + */ + public void setGroup(List group) { + this.group = group; + } + + /** + * Create a {@link StatsGroupingColumn} to hold the specified + * {@link StatsGrouping} instances. + * + * @param statsGroupings + * the groupings + * @return the column + */ + public static StatsGroupingColumn withGroupings( + StatsGrouping... statsGroupings) { + StatsGroupingColumn column = new StatsGroupingColumn(); + + for (StatsGrouping grouping : statsGroupings) { + column.group.add(grouping); + } + + return column; + } +} diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/DataPoint.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/DataPoint.java index 569bd719cd..4173991538 100644 --- a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/DataPoint.java +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/DataPoint.java @@ -20,10 +20,6 @@ package com.raytheon.uf.common.stats.data; import java.math.BigDecimal; -import java.text.DecimalFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -31,7 +27,8 @@ import javax.xml.bind.annotation.XmlRootElement; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; -import com.raytheon.uf.common.stats.util.DataViewUtils; +import com.raytheon.uf.common.stats.util.DataView; +import com.raytheon.uf.common.stats.util.UnitUtils.UnitTypes; /** * Class holding an x,y data point and other associated information for the @@ -43,7 +40,8 @@ import com.raytheon.uf.common.stats.util.DataViewUtils; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Sep 7, 2012 mpduff Initial creation + * Sep 7, 2012 mpduff Initial creation + * Jan 17, 2013 1357 mpduff Moved sample code out of this class. * * * @@ -55,37 +53,12 @@ import com.raytheon.uf.common.stats.util.DataViewUtils; @XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize public class DataPoint implements Comparable { - /** Date Format object */ - private final ThreadLocal sdf = new ThreadLocal() { - @Override - protected SimpleDateFormat initialValue() { - SimpleDateFormat sTemp = new SimpleDateFormat("MM/dd/yyyy HH:mm"); - sTemp.setTimeZone(TimeZone.getTimeZone("GMT")); - return sTemp; - } - }; - - /** Decimal Format object */ - private final ThreadLocal decFormat = new ThreadLocal() { - @Override - protected DecimalFormat initialValue() { - DecimalFormat format = new DecimalFormat("########.#"); - return format; - } - }; - /** * X value - millis */ @DynamicSerializeElement private long x; - /** - * Text display for the sampling of this point - */ - @DynamicSerializeElement - protected String sampleText; - /** Min value */ @DynamicSerializeElement private BigDecimal min = new BigDecimal(Integer.MAX_VALUE); @@ -102,6 +75,9 @@ public class DataPoint implements Comparable { @DynamicSerializeElement private BigDecimal sum = new BigDecimal(0); + @DynamicSerializeElement + private UnitTypes unitType; + /** Constructor */ public DataPoint() { sum = sum.setScale(1, BigDecimal.ROUND_HALF_UP); @@ -110,27 +86,6 @@ public class DataPoint implements Comparable { count = count.setScale(1, BigDecimal.ROUND_HALF_UP); } - /** - * @param sampleText - * the sampleText to set - */ - public void setSampleText(String sampleText) { - this.sampleText = sampleText; - } - - /** - * Get the sample text for this point object - * - * @return the sample text string - */ - public String getSampleText(String view) { - SimpleDateFormat dateFormat = sdf.get(); - DecimalFormat decimalFormat = decFormat.get(); - - return dateFormat.format(new Date(x)) + "Z, " - + decimalFormat.format(getValue(view)); - } - /** * @param x * the x to set @@ -258,20 +213,35 @@ public class DataPoint implements Comparable { return 0; } + /** + * @return the unitType + */ + public UnitTypes getUnitType() { + return unitType; + } + + /** + * @param unitType + * the unitType to set + */ + public void setUnitType(UnitTypes unitType) { + this.unitType = unitType; + } + /** * Get the value for the provided data view type. * * @param view * the view type */ - public double getValue(String view) { - if (view.equals(DataViewUtils.DataView.AVG.getView())) { + public double getValue(DataView view) { + if (view.equals(DataView.AVG)) { return getAvg(); - } else if (view.equals(DataViewUtils.DataView.MIN.getView())) { + } else if (view.equals(DataView.MIN)) { return getMin(); - } else if (view.equals(DataViewUtils.DataView.MAX.getView())) { + } else if (view.equals(DataView.MAX)) { return getMax(); - } else if (view.equals(DataViewUtils.DataView.SUM.getView())) { + } else if (view.equals(DataView.SUM)) { return getSum(); } else { return getCount(); diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/GraphData.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/GraphData.java index c05481534f..9e13e54f5a 100644 --- a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/GraphData.java +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/GraphData.java @@ -33,7 +33,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; import com.raytheon.uf.common.stats.AggregateRecord; import com.raytheon.uf.common.stats.StatisticsEvent; -import com.raytheon.uf.common.stats.util.UnitUtils; +import com.raytheon.uf.common.stats.util.DataView; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; @@ -43,17 +43,18 @@ import com.raytheon.uf.common.util.ReflectionUtil; /** * Data object for the statistics graph. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Oct 3, 2012     728     mpduff      Initial creation
- *
+ * Oct 03, 2012    728     mpduff      Initial creation
+ * Jan 17, 2013   1357     mpduff      Add timestep.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -96,8 +97,17 @@ public class GraphData { @DynamicSerializeElement private String displayUnit; - /** UnitUtils object */ - private UnitUtils unitUtils; + /** Timestep value */ + @DynamicSerializeElement + private long timeStep; + + /** Event Type value */ + @DynamicSerializeElement + private String eventType; + + /** Data Type value */ + @DynamicSerializeElement + private String dataType; /** * Constructor. @@ -130,7 +140,7 @@ public class GraphData { /** * Add an AggregateRecord. - * + * * @param record */ public void addRecord(AggregateRecord record) { @@ -148,7 +158,7 @@ public class GraphData { /** * Get a list of group memebers. - * + * * @return */ public List getGroupMembers() { @@ -160,7 +170,7 @@ public class GraphData { /** * Get the smallest value in the data set. - * + * * @return */ public double getMinValue() { @@ -177,7 +187,7 @@ public class GraphData { /** * Get the largest value in the data set. - * + * * @return */ public double getMaxValue() { @@ -194,10 +204,10 @@ public class GraphData { /** * Get the smallest value in the data set. - * + * * @return */ - public double getMinValue(Set visibleDataSet, String view) { + public double getMinValue(Set visibleDataSet, DataView view) { if (visibleDataSet.isEmpty()) { return 0; } @@ -217,10 +227,10 @@ public class GraphData { /** * Get the largest value in the data set. - * + * * @return */ - public double getMaxValue(Set visibleDataSet, String view) { + public double getMaxValue(Set visibleDataSet, DataView view) { if (visibleDataSet.isEmpty()) { return 1; } @@ -239,7 +249,7 @@ public class GraphData { /** * Get the time range for this object. - * + * * @return */ public TimeRange getTimeRange() { @@ -248,7 +258,7 @@ public class GraphData { /** * Set the TimeRange - * + * * @param timeRange */ public void setTimeRange(TimeRange timeRange) { @@ -257,7 +267,7 @@ public class GraphData { /** * Set the key sequence - * + * * @param keySequence */ public void setKeySequence(List keySequence) { @@ -270,7 +280,7 @@ public class GraphData { /** * Get the key sequence. - * + * * @return */ public List getKeySequence() { @@ -279,7 +289,7 @@ public class GraphData { /** * Get a list of all keys. - * + * * @return the keys */ public List getKeys() { @@ -288,7 +298,7 @@ public class GraphData { /** * Get a list of keys that contain data. - * + * * @return the keys with data */ public List getKeysWithData() { @@ -305,7 +315,7 @@ public class GraphData { /** * Set the StatsLabelData object - * + * * @param statsLabelData */ public void setStatsLabelData(StatsLabelData statsLabelData) { @@ -315,7 +325,7 @@ public class GraphData { /** * Get the StatsLabelData - * + * * @return */ public StatsLabelData getStatsLabelData() { @@ -324,7 +334,7 @@ public class GraphData { /** * Get the group and names map. - * + * * @return */ public Map> getGroupAndNamesMap() { @@ -333,12 +343,12 @@ public class GraphData { /** * Get the units from the event object - * + * * @param eventId * Event id * @param field * data field - * + * * @return The units */ @VisibleForTesting @@ -397,7 +407,7 @@ public class GraphData { /** * Set the StatsData map. - * + * * @param statsDataMap */ public void setStatsDataMap(Map statsDataMap) { @@ -405,18 +415,47 @@ public class GraphData { } /** - * @return the unitUtils + * @return the timeStep */ - public UnitUtils getUnitUtils() { - return unitUtils; + public long getTimeStep() { + return timeStep; } /** - * @param unitUtils - * the unitUtils to set + * @param timeStep + * the timeStep to set */ - public void setUnitUtils(UnitUtils unitUtils) { - this.unitUtils = unitUtils; - this.unitUtils.setConversion(this.getMaxValue()); + public void setTimeStep(long timeStep) { + this.timeStep = timeStep; + } + + /** + * @return the eventType + */ + public String getEventType() { + return eventType; + } + + /** + * @param eventType + * the eventType to set + */ + public void setEventType(String eventType) { + this.eventType = eventType; + } + + /** + * @return the dataType + */ + public String getDataType() { + return dataType; + } + + /** + * @param dataType + * the dataType to set + */ + public void setDataType(String dataType) { + this.dataType = dataType; } } diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsBin.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsBin.java index b06266cf9f..5174931dd4 100644 --- a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsBin.java +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsBin.java @@ -28,17 +28,18 @@ import com.raytheon.uf.common.stats.AggregateRecord; /** * A bin of Statistical data. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Sep 11, 2012   723      mpduff      Initial creation
- *
+ * Sep 11, 2012   723      mpduff      Initial creation.
+ * Jan 17, 2013  1357      mpduff      Change method name.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -57,6 +58,17 @@ public class StatsBin { } + /** + * Copy constructor. + * + * @param bin + * The StatsBin object to copy + */ + public StatsBin(StatsBin bin) { + this.setBinMillis(bin.getBinMillis()); + data.addAll(bin.getData()); + } + /** * @return the binMillis */ @@ -74,16 +86,16 @@ public class StatsBin { /** * Add an AggregateRecord object. - * + * * @param record */ - public void setData(AggregateRecord record) { + public void addData(AggregateRecord record) { this.data.add(record); } /** * Get the AggregateRecord objects - * + * * @return */ public List getData() { diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsData.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsData.java index 2b4dc162ff..5481057de8 100644 --- a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsData.java +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsData.java @@ -32,22 +32,23 @@ import javax.xml.bind.annotation.XmlRootElement; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; import com.raytheon.uf.common.stats.AggregateRecord; -import com.raytheon.uf.common.stats.util.UnitUtils; +import com.raytheon.uf.common.stats.util.DataView; import com.raytheon.uf.common.time.TimeRange; /** * Statistical data object holding data to be graphed. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Sep 07, 2012    728     mpduff      Initial creation
- *
+ * Sep 07, 2012    728     mpduff      Initial creation.
+ * Jan 17, 2013   1357     mpduff      Store data in raw units, not converted.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -84,9 +85,6 @@ public class StatsData { @DynamicSerializeElement private Map bins; - /** UnitUtils object */ - private UnitUtils unitUtils; - /** Constructor */ public StatsData() { @@ -94,7 +92,7 @@ public class StatsData { /** * Constructor - * + * * @param key * Key to the object * @param tsMillis @@ -104,12 +102,10 @@ public class StatsData { * @param unitUtils * UnitUtils object */ - public StatsData(String key, long tsMillis, TimeRange timeRange, - UnitUtils unitUtils) { + public StatsData(String key, long tsMillis, TimeRange timeRange) { this.key = key; this.dataFrequency = (int) tsMillis; this.timeRange = timeRange; - this.unitUtils = unitUtils; } /** @@ -130,7 +126,7 @@ public class StatsData { /** * @return the minValue */ - public Double getMinValue(String view) { + public Double getMinValue(DataView view) { double minValue = Integer.MAX_VALUE; for (DataPoint point : pointList) { @@ -145,7 +141,7 @@ public class StatsData { /** * @return the minValue */ - public Double getMaxValue(String view) { + public Double getMaxValue(DataView view) { double maxValue = Integer.MIN_VALUE; for (DataPoint point : pointList) { @@ -189,7 +185,7 @@ public class StatsData { /** * Get the list of DataPoint objects for the key. - * + * * @param key * The key * @return List of DataPoint objects @@ -216,7 +212,7 @@ public class StatsData { /** * Add an AggregateRecord. - * + * * @param rec * the record to add */ @@ -226,7 +222,7 @@ public class StatsData { /** * Get the key - * + * * @return */ public String getKey() { @@ -235,7 +231,7 @@ public class StatsData { /** * Set the key - * + * * @param key * the key to set */ @@ -245,7 +241,7 @@ public class StatsData { /** * Set the StatsBin object map. - * + * * @param bins */ public void setBins(Map bins) { @@ -263,7 +259,7 @@ public class StatsData { long start = startDate.getTime(); long bin = getBinKey(start); if (bins.get(bin) != null) { - bins.get(bin).setData(record); + bins.get(bin).addData(record); } } @@ -272,13 +268,11 @@ public class StatsData { /** * Create the points for this key. - * + * * @param dataKey */ private void createPoints() { // Bins are created, now make the graph group member and point objects - // convert the data values before storing in the data object - double conversion = unitUtils.getConversion(); for (long key : bins.keySet()) { StatsBin sb = bins.get(key); List dataList = sb.getData(); @@ -288,9 +282,9 @@ public class StatsData { for (AggregateRecord rec : dataList) { // Check for an existing point object - point.setMax(rec.getMax() / conversion); - point.setMin(rec.getMin() / conversion); - point.setSum(rec.getSum() / conversion); + point.setMax(rec.getMax()); + point.setMin(rec.getMin()); + point.setSum(rec.getSum()); point.addToCount(rec.getCount()); } @@ -301,7 +295,7 @@ public class StatsData { /** * Get the bin key for the given millisecond value. - * + * * @param millis * The millisecond value * @return The bin that should hold this millisecond value diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsEventData.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsEventData.java index c7351576bd..f33f0be176 100644 --- a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsEventData.java +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/data/StatsEventData.java @@ -26,17 +26,18 @@ import java.util.Map; /** * Stats Event helper object. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Nov 8, 2012    728      mpduff      Initial creation
- *
+ * Nov 08, 2012    728     mpduff      Initial creation.
+ * Jan 23, 2013   1523     mpduff      Fix list length.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -136,7 +137,7 @@ public class StatsEventData { /** * Get the group list - * + * * @return */ public String[] getGroups() { @@ -145,16 +146,16 @@ public class StatsEventData { /** * Get the attribute list - * + * * @return */ public String[] getAttributes() { - return attributeList.toArray(new String[groupList.size()]); + return attributeList.toArray(new String[attributeList.size()]); } /** * Get the group name from the display name. - * + * * @param displayName * @return */ diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/DataView.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/DataView.java new file mode 100644 index 0000000000..73ba4e3300 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/DataView.java @@ -0,0 +1,77 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.stats.util; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.raytheon.uf.common.units.DataSizeUnit; + +/** + * Data view enumeration. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 18, 2013    1357    mpduff      Moved to its own file.
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public enum DataView { + AVG("Average"), MIN("Minimum"), MAX("Maximum"), SUM("Sum"), COUNT("Count"); + + private final String view; + + private DataView(String view) { + this.view = view; + } + + public String getView() { + return view; + } + + private static final Map LOOKUP_MAP; + static { + Map map = new HashMap(); + for (DataView view : DataView.values()) { + map.put(view.getView(), view); + } + LOOKUP_MAP = Collections.unmodifiableMap(map); + } + + /** + * Retrieve the {@link DataSizeUnit} for its string representation. + * + * @param asString + * @return + */ + public static DataView fromString(String asString) { + return LOOKUP_MAP.get(asString); + } + +} \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/UnitUtils.java b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/UnitUtils.java index 3369c245a6..0dbb319678 100644 --- a/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/UnitUtils.java +++ b/edexOsgi/com.raytheon.uf.common.stats/src/com/raytheon/uf/common/stats/util/UnitUtils.java @@ -19,125 +19,113 @@ **/ package com.raytheon.uf.common.stats.util; +import java.util.Collections; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; +import com.google.common.annotations.VisibleForTesting; import com.raytheon.uf.common.serialization.ISerializableObject; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; -import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.common.units.DataSizeUnit; /** * Utility class for data size conversions. KB vs MB vs GB - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Nov 14, 2012    728     mpduff      Initial creation.
- *
+ * Jan 17, 2013   1357     mpduff      Refactored to use DataSizeUnit and TimeUnit.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @DynamicSerialize public class UnitUtils implements ISerializableObject { - /** Bytes per Kilobyte */ - private static final double BYTES_PER_KILOBYTE = 1024.0; - /** Different unit types for statistics */ public static enum UnitTypes { DATA_SIZE, TIME, COUNT } /** - * Data Size Conversions + * Time Conversions. */ - public static enum DataSize { - KB("KB", BYTES_PER_KILOBYTE), MB("MB", BYTES_PER_KILOBYTE - * BYTES_PER_KILOBYTE), GB("GB", BYTES_PER_KILOBYTE - * BYTES_PER_KILOBYTE * BYTES_PER_KILOBYTE); + public static enum TimeConversion { + MS("ms", "MILLISECONDS"), Second("Seconds", "SECONDS"), Minute( + "Minutes", "MINUTES"), Hour("Hours", "HOURS"); private final String unit; - private final double conversion; + private final String fullUnit; - private static Set dataUnits; + private TimeUnit timeUnit; - private DataSize(String unit, double conversion) { + private TimeConversion(String unit, String fullUnit) { this.unit = unit; - this.conversion = conversion; - populateSet(); - } - - private static void populateSet() { - dataUnits = new HashSet(); - dataUnits.add("KB"); - dataUnits.add("MB"); - dataUnits.add("GB"); + this.fullUnit = fullUnit; + timeUnit = TimeUnit.valueOf(fullUnit); } public String getDataUnit() { return unit; } - public double getConversion() { - return conversion; + public String getFullUnit() { + return fullUnit; } - public static Set getDataUnits() { - return dataUnits; + public TimeUnit getTimeUnit() { + return timeUnit; + } + + public static TimeConversion getInstance(String unit) { + return TIME_UNIT_LOOKUP.get(unit); } } /** - * Time Conversions. + * Data size unit lookup map. */ - public static enum TimeConversion { - MS("ms", 1), Second("seconds", TimeUtil.MILLIS_PER_SECOND), Minute( - "minutes", TimeUtil.MILLIS_PER_MINUTE), Hour("hours", - TimeUtil.MILLIS_PER_HOUR); - - private static Set dataUnits; - - private final String unit; - - private final double conversion; - - private TimeConversion(String unit, double conversion) { - this.unit = unit; - this.conversion = conversion; - populateSet(); + private static final Map DATA_SIZE_UNIT_LOOKUP; + static { + DataSizeUnit[] values = DataSizeUnit.values(); + Map map = new LinkedHashMap( + values.length); + for (DataSizeUnit dataSize : values) { + map.put(dataSize.getUnit(), dataSize); } + DATA_SIZE_UNIT_LOOKUP = Collections.unmodifiableMap(map); + } - private static void populateSet() { - dataUnits = new HashSet(); - dataUnits.add("seconds"); - dataUnits.add("ms"); - dataUnits.add("minutes"); - dataUnits.add("hours"); - } - - public String getDataUnit() { - return unit; - } - - public double getConversion() { - return conversion; - } - - public static Set getDataUnits() { - return dataUnits; + /** + * Time unit lookup map. + */ + private static final Map TIME_UNIT_LOOKUP; + static { + TimeConversion[] values = TimeConversion.values(); + Map map = new LinkedHashMap( + values.length); + for (TimeConversion timeConversion : values) { + map.put(timeConversion.getDataUnit(), timeConversion); } + TIME_UNIT_LOOKUP = Collections.unmodifiableMap(map); } /** The event type */ + @DynamicSerializeElement private String eventType; /** The data type */ + @DynamicSerializeElement private String dataType; /** The display unit */ @@ -148,10 +136,6 @@ public class UnitUtils implements ISerializableObject { @DynamicSerializeElement private UnitTypes unitType; - /** Copnversion factor */ - @DynamicSerializeElement - private double conversion = 1; - /** * Constructor */ @@ -161,7 +145,7 @@ public class UnitUtils implements ISerializableObject { /** * Constructor - * + * * @param eventType * event type * @param dataType @@ -174,38 +158,6 @@ public class UnitUtils implements ISerializableObject { this.unitType = UnitTypes.COUNT; } - /** - * The largest value of the data set. This is used to determine which - * conversion to use if one is not specified. - * - * @param value - * Largest value of the data set - * - * @return The conversion factor - */ - public void setConversion(double value) { - // Which unit type is it? - if (unitType == UnitTypes.COUNT) { - conversion = 1; - } else if (unitType == UnitTypes.DATA_SIZE) { - if (value < DataSize.MB.getConversion()) { - conversion = DataSize.KB.getConversion(); - } else if (value < DataSize.GB.getConversion()) { - conversion = DataSize.MB.getConversion(); - } else if (value >= DataSize.GB.getConversion()) { - conversion = DataSize.GB.getConversion(); - } - } else if (unitType == UnitTypes.TIME) { - if (value < TimeUtil.MILLIS_PER_MINUTE) { - conversion = TimeUtil.MILLIS_PER_SECOND; - } else if (value < TimeUtil.MILLIS_PER_HOUR) { - conversion = TimeUtil.MILLIS_PER_MINUTE; - } else { - conversion = TimeUtil.MILLIS_PER_SECOND; - } - } - } - /** * @return the eventType */ @@ -220,15 +172,6 @@ public class UnitUtils implements ISerializableObject { return dataType; } - /** - * Get the conversion - * - * @return - */ - public double getConversion() { - return conversion; - } - /** * @return the unitType */ @@ -252,36 +195,139 @@ public class UnitUtils implements ISerializableObject { } /** - * Set the display unit. - * * @param displayUnit + * the displayUnit to set */ public void setDisplayUnit(String displayUnit) { this.displayUnit = displayUnit; + setUnitType(displayUnit); + } - // Determine the unitType - if (DataSize.getDataUnits().contains(displayUnit)) { - unitType = UnitTypes.DATA_SIZE; - } else if (TimeConversion.getDataUnits().contains(displayUnit)) { - unitType = UnitTypes.TIME; - } + /** + * @param eventType + * the eventType to set + */ + public void setEventType(String eventType) { + this.eventType = eventType; + } - if (unitType == UnitTypes.DATA_SIZE) { - if (displayUnit.equals(DataSize.KB.getDataUnit())) { - conversion = DataSize.KB.getConversion(); - } else if (displayUnit.equals(DataSize.MB.getDataUnit())) { - conversion = DataSize.MB.getConversion(); - } else if (displayUnit.equals(DataSize.GB.getDataUnit())) { - conversion = DataSize.GB.getConversion(); - } - } else if (unitType == UnitTypes.TIME) { - if (displayUnit.equals(TimeConversion.MS.getDataUnit())) { - conversion = 1; - } else if (displayUnit.equals(TimeConversion.Second.getDataUnit())) { - conversion = TimeUtil.MILLIS_PER_SECOND; - } else if (displayUnit.equals(TimeConversion.Minute.getDataUnit())) { - conversion = TimeUtil.MILLIS_PER_MINUTE; - } + /** + * @param dataType + * the dataType to set + */ + public void setDataType(String dataType) { + this.dataType = dataType; + } + + /** + * Set the unit type based on the display unit. + * + * @param displayUnit + * The display unit + */ + public void setUnitType(String displayUnit) { + if (TIME_UNIT_LOOKUP.containsKey(displayUnit)) { + this.setUnitType(UnitTypes.TIME); + } else if (DATA_SIZE_UNIT_LOOKUP.containsKey(displayUnit)) { + this.setUnitType(UnitTypes.DATA_SIZE); } } + + /** + * Get the available units for the provided unit type. + * + * @param type + * The type of unit + * @return The available units + */ + @VisibleForTesting + public Set getUnitOptions(UnitTypes type) { + Set units = Collections.emptySet(); + + switch (type) { + case DATA_SIZE: + units = DATA_SIZE_UNIT_LOOKUP.keySet(); + break; + case TIME: + units = TIME_UNIT_LOOKUP.keySet(); + break; + case COUNT: + units = new HashSet(); + units.add("Count"); + break; + default: + break; + } + + return units; + } + + /** + * Convert the value in original units to displayUnits. + * + * @param unit + * original unit + * @param value + * in bytes + * @return converted value + */ + @VisibleForTesting + public double convertDataSizeValue(DataSizeUnit unit, double value) { + DataSizeUnit ds = DataSizeUnit.fromString(displayUnit); + if (ds != null) { + if (ds == DataSizeUnit.BYTE) { + return unit.toByte((long) value); + } else if (ds == DataSizeUnit.KB) { + return unit.toKB((long) value); + } else if (ds == DataSizeUnit.MB) { + return unit.toMB((long) value); + } else if (ds == DataSizeUnit.GB) { + return unit.toGB((long) value); + } + + return value; + } + + return value; + } + + /** + * Convert a time from one unit to the display unit. + * + * @param unit + * Originating unit + * @param value + * value to convert + * @return value converted to display unit + */ + @VisibleForTesting + public long convertTimeValue(TimeConversion unit, long value) { + TimeConversion outputTc = TimeConversion.getInstance(displayUnit); + return outputTc.getTimeUnit().convert(value, unit.getTimeUnit()); + } + + /** + * Convert the provided value. Time types expect source units to be ms and + * data size units to be Bytes. + * + * @param value + * @param view + * @param displayUnit + * @return The converted value + */ + public double convertValue(double value) { + if (getUnitType() == UnitTypes.TIME) { + return convertTimeValue(TimeConversion.MS, (long) value); + } else { + return convertDataSizeValue(DataSizeUnit.BYTE, value); + } + + } + + /** + * Get the different unit options for the provided unit type. + */ + public Set getUnitOptions() { + return this.getUnitOptions(this.unitType); + } } diff --git a/edexOsgi/com.raytheon.uf.common.time/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.time/META-INF/MANIFEST.MF index e2914c2ca3..5cc9c2faac 100644 --- a/edexOsgi/com.raytheon.uf.common.time/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.time/META-INF/MANIFEST.MF @@ -18,5 +18,7 @@ Import-Package: javax.persistence, Eclipse-RegisterBuddy: com.raytheon.uf.common.serialization Export-Package: com.raytheon.uf.common.time, com.raytheon.uf.common.time.adapter, + com.raytheon.uf.common.time.domain, + com.raytheon.uf.common.time.domain.api, com.raytheon.uf.common.time.msgs, com.raytheon.uf.common.time.util diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/Duration.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/Duration.java new file mode 100644 index 0000000000..0ccd973755 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/Duration.java @@ -0,0 +1,165 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import java.util.concurrent.TimeUnit; + +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeTypeAdapter; +import com.raytheon.uf.common.time.domain.api.IDuration; + +/** + * Implementation of {@link IDuration}. Intentionally package-private as it is + * an implementation detail, and not part of the public API. All access should + * be constrained through {@link Durations}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 10, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@XmlJavaTypeAdapter(value = IDurationTypeAdapter.class) +@DynamicSerializeTypeAdapter(factory = IDurationTypeAdapter.class) +class Duration implements IDuration { + + private final long valueAsNanoseconds; + + /** + * Constructor. + * + * @param value + * the unit value + * @param unit + * the unit + */ + Duration(long value, TimeUnit unit) { + this.valueAsNanoseconds = unit.toNanos(value); + } + + /** + * {@inheritDoc} + */ + @Override + public long getNanos() { + return convert(TimeUnit.NANOSECONDS); + } + + /** + * {@inheritDoc} + */ + @Override + public long getMicros() { + return convert(TimeUnit.MICROSECONDS); + } + + /** + * {@inheritDoc} + */ + @Override + public long getMillis() { + return convert(TimeUnit.MILLISECONDS); + } + + /** + * {@inheritDoc} + */ + @Override + public long getSeconds() { + return convert(TimeUnit.SECONDS); + } + + /** + * {@inheritDoc} + */ + @Override + public long getMinutes() { + return convert(TimeUnit.MINUTES); + } + + /** + * {@inheritDoc} + */ + @Override + public long getHours() { + return convert(TimeUnit.HOURS); + } + + /** + * {@inheritDoc} + */ + @Override + public long getDays() { + return convert(TimeUnit.DAYS); + } + + private long convert(TimeUnit targetUnit) { + return targetUnit.convert(valueAsNanoseconds, TimeUnit.NANOSECONDS); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof IDuration) { + IDuration other = (IDuration) obj; + return other.getNanos() == this.getNanos(); + } + return super.equals(obj); + } + + @Override + public int hashCode() { + return (int) this.getNanos(); + } + + /** + * {@inheritDoc} + */ + @Override + public Duration plus(IDuration anotherDuration) { + return new Duration(getNanos() + anotherDuration.getNanos(), + TimeUnit.NANOSECONDS); + } + + /** + * {@inheritDoc} + */ + @Override + public Duration minus(IDuration anotherDuration) { + return new Duration(getNanos() - anotherDuration.getNanos(), + TimeUnit.NANOSECONDS); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return Durations.toString(this); + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/Durations.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/Durations.java new file mode 100644 index 0000000000..59b54f1b98 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/Durations.java @@ -0,0 +1,140 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.raytheon.uf.common.time.domain.api.IDuration; +import com.raytheon.uf.common.time.domain.api.ITimePoint; + +/** + * Retrieve {@link IDuration}s. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 11, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public final class Durations { + + private static final Pattern DURATION_PATTERN = Pattern + .compile("\\s*(\\d+)\\s+([^\\s]+)\\s*"); + + public static final IDuration ZERO = Durations + .of(0L, TimeUnit.MILLISECONDS); + + /** + * Retrieve a {@link IDuration} of the specified value and unit. + * + * @param value + * @param unit + * @return the duration + */ + public static IDuration of(long value, TimeUnit unit) { + return new Duration(value, unit); + } + + /** + * Retrieve the duration between two {@link TimePoint}s. + * + * @param start + * the starting time point + * @param end + * the ending time point + * @return the duration between the two points + */ + public static IDuration between(ITimePoint start, ITimePoint end) { + final long millis = end.asMilliseconds() - start.asMilliseconds(); + return of(millis, TimeUnit.MILLISECONDS); + } + + /** + * Parse a string representation of a {@link Duration}. + * + * @param asString + * the string representation of the duration + * + * @return the duration + * @throws IllegalArgumentException + * if the argument cannot be parsed into a duration + */ + public static IDuration fromString(String asString) { + final Matcher m = DURATION_PATTERN.matcher(asString); + if (m.matches()) { + return of(Long.parseLong(m.group(1)), TimeUnit.valueOf(m.group(2))); + } + + throw new IllegalArgumentException("The argument [" + asString + + "] does not match a duration!"); + } + + /** + * Convert the {@link IDuration} to a string representation. This method + * figures out the "optimal" unit to display the time in, e.g. 120 minutes + * would display as "2 HOURS", but 128 minutes will be displayed as "128 + * MINUTES". + * + * @param duration + * the duration instance + * @return the string representation + */ + public static String toString(IDuration duration) { + TimeUnit timeUnitForDisplay = TimeUnit.DAYS; + + final TimeUnit[] values = TimeUnit.values(); + final long nanos = duration.getNanos(); + for (int unitIdx = 1; unitIdx < values.length; unitIdx++) { + final TimeUnit timeUnitToTry = values[unitIdx]; + + // If we would lose precision, then use the time unit before this + // one + final long valueInNewTimeUnit = timeUnitToTry.convert(nanos, + TimeUnit.NANOSECONDS); + final boolean wouldLosePrecision = timeUnitToTry + .toNanos(valueInNewTimeUnit) != nanos; + if (wouldLosePrecision) { + timeUnitForDisplay = values[unitIdx - 1]; + break; + } + } + + // Now construct and return the pretty version of the String + final long convertedValue = timeUnitForDisplay.convert(nanos, + TimeUnit.NANOSECONDS); + return convertedValue + " " + timeUnitForDisplay.toString(); + } + + /** + * Disabled constructor. + */ + private Durations() { + } +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/IDurationTypeAdapter.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/IDurationTypeAdapter.java new file mode 100644 index 0000000000..0e8d88ce93 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/IDurationTypeAdapter.java @@ -0,0 +1,86 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import java.util.concurrent.TimeUnit; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +import com.raytheon.uf.common.serialization.IDeserializationContext; +import com.raytheon.uf.common.serialization.ISerializationContext; +import com.raytheon.uf.common.serialization.ISerializationTypeAdapter; +import com.raytheon.uf.common.serialization.SerializationException; +import com.raytheon.uf.common.time.domain.api.IDuration; + +/** + * {@link ISerializationTypeAdapter} for {@link IDuration} instances. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 11, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +public class IDurationTypeAdapter extends XmlAdapter + implements + ISerializationTypeAdapter { + + /** + * {@inheritDoc} + */ + @Override + public void serialize(ISerializationContext serializer, IDuration object) + throws SerializationException { + serializer.writeI64(object.getNanos()); + } + + /** + * {@inheritDoc} + */ + @Override + public IDuration deserialize(IDeserializationContext deserializer) + throws SerializationException { + return Durations.of(deserializer.readI64(), TimeUnit.NANOSECONDS); + } + + /** + * {@inheritDoc} + */ + @Override + public IDuration unmarshal(String v) throws Exception { + return Durations.fromString(v); + } + + /** + * {@inheritDoc} + */ + @Override + public String marshal(IDuration v) throws Exception { + return Durations.toString(v); + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/ITimeIntervalTypeAdapter.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/ITimeIntervalTypeAdapter.java new file mode 100644 index 0000000000..4bb85f810a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/ITimeIntervalTypeAdapter.java @@ -0,0 +1,93 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +import com.raytheon.uf.common.serialization.IDeserializationContext; +import com.raytheon.uf.common.serialization.ISerializationContext; +import com.raytheon.uf.common.serialization.ISerializationTypeAdapter; +import com.raytheon.uf.common.serialization.SerializationException; +import com.raytheon.uf.common.time.domain.api.ITimeInterval; +import com.raytheon.uf.common.time.domain.api.ITimePoint; + +/** + * {@link ISerializationTypeAdapter} for {@link ITimePoint} instances. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +public class ITimeIntervalTypeAdapter extends + XmlAdapter implements + ISerializationTypeAdapter { + /** + * {@inheritDoc} + */ + @Override + public void serialize(ISerializationContext serializer, ITimeInterval object) + throws SerializationException { + serializer.writeObject(object.getStart()); + serializer.writeObject(object.getEnd()); + } + + /** + * {@inheritDoc} + */ + @Override + public ITimeInterval deserialize(IDeserializationContext deserializer) + throws SerializationException { + ITimePoint start = (ITimePoint) deserializer.readObject(); + ITimePoint end = (ITimePoint) deserializer.readObject(); + + return TimeIntervals.fromTimePoints(start, end); + } + + /** + * {@inheritDoc} + */ + @Override + public ITimeInterval unmarshal(TimeIntervalJaxbable v) + throws Exception { + return TimeIntervals.fromTimePoints(TimePoints.fromDate(v.getStart()), + TimePoints.fromDate(v.getEnd())); + } + + /** + * {@inheritDoc} + */ + @Override + public TimeIntervalJaxbable marshal(ITimeInterval v) throws Exception { + TimeIntervalJaxbable jaxbable = new TimeIntervalJaxbable(); + jaxbable.setStart(v.getStart().asDate()); + jaxbable.setEnd(v.getEnd().asDate()); + + return jaxbable; + } +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/ITimePointTypeAdapter.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/ITimePointTypeAdapter.java new file mode 100644 index 0000000000..e9e44f50bf --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/ITimePointTypeAdapter.java @@ -0,0 +1,83 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import java.util.Date; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +import com.raytheon.uf.common.serialization.IDeserializationContext; +import com.raytheon.uf.common.serialization.ISerializationContext; +import com.raytheon.uf.common.serialization.ISerializationTypeAdapter; +import com.raytheon.uf.common.serialization.SerializationException; +import com.raytheon.uf.common.time.domain.api.ITimePoint; + +/** + * {@link ISerializationTypeAdapter} for {@link ITimePoint} instances. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +public class ITimePointTypeAdapter extends XmlAdapter + implements ISerializationTypeAdapter { + /** + * {@inheritDoc} + */ + @Override + public void serialize(ISerializationContext serializer, ITimePoint object) + throws SerializationException { + serializer.writeI64(object.asMilliseconds()); + } + + /** + * {@inheritDoc} + */ + @Override + public ITimePoint deserialize(IDeserializationContext deserializer) + throws SerializationException { + return TimePoints.fromMillis(deserializer.readI64()); + } + + /** + * {@inheritDoc} + */ + @Override + public ITimePoint unmarshal(Date v) throws Exception { + return TimePoints.fromDate(v); + } + + /** + * {@inheritDoc} + */ + @Override + public Date marshal(ITimePoint v) throws Exception { + return v.asDate(); + } +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeInterval.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeInterval.java new file mode 100644 index 0000000000..cd488c4fc8 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeInterval.java @@ -0,0 +1,136 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeTypeAdapter; +import com.raytheon.uf.common.time.domain.api.IDuration; +import com.raytheon.uf.common.time.domain.api.ITimeInterval; +import com.raytheon.uf.common.time.domain.api.ITimePoint; + +/** + * Implementation of {@link ITimeInterval}. Intentionally package-private as it + * is an implementation detail, and not part of the public API. All access + * should be constrained through {@link TimeIntervals}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@XmlJavaTypeAdapter(value = ITimeIntervalTypeAdapter.class) +@DynamicSerializeTypeAdapter(factory = ITimeIntervalTypeAdapter.class) +class TimeInterval implements ITimeInterval { + + private final ITimePoint intervalStart; + + private final ITimePoint intervalEnd; + + /** + * Constructor. + * + * @param intervalStart + * the start of the interval + * @param intervalEnd + * the end of the interval + */ + TimeInterval(ITimePoint intervalStart, ITimePoint intervalEnd) { + this.intervalStart = intervalStart; + this.intervalEnd = intervalEnd; + } + + /** + * {@inheritDoc} + */ + @Override + public ITimePoint getStart() { + return intervalStart; + } + + /** + * {@inheritDoc} + */ + @Override + public ITimePoint getEnd() { + return intervalEnd; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean containsTimePoint(ITimePoint timePoint) { + final boolean intervalStartSameOrBefore = intervalStart + .isBefore(timePoint) || intervalStart.isSame(timePoint); + final boolean intervalEndSameOrAfter = intervalEnd.isAfter(timePoint) + || intervalEnd.isSame(timePoint); + + return intervalStartSameOrBefore && intervalEndSameOrAfter; + } + + /** + * {@inheritDoc} + */ + @Override + public IDuration getDuration() { + return Durations.between(intervalStart, intervalEnd); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof ITimeInterval) { + ITimeInterval other = (ITimeInterval) obj; + + return this.getStart().equals(other.getStart()) + && this.getEnd().equals(other.getEnd()); + } + return super.equals(obj); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return getStart().hashCode() + getEnd().hashCode(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("start [").append(getStart()).append("]"); + sb.append(" end [").append(getEnd()).append("]"); + sb.append(" duration [").append(getDuration()).append("]"); + + return sb.toString(); + } +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeIntervalJaxbable.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeIntervalJaxbable.java new file mode 100644 index 0000000000..67e1050e7a --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeIntervalJaxbable.java @@ -0,0 +1,91 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import java.util.Date; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + +import com.raytheon.uf.common.time.domain.api.ITimeInterval; + +/** + * Representation of a {@link ITimeInterval} for the purpose of JAXB. This class + * should only be used for converting to and from JAXB in + * {@link ITimeIntervalTypeAdapter}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +@XmlType(propOrder = { "start", "end" }) +public class TimeIntervalJaxbable { + + @XmlElement(required = true) + private Date start; + + @XmlElement(required = true) + private Date end; + + /** + * @return the start + */ + public Date getStart() { + return start; + } + + /** + * @param start + * the start to set + */ + public void setStart(Date start) { + this.start = start; + } + + /** + * @return the end + */ + public Date getEnd() { + return end; + } + + /** + * @param end + * the end to set + */ + public void setEnd(Date end) { + this.end = end; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeIntervals.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeIntervals.java new file mode 100644 index 0000000000..e6a67bcc1d --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimeIntervals.java @@ -0,0 +1,69 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import com.raytheon.uf.common.time.domain.api.ITimeInterval; +import com.raytheon.uf.common.time.domain.api.ITimePoint; + +/** + * Utility class to work with {@link ITimeInterval}s + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public final class TimeIntervals { + + /** + * Construct a {@link ITimeInterval} from two {@link ITimePoint}s. + * + * @param start + * the start of the time interval + * @param end + * the end of the time interval + * @return the interval + */ + public static ITimeInterval fromTimePoints(ITimePoint start, ITimePoint end) { + if (end.isBefore(start)) { + throw new IllegalArgumentException( + "The end time point cannot be before the start time point:\n[end = " + + end + "] [start = " + start + "]"); + } + return new TimeInterval(start, end); + } + + /** + * No construction. + */ + private TimeIntervals() { + + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimePoint.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimePoint.java new file mode 100644 index 0000000000..30be544084 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimePoint.java @@ -0,0 +1,148 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import java.util.Date; + +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeTypeAdapter; +import com.raytheon.uf.common.time.domain.api.ITimeInterval; +import com.raytheon.uf.common.time.domain.api.ITimePoint; +import com.raytheon.uf.common.time.util.TimeUtil; + +/** + * Implementation of {@link ITimePoint}. Intentionally package-private as it is + * an implementation detail, and not part of the public API. All access should + * be constrained through {@link TimePoints}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@XmlJavaTypeAdapter(value = ITimePointTypeAdapter.class) +@DynamicSerializeTypeAdapter(factory = ITimePointTypeAdapter.class) +class TimePoint implements ITimePoint { + + private final long milliseconds; + + /** + * Construct a {@link TimePoint} for the specified milliseconds. + * + * @param milliseconds + */ + TimePoint(long milliseconds) { + this.milliseconds = milliseconds; + } + + /** + * Deep-copy another {@link ITimePoint}. + * + * @param toCopy + */ + TimePoint(ITimePoint toCopy) { + this(toCopy.asMilliseconds()); + } + + /** + * {@inheritDoc} + */ + @Override + public Date asDate() { + return new Date(milliseconds); + } + + /** + * {@inheritDoc} + */ + @Override + public long asMilliseconds() { + return milliseconds; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isAfter(ITimePoint anotherTimePoint) { + return this.asMilliseconds() > anotherTimePoint.asMilliseconds(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isBefore(ITimePoint anotherTimePoint) { + return this.asMilliseconds() < anotherTimePoint.asMilliseconds(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSame(ITimePoint anotherPoint) { + return this.asMilliseconds() == anotherPoint.asMilliseconds(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isWithin(ITimeInterval interval) { + return interval.containsTimePoint(this); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof ITimePoint) { + ITimePoint other = (ITimePoint) obj; + return this.isSame(other); + } + return super.equals(obj); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return (int) asMilliseconds(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return TimeUtil.formatDate(asDate()); + } +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimePoints.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimePoints.java new file mode 100644 index 0000000000..3360c7e2b9 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/TimePoints.java @@ -0,0 +1,75 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import java.util.Date; + +import com.raytheon.uf.common.time.domain.api.ITimePoint; +import com.raytheon.uf.common.time.util.TimeUtil; + +/** + * Utility class to work with {@link ITimePoint}s. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public final class TimePoints { + + /** + * Return the {@link ITimePoint} instance for the specified milliseconds. + * + * @return the milliseconds as an {@link ITimePoint} + */ + public static ITimePoint fromMillis(long milliseconds) { + return new TimePoint(milliseconds); + } + + /** + * Return the {@link ITimePoint} instance for the specified {@link Date}. + * + * @return the date as an {@link ITimePoint} + */ + public static ITimePoint fromDate(Date date) { + return new TimePoint(date.getTime()); + } + + /** + * Return the {@link ITimePoint} instance of the current time. + * + * @return now, as an {@link ITimePoint} + */ + public static ITimePoint now() { + return fromDate(TimeUtil.newImmutableDate()); + } + + private TimePoints() { + } +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/IDuration.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/IDuration.java new file mode 100644 index 0000000000..250f649f57 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/IDuration.java @@ -0,0 +1,138 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain.api; + +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import javax.xml.datatype.Duration; + +import com.raytheon.uf.common.time.domain.IDurationTypeAdapter; + +/** + * Interface for a duration. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 11, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@XmlJavaTypeAdapter(value = IDurationTypeAdapter.class) +public interface IDuration { + + /** + * Retrieve the number of nanoseconds represented by the duration. + * Conversions from finer to coarser granularities truncate, so lose + * precision. For example converting 999 milliseconds to seconds + * results in 0. + * + * @return the number of nanoseconds, or 0 if the converted value is less + * than 1 of the new unit + */ + long getNanos(); + + /** + * Retrieve the number of microseconds represented by the duration. + * Conversions from finer to coarser granularities truncate, so lose + * precision. For example converting 999 milliseconds to seconds + * results in 0. + * + * @return the number of microseconds, or 0 if the converted value is less + * than 1 of the new unit + */ + long getMicros(); + + /** + * Retrieve the number of milliseconds represented by the duration. + * Conversions from finer to coarser granularities truncate, so lose + * precision. For example converting 999 milliseconds to seconds + * results in 0. + * + * @return the number of milliseconds, or 0 if the converted value is less + * than 1 of the new unit + */ + long getMillis(); + + /** + * Retrieve the number of seconds represented by the duration. Conversions + * from finer to coarser granularities truncate, so lose precision. For + * example converting 999 milliseconds to seconds results in + * 0. + * + * @return the number of seconds, or 0 if the converted value is less than 1 + * of the new unit + */ + long getSeconds(); + + /** + * Retrieve the number of minutes represented by the duration. Conversions + * from finer to coarser granularities truncate, so lose precision. For + * example converting 999 milliseconds to seconds results in + * 0. + * + * @return the number of minutes, or 0 if the converted value is less than 1 + * of the new unit + */ + long getMinutes(); + + /** + * Retrieve the number of hours represented by the duration. Conversions + * from finer to coarser granularities truncate, so lose precision. For + * example converting 999 milliseconds to seconds results in + * 0. + * + * @return the number of hours, or 0 if the converted value is less than 1 + * of the new unit + */ + long getHours(); + + /** + * Retrieve the number of hours represented by the duration. Conversions + * from finer to coarser granularities truncate, so lose precision. For + * example converting 999 milliseconds to seconds results in + * 0. + * + * @return the number of days, or 0 if the converted value is less than 1 of + * the new unit + */ + long getDays(); + + /** + * Add another {@link Duration} to this one. + * + * @param anotherDuration + * @return the duration of the sum + */ + IDuration plus(IDuration anotherDuration); + + /** + * Subtract another {@link Duration} from this one. + * + * @param anotherDuration + * @return the duration of the difference + */ + IDuration minus(IDuration anotherDuration); +} \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/ITimeInterval.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/ITimeInterval.java new file mode 100644 index 0000000000..49c5be0afb --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/ITimeInterval.java @@ -0,0 +1,75 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain.api; + +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import com.raytheon.uf.common.time.domain.ITimeIntervalTypeAdapter; + +/** + * Represents a specific interval in time. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@XmlJavaTypeAdapter(value = ITimeIntervalTypeAdapter.class) +public interface ITimeInterval { + + /** + * Return the start {@link ITimePoint} of the {@link ITimeInterval}. + * + * @return the time point the interval started + */ + ITimePoint getStart(); + + /** + * Return the end {@link ITimePoint} of the {@link ITimeInterval}. + * + * @return the time point the interval ended + */ + ITimePoint getEnd(); + + /** + * Check whether an {@link ITimePoint} falls within the + * {@link ITimeInterval}. + * + * @param timePoint + * the time point + * @return true if the interval contains the point + */ + boolean containsTimePoint(ITimePoint timePoint); + + /** + * Retrieve the duration of the {@link ITimeInterval}. + * + * @return the duration + */ + IDuration getDuration(); +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/ITimePoint.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/ITimePoint.java new file mode 100644 index 0000000000..e6edd4c530 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/domain/api/ITimePoint.java @@ -0,0 +1,98 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain.api; + +import java.util.Date; + +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import com.raytheon.uf.common.time.domain.ITimePointTypeAdapter; + +/** + * Represents an instance in time. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@XmlJavaTypeAdapter(value = ITimePointTypeAdapter.class) +public interface ITimePoint { + + /** + * Return the {@link ITimePoint} as a {@link Date}. + * + * @return the {@link ITimePoint} as a {@link Date} + */ + Date asDate(); + + /** + * Return the {@link ITimePoint} as the milliseconds which would be returned + * by {@link Date}. + * + * @return the milliseconds + */ + long asMilliseconds(); + + /** + * Check whether this {@link ITimePoint} is before another one. + * + * @param anotherPoint + * the other {@link ITimePoint} + * @return true if this point in time is before the other one + */ + boolean isBefore(ITimePoint anotherPoint); + + /** + * Check whether this {@link ITimePoint} is after another one. + * + * @param anotherPoint + * the other {@link ITimePoint} + * @return true if this point in time is after the other one + */ + boolean isAfter(ITimePoint anotherPoint); + + /** + * Check whether this {@link ITimePoint} is the same as another one. + * + * @param anotherPoint + * the other {@link ITimePoint} + * @return true if this point in time is the same as the other one + */ + boolean isSame(ITimePoint anotherPoint); + + /** + * Check whether this {@link ITimePoint} falls within the specified + * {@link ITimeInterval}. + * + * @param interval + * the {@link ITimeInterval} + * @return true if this point in time is within the time interval + */ + boolean isWithin(ITimeInterval interval); +} diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/AbstractTimer.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/AbstractTimer.java index 0be0ed7b40..213d0d5681 100644 --- a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/AbstractTimer.java +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/AbstractTimer.java @@ -1,5 +1,8 @@ package com.raytheon.uf.common.time.util; +import com.raytheon.uf.common.time.domain.Durations; +import com.raytheon.uf.common.time.domain.api.IDuration; +import com.raytheon.uf.common.time.domain.api.ITimePoint; /** * @@ -13,19 +16,19 @@ package com.raytheon.uf.common.time.util; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Aug 16, 2012 0743 djohnson Initial creation + * Jan 14, 2013 1286 djohnson Use time domain API. * * * * @author djohnson * @version 1.0 */ -// @NotThreadSafe abstract class AbstractTimer implements ITimer { - private long start; + private ITimePoint start; - private long stop; + private ITimePoint stop; - private long elapsedTime; + private IDuration elapsedTime = Durations.ZERO; /** * {@inheritDoc} @@ -33,8 +36,8 @@ abstract class AbstractTimer implements ITimer { @Override public void start() { if (isTimerStopped()) { - elapsedTime += (stop - start); - stop = 0; + elapsedTime = elapsedTime.plus(Durations.between(start, stop)); + stop = null; } else if (isTimerStarted()) { throw new IllegalStateException( "A timer that is running must be stopped before start() is called again!"); @@ -62,8 +65,21 @@ abstract class AbstractTimer implements ITimer { */ @Override public long getElapsedTime() { - long currentOrStopTime = (isTimerRunning()) ? getCurrentTime() : stop; - return (currentOrStopTime - start) + elapsedTime; + return getElapsed().getMillis(); + } + + /** + * {@inheritDoc} + */ + @Override + public IDuration getElapsed() { + ITimePoint currentOrStopTime = (isTimerRunning()) ? getCurrentTime() + : stop; + if (currentOrStopTime == null && start == null) { + return Durations.ZERO; + } + IDuration currentRun = Durations.between(start, currentOrStopTime); + return currentRun.plus(elapsedTime); } /** @@ -71,12 +87,12 @@ abstract class AbstractTimer implements ITimer { */ @Override public void reset() { - start = 0; - stop = 0; - elapsedTime = 0; + start = null; + stop = null; + elapsedTime = Durations.ZERO; } - protected abstract long getCurrentTime(); + protected abstract ITimePoint getCurrentTime(); /** * Check whether the timer is actively running. @@ -93,7 +109,7 @@ abstract class AbstractTimer implements ITimer { * @return true if the timer was started */ private boolean isTimerStarted() { - return start > 0; + return start != null; } /** @@ -102,6 +118,6 @@ abstract class AbstractTimer implements ITimer { * @return true if the timer is stopped */ private boolean isTimerStopped() { - return stop > 0; + return stop != null; } } diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/ITimer.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/ITimer.java index 0a028176ad..9fcaccfc58 100644 --- a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/ITimer.java +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/ITimer.java @@ -1,5 +1,7 @@ package com.raytheon.uf.common.time.util; +import com.raytheon.uf.common.time.domain.api.IDuration; + /** * * Defines a timer that can be started and stopped. @@ -11,6 +13,7 @@ package com.raytheon.uf.common.time.util; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Aug 16, 2012 0743 djohnson Initial creation + * Jan 11, 2013 djohnson Use {@link IDuration}. * * * @@ -43,6 +46,13 @@ public interface ITimer { */ long getElapsedTime(); + /** + * Get the elapsed time + * + * @return the elapsed time + */ + IDuration getElapsed(); + /** * Reset the timer. */ diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/TimeUtil.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/TimeUtil.java index f236e4d402..ac04d0011f 100644 --- a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/TimeUtil.java +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/TimeUtil.java @@ -28,6 +28,8 @@ import java.util.TimeZone; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.SimulatedTime; +import com.raytheon.uf.common.time.domain.TimePoints; +import com.raytheon.uf.common.time.domain.api.ITimePoint; /** * Utilities for time, some extracted from Util. @@ -42,14 +44,16 @@ import com.raytheon.uf.common.time.SimulatedTime; * Nov 09, 2012 1322 djohnson Add SECONDS_PER_MINUTE. * Nov 21, 2012 728 mpduff Added MILLIS_PER_MONTH. * Jan 07, 2013 1451 djohnson Add newGmtCalendar() and time constants. + * Jan 17, 2013 1357 mpduff Change MILLIS_PER_MONTH to MILLIS_PER_30_DAYS + * Jan 22, 2013 1484 mpduff Add HOURS_PER_WEEK. + * Jan 22, 2013 1519 djohnson Add MINUTES_PER_DAY. * * * * @author njensen * @version 1.0 */ - -public class TimeUtil { +public final class TimeUtil { /** * A clock that does not really return the current time. Useful when you @@ -63,9 +67,12 @@ public class TimeUtil { * */ private static class NullClock extends AbstractTimer { + private static final ITimePoint CONSTANT_TIME = TimePoints + .fromMillis(1L); + @Override - protected long getCurrentTime() { - return 1; + protected ITimePoint getCurrentTime() { + return CONSTANT_TIME; } } @@ -91,8 +98,16 @@ public class TimeUtil { public static final int HOURS_PER_DAY = 24; + public static final int HOURS_PER_HALF_DAY = HOURS_PER_DAY / 2; + + public static final int HOURS_PER_QUARTER_DAY = HOURS_PER_HALF_DAY / 2; + + public static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY; + private static final int DAYS_PER_WEEK = 7; + public static final int HOURS_PER_WEEK = HOURS_PER_DAY * DAYS_PER_WEEK; + // Util.java has a few of these constants, but that is located in an EDEX // plugin and this is a more appropriate place for them anyways public static final long MILLIS_PER_SECOND = 1000; @@ -107,10 +122,7 @@ public class TimeUtil { public static final long MILLIS_PER_WEEK = MILLIS_PER_DAY * DAYS_PER_WEEK; - /** - * Note: This constant assumes a month of 30 days. - */ - public static final long MILLIS_PER_MONTH = MILLIS_PER_DAY * 30; + public static final long MILLIS_PER_30_DAYS = MILLIS_PER_DAY * 30; /** * Note: This constant does not take into account leap years. @@ -377,4 +389,10 @@ public class TimeUtil { } return calendar; } + + /** + * Disabled constructor. + */ + private TimeUtil() { + } } diff --git a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/TimerImpl.java b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/TimerImpl.java index 337deafa35..3685f77ba1 100644 --- a/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/TimerImpl.java +++ b/edexOsgi/com.raytheon.uf.common.time/src/com/raytheon/uf/common/time/util/TimerImpl.java @@ -1,5 +1,8 @@ package com.raytheon.uf.common.time.util; +import com.raytheon.uf.common.time.domain.TimePoints; +import com.raytheon.uf.common.time.domain.api.ITimePoint; + /** * @@ -27,7 +30,7 @@ class TimerImpl extends AbstractTimer { * {@inheritDoc} */ @Override - protected long getCurrentTime() { - return TimeUtil.currentTimeMillis(); + protected ITimePoint getCurrentTime() { + return TimePoints.fromMillis(TimeUtil.currentTimeMillis()); } } diff --git a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataSizeUnit.java b/edexOsgi/com.raytheon.uf.common.units/src/com/raytheon/uf/common/units/DataSizeUnit.java similarity index 80% rename from cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataSizeUnit.java rename to edexOsgi/com.raytheon.uf.common.units/src/com/raytheon/uf/common/units/DataSizeUnit.java index fb4e427311..89f23ca2d0 100644 --- a/cave/com.raytheon.uf.viz.datadelivery/src/com/raytheon/uf/viz/datadelivery/utils/DataSizeUnit.java +++ b/edexOsgi/com.raytheon.uf.common.units/src/com/raytheon/uf/common/units/DataSizeUnit.java @@ -1,8 +1,11 @@ -package com.raytheon.uf.viz.datadelivery.utils; +package com.raytheon.uf.common.units; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.xml.bind.annotation.XmlEnum; import javax.xml.bind.annotation.XmlEnumValue; -import javax.xml.bind.annotation.XmlType; /** * Enumeration for Data Size units and conversions. Based off of TimeUnit class. @@ -13,14 +16,16 @@ import javax.xml.bind.annotation.XmlType; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Jan 08, 2013 1420 mpduff Initial creation. + * Jan 08, 2013 1420 mpduff Initial creation. + * Jan 14, 2013 1286 djohnson Add lookup map via string version. + * Jan 17, 2013 1357 mpduff Moved to com.raytheon.uf.common.units so other plugins can use it. * * * * @author mpduff * @version 1.0 */ -@XmlType(name = "ruleUnit") + @XmlEnum public enum DataSizeUnit { @XmlEnumValue("Byte") @@ -201,4 +206,23 @@ public enum DataSizeUnit { * @return converted value */ public abstract long convert(long l, DataSizeUnit ds); + + private static final Map LOOKUP_MAP; + static { + Map map = new HashMap(); + for (DataSizeUnit unit : DataSizeUnit.values()) { + map.put(unit.getUnit(), unit); + } + LOOKUP_MAP = Collections.unmodifiableMap(map); + } + + /** + * Retrieve the {@link DataSizeUnit} for its string representation. + * + * @param asString + * @return + */ + public static DataSizeUnit fromString(String asString) { + return LOOKUP_MAP.get(asString); + } } \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthGraphDataAdapter.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthGraphDataAdapter.java index f8b2ac0908..9d012ec956 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthGraphDataAdapter.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthGraphDataAdapter.java @@ -31,6 +31,11 @@ import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.raytheon.uf.common.datadelivery.bandwidth.data.BandwidthGraphData; import com.raytheon.uf.common.datadelivery.bandwidth.data.TimeWindowData; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; +import com.raytheon.uf.common.serialization.SerializationException; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.edex.datadelivery.bandwidth.dao.BandwidthAllocation; import com.raytheon.uf.edex.datadelivery.bandwidth.dao.SubscriptionDao; @@ -50,7 +55,8 @@ import com.raytheon.uf.edex.datadelivery.bandwidth.retrieval.RetrievalPlan.Bandw * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Dec 6, 2012 1397 djohnson Initial creation + * Dec 06, 2012 1397 djohnson Initial creation + * Jan 25, 2013 1528 djohnson Subscription priority is now an enum. * * * @@ -59,6 +65,8 @@ import com.raytheon.uf.edex.datadelivery.bandwidth.retrieval.RetrievalPlan.Bandw */ class BandwidthGraphDataAdapter { + private static final IUFStatusHandler statusHandler = UFStatus + .getHandler(BandwidthGraphDataAdapter.class); private final RetrievalManager retrievalManager; @@ -88,7 +96,7 @@ class BandwidthGraphDataAdapter { .getBucketMinutes()); Map> dataMap = new HashMap>(); - Map priorityMap = new HashMap(); + Map priorityMap = new HashMap(); Map retrievals = new HashMap(); Multimap reservations = ArrayListMultimap @@ -133,7 +141,16 @@ class BandwidthGraphDataAdapter { final SubscriptionRetrieval value = entry.getValue(); SubscriptionDao dao = value.getSubscriptionDao(); final String subName = dao.getName(); - priorityMap.put(subName, Integer.valueOf((int) dao.getPriority())); + try { + priorityMap.put(subName, dao.getSubscription().getPriority()); + } catch (SerializationException e) { + statusHandler + .handle(Priority.PROBLEM, + "Unable to get access to the actual subscription for [" + + subName + "], skipping...", + e); + continue; + } List timeWindows = dataMap.get(subName); diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthManager.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthManager.java index b037dfb8f9..bcd51a6e14 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthManager.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthManager.java @@ -96,7 +96,9 @@ import com.raytheon.uf.edex.event.EventBus; * Dec 06, 2012 1397 djohnson Add ability to get bandwidth graph data. * Dec 11, 2012 1403 djohnson Adhoc subscriptions no longer go to the registry. * Dec 12, 2012 1286 djohnson Remove shutdown hook and finalize(). - * + * Jan 25, 2013 1528 djohnson Compare priorities as primitive ints. + * Jan 28, 2013 1530 djohnson Unschedule all allocations for a subscription that does not fully schedule. + * Jan 30, 2013 1501 djohnson Fix broken calculations for determining required latency. * * * @author dhladky @@ -567,9 +569,45 @@ abstract class BandwidthManager extends .getCycleTimes()); List unscheduled = schedule(subscription, cycles); + unscheduleSubscriptionsForAllocations(unscheduled); + return unscheduled; } + /** + * Unschedules all subscriptions the allocations are associated to. + * + * @param unscheduled + * the unscheduled allocations + */ + private void unscheduleSubscriptionsForAllocations( + List unscheduled) { + Set subscriptionsToUnschedule = Sets.newHashSet(); + for (BandwidthAllocation unscheduledAllocation : unscheduled) { + if (unscheduledAllocation instanceof SubscriptionRetrieval) { + SubscriptionRetrieval retrieval = (SubscriptionRetrieval) unscheduledAllocation; + try { + subscriptionsToUnschedule.add(retrieval.getSubscription()); + } catch (SerializationException e) { + statusHandler.handle(Priority.PROBLEM, + "Unable to deserialize a subscription", e); + continue; + } + } + } + + for (Subscription sub : subscriptionsToUnschedule) { + sub.setUnscheduled(true); + try { + subscriptionUpdated(sub); + } catch (SerializationException e) { + statusHandler.handle(Priority.PROBLEM, + "Unable to deserialize a subscription", e); + continue; + } + } + } + /** * {@inheritDoc} * @@ -658,7 +696,8 @@ abstract class BandwidthManager extends // If BandwidthManager does not know about the subscription, and // it's active, attempt to add it.. - if (subscriptionDaos.isEmpty() && subscription.isActive()) { + if (subscriptionDaos.isEmpty() && subscription.isActive() + && !subscription.isUnscheduled()) { final boolean subscribedToCycles = !subscription.getTime() .getCycleTimes().isEmpty(); final boolean useMostRecentDataSetUpdate = !subscribedToCycles; @@ -687,8 +726,8 @@ abstract class BandwidthManager extends unscheduled = schedule(adhoc); } return unscheduled; - } else if (!subscription.isActive()) { - // See if the subscription was inactivated.. + } else if (!subscription.isActive() || subscription.isUnscheduled()) { + // See if the subscription was inactivated or unscheduled.. // Need to remove BandwidthReservations for this // subscription. return remove(subscriptionDaos, true); @@ -796,7 +835,7 @@ abstract class BandwidthManager extends boolean requiresReschedule = (old.getDataSetSize() != subscription .getDataSetSize()) // Priority is different - || (!old.getPriority().equals(subscription.getPriority())) + || (old.getPriority() != subscription.getPriority()) // Latency is different || (!(old.getLatencyInMinutes() == subscription .getLatencyInMinutes())); @@ -1121,8 +1160,7 @@ abstract class BandwidthManager extends * @return the graph data */ private BandwidthGraphData getBandwidthGraphData() { - return new BandwidthGraphDataAdapter(retrievalManager) - .get(); + return new BandwidthGraphDataAdapter(retrievalManager).get(); } /** @@ -1505,95 +1543,86 @@ abstract class BandwidthManager extends * @return the required latency, in minutes */ @VisibleForTesting - int determineRequiredLatency(Subscription subscription) { + int determineRequiredLatency(final Subscription subscription) { ITimer timer = TimeUtil.getTimer(); timer.start(); - try { - final Subscription clone = BandwidthUtil.cheapClone( - Subscription.class, subscription); - if (clone.getLatencyInMinutes() < 1) { - clone.setLatencyInMinutes(1); - } - - boolean foundLatency = false; - int latency = clone.getLatencyInMinutes(); - int previousLatency = latency; - do { - // Double the latency until we have two values we can binary - // search between... - previousLatency = latency; - latency *= 2; - clone.setLatencyInMinutes(latency); - foundLatency = isSchedulableWithoutConflict(clone); - } while (!foundLatency); - - SortedSet possibleLatencies = new TreeSet(); - for (int i = previousLatency; i < (latency + 1); i++) { - possibleLatencies.add(Integer.valueOf(i)); - } - - IBinarySearchResponse response = AlgorithmUtil - .binarySearch(possibleLatencies, new Comparable() { - @Override - public int compareTo(Integer valueToCheck) { - clone.setLatencyInMinutes(valueToCheck); - - boolean latencyWouldWork = isSchedulableWithoutConflict(clone); - - // Check if one value less would not work, if so - // then this is the required latency, otherwise keep - // searching - if (latencyWouldWork) { - clone.setLatencyInMinutes(clone - .getLatencyInMinutes() - 1); - - return (isSchedulableWithoutConflict(clone)) ? 1 - : 0; - } else { - // Still too low, stuff would be unscheduled - return -1; - } - } - }); - - final Integer binarySearchedLatency = response.getItem(); - if (binarySearchedLatency != null) { - latency = binarySearchedLatency.intValue(); - - if (statusHandler.isPriorityEnabled(Priority.DEBUG)) { - statusHandler - .debug(String - .format("Found required latency of [%s] in [%s] iterations", - binarySearchedLatency, - response.getIterations())); - } - } else { - statusHandler - .warn(String - .format("Unable to find the required latency with a binary search, using required latency [%s]", - latency)); - } - - timer.stop(); - - int bufferRoomInMinutes = retrievalManager.getPlan( - subscription.getRoute()).getBucketMinutes(); - - final String logMsg = String - .format("Determined required latency of [%s] in [%s] ms. Adding buffer room of [%s] minutes", - latency, timer.getElapsedTime(), - bufferRoomInMinutes); - statusHandler.info(logMsg); - - latency += bufferRoomInMinutes; - - return latency; - } catch (SerializationException e) { - statusHandler.handle(Priority.PROBLEM, - "Unable to serialize a Subscription", e); - return -1; + boolean foundLatency = false; + int latency = subscription.getLatencyInMinutes(); + if (latency < 1) { + latency = 1; } + int previousLatency = latency; + do { + // Double the latency until we have two values we can binary + // search between... + previousLatency = latency; + latency *= 2; + + Subscription clone = new Subscription(subscription); + clone.setLatencyInMinutes(latency); + foundLatency = isSchedulableWithoutConflict(clone); + } while (!foundLatency); + + SortedSet possibleLatencies = new TreeSet(); + for (int i = previousLatency; i < (latency + 1); i++) { + possibleLatencies.add(Integer.valueOf(i)); + } + + IBinarySearchResponse response = AlgorithmUtil.binarySearch( + possibleLatencies, new Comparable() { + @Override + public int compareTo(Integer valueToCheck) { + Subscription clone = new Subscription(subscription); + clone.setLatencyInMinutes(valueToCheck); + + boolean latencyWouldWork = isSchedulableWithoutConflict(clone); + + // Check if one value less would not work, if so + // then this is the required latency, otherwise keep + // searching + if (latencyWouldWork) { + clone.setLatencyInMinutes(clone + .getLatencyInMinutes() - 1); + + return (isSchedulableWithoutConflict(clone)) ? 1 + : 0; + } else { + // Still too low, stuff would be unscheduled + return -1; + } + } + }); + + final Integer binarySearchedLatency = response.getItem(); + if (binarySearchedLatency != null) { + latency = binarySearchedLatency.intValue(); + + if (statusHandler.isPriorityEnabled(Priority.DEBUG)) { + statusHandler.debug(String.format( + "Found required latency of [%s] in [%s] iterations", + binarySearchedLatency, response.getIterations())); + } + } else { + statusHandler + .warn(String + .format("Unable to find the required latency with a binary search, using required latency [%s]", + latency)); + } + + timer.stop(); + + int bufferRoomInMinutes = retrievalManager.getPlan( + subscription.getRoute()).getBucketMinutes(); + + final String logMsg = String + .format("Determined required latency of [%s] in [%s] ms. Adding buffer room of [%s] minutes", + latency, timer.getElapsedTime(), bufferRoomInMinutes); + statusHandler.info(logMsg); + + latency += bufferRoomInMinutes; + + return latency; } /** diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/dao/BandwidthAllocation.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/dao/BandwidthAllocation.java index 683db4760e..5ac5ed34e3 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/dao/BandwidthAllocation.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/dao/BandwidthAllocation.java @@ -298,4 +298,16 @@ public class BandwidthAllocation implements IPersistableDataObject, return sb.toString(); } + /** + * Check whether this allocation is higher priority than another. + * + * @param other + * the other + * @return true if this allocation is higher priority than the other one + */ + public boolean isHigherPriorityThan(BandwidthAllocation other) { + // A lower priority value means it's higher priority + return this.getPriority() < other.getPriority(); + } + } \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/retrieval/PriorityRetrievalScheduler.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/retrieval/PriorityRetrievalScheduler.java index 279c1d87d1..49fa940def 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/retrieval/PriorityRetrievalScheduler.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/retrieval/PriorityRetrievalScheduler.java @@ -28,7 +28,7 @@ import com.raytheon.uf.edex.datadelivery.bandwidth.util.BandwidthUtil; * Aug 27, 2012 726 jspinks Initial release. * Oct 17, 2012 0726 djohnson If unable to find a bucket with floorKey, use ceilingKey. * Oct 26, 2012 1286 djohnson Return list of unscheduled allocations. - * + * Jan 25, 2013 1528 djohnson Lower priority requests should not be able to unschedule higher priority requests. * * * @version 1.0 @@ -180,7 +180,10 @@ public class PriorityRetrievalScheduler implements IRetrievalScheduler { for (BandwidthBucket bucket : window) { for (BandwidthAllocation o : bucket.getRequests()) { long estimatedSizeInBytes = o.getEstimatedSizeInBytes(); - if (request.getPriority() > o.getPriority()) { + // This was bad... we just about released giving lower + // priority requests the ability to unschedule higher priority + // requests.... + if (request.isHigherPriorityThan(o)) { total += estimatedSizeInBytes; lowerPriorityRequests.add(o); } diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/util/BandwidthUtil.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/util/BandwidthUtil.java index 62310af045..48587bddec 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/util/BandwidthUtil.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.bandwidth/src/com/raytheon/uf/edex/datadelivery/bandwidth/util/BandwidthUtil.java @@ -207,7 +207,7 @@ public class BandwidthUtil { // will have to revisit when other data type are introduced. // perhaps minute of the day? dao.setCycle(baseReferenceTime.get(Calendar.HOUR_OF_DAY)); - dao.setPriority(subscription.getPriority()); + dao.setPriority(subscription.getPriority().getPriorityValue()); dao.setRegistryId(subscription.getId()); return dao; } diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.event/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.datadelivery.event/META-INF/MANIFEST.MF index 370aea781a..49bf0e89f1 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.event/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.event/META-INF/MANIFEST.MF @@ -18,4 +18,6 @@ Require-Bundle: com.google.guava;bundle-version="1.0.0", org.springframework;bundle-version="2.5.6", com.raytheon.uf.common.event;bundle-version="1.0.0", com.raytheon.uf.common.datadelivery.registry;bundle-version="1.0.0", - com.raytheon.uf.common.registry.event;bundle-version="1.0.0" + com.raytheon.uf.common.registry.event;bundle-version="1.0.0", + com.raytheon.uf.common.registry.ebxml;bundle-version="1.0.0", + com.raytheon.uf.common.datadelivery.service;bundle-version="1.0.0" diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.event/res/spring/event-datadelivery-request.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.event/res/spring/event-datadelivery.xml similarity index 90% rename from edexOsgi/com.raytheon.uf.edex.datadelivery.event/res/spring/event-datadelivery-request.xml rename to edexOsgi/com.raytheon.uf.edex.datadelivery.event/res/spring/event-datadelivery.xml index 95920aaa57..de3b7a62fd 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.event/res/spring/event-datadelivery-request.xml +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.event/res/spring/event-datadelivery.xml @@ -24,19 +24,19 @@ - + - + - + - + diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.event/src/com/raytheon/uf/edex/datadelivery/event/handler/SubscriptionNotificationHandler.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.event/src/com/raytheon/uf/edex/datadelivery/event/handler/SubscriptionNotificationHandler.java index e0a17c731e..cb31c53e84 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.event/src/com/raytheon/uf/edex/datadelivery/event/handler/SubscriptionNotificationHandler.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.event/src/com/raytheon/uf/edex/datadelivery/event/handler/SubscriptionNotificationHandler.java @@ -21,21 +21,22 @@ package com.raytheon.uf.edex.datadelivery.event.handler; import java.util.Calendar; -import com.raytheon.uf.common.datadelivery.event.notification.BaseSubscriptionNotificationRequest; -import com.raytheon.uf.common.datadelivery.event.notification.BaseSubscriptionNotificationResponse; import com.raytheon.uf.common.datadelivery.event.notification.NotificationRecord; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.handlers.IBaseSubscriptionHandler; +import com.raytheon.uf.common.datadelivery.service.BaseSubscriptionNotificationRequest; +import com.raytheon.uf.common.datadelivery.service.BaseSubscriptionNotificationResponse; import com.raytheon.uf.common.serialization.comm.IRequestHandler; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; /** * Subscription Notification Handler. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Jun 25, 2012            mpduff     Initial creation.
@@ -44,13 +45,16 @@ import com.raytheon.uf.common.status.UFStatus;
  * Aug 31, 2012    1128    mpduff     Set priority and category from request.
  * Sep 06, 2012     687    mpduff     Send a SubscriptionNotificationResponse object.
  * Sep 24, 2012    1157    mpduff     Changed to use BaseSubscriptionNotificationRequest.
+ * Jan 17, 2013 1501       djohnson     If a subscription is still in the registry, use it for the notification response.
+ * Jan 21, 2013 1501       djohnson     Throw an exception if subscription is not provided on the request.
  * 
- * + * * @author mpduff * @version 1.0 */ -public class SubscriptionNotificationHandler extends AbstractHandler implements +public class SubscriptionNotificationHandler extends + AbstractHandler implements IRequestHandler> { private static final IUFStatusHandler statusHandler = UFStatus @@ -60,7 +64,7 @@ public class SubscriptionNotificationHandler extends Abs /** * Constructor - * + * * @param uri * the jms uri to send the response */ @@ -70,7 +74,7 @@ public class SubscriptionNotificationHandler extends Abs /* * (non-Javadoc) - * + * * @see * com.raytheon.uf.common.serialization.comm.IRequestHandler#handleRequest * (com.raytheon.uf.common.serialization.comm.IServerRequest) @@ -87,9 +91,28 @@ public class SubscriptionNotificationHandler extends Abs storeAndSend(record, uri); - BaseSubscriptionNotificationResponse response = request.getResponse(); + BaseSubscriptionNotificationResponse response = request + .getResponse(); response.setMessage(request.getMessage()); - response.setSubscription(request.getSubscription()); + + final IBaseSubscriptionHandler subscriptionHandler = response + .getSubscriptionHandler(); + final T requestSubscription = request.getSubscription(); + + if (requestSubscription == null) { + throw new IllegalArgumentException( + "Unable to send a notification for a null subscription!", + new NullPointerException("requestSubscription")); + } + + final T registryVersion = subscriptionHandler + .getByName(requestSubscription.getName()); + + // If the subscription is still in the registry, use that version which + // will reflect any updates that have occurred since the notification + // was sent, otherwise pass along the one provided with the request + response.setSubscription((registryVersion != null) ? registryVersion + : requestSubscription); send(response, uri); diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.feature/feature.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.feature/feature.xml index 7420fa1438..af9645414a 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.feature/feature.xml +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.feature/feature.xml @@ -133,6 +133,13 @@ version="0.0.0" unpack="false"/> + + datesToCrawl = new ArrayList(); Date date = TimeUtil.newImmutableDate(); - long postedFileDelayMilliseconds = TimeUnit.MILLISECONDS - .convert(provider.getPostedFileDelayValue(), - provider.getPostedFileDelayUnits()); + long postedFileDelayMilliseconds = provider + .getPostedFileDelay().getMillis(); if (postedFileDelayMilliseconds > 0) { // Check whether the posted file delay would place us in diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/OPENDAPServiceConfig.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/OPENDAPServiceConfig.xml index dc9ce2dc88..1c895b1050 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/OPENDAPServiceConfig.xml +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/OPENDAPServiceConfig.xml @@ -74,6 +74,7 @@ + diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/harvester/NOMADS-harvester.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/harvester/NOMADS-harvester.xml index 319b9ff0f6..eed51c2d9d 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/harvester/NOMADS-harvester.xml +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/harvester/NOMADS-harvester.xml @@ -41,13 +41,13 @@ /awips2/crawl HHddMMMyyyy ruc - rap32 + rap_f \.das$ \.dds$ help$ - fens_all - cmcens_all - gep_all + fens\d\d\d_ + cmcens[cp]\d\d + ge[cp]\d\d 0 0 12 * * ? diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/cmcensLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/cmcensLevelLookup.xml deleted file mode 100644 index e5cdc29670..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/cmcensLevelLookup.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - 1000.0 - 925.0 - 850.0 - 700.0 - 500.0 - 250.0 - 200.0 - 100.0 - 50.0 - 10.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/fensLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/fensLevelLookup.xml deleted file mode 100644 index e5cdc29670..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/fensLevelLookup.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - 1000.0 - 925.0 - 850.0 - 700.0 - 500.0 - 250.0 - 200.0 - 100.0 - 50.0 - 10.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gensLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gensLevelLookup.xml deleted file mode 100644 index 96a86d0c5d..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gensLevelLookup.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - 1000.0 - 975.0 - 950.0 - 925.0 - 900.0 - 850.0 - 800.0 - 750.0 - 700.0 - 650.0 - 600.0 - 550.0 - 500.0 - 450.0 - 400.0 - 350.0 - 300.0 - 250.0 - 200.0 - 150.0 - 100.0 - 70.0 - 50.0 - 30.0 - 20.0 - 10.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gens_bcLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gens_bcLevelLookup.xml deleted file mode 100644 index d2aab31231..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gens_bcLevelLookup.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - 1000.0 - 925.0 - 850.0 - 600.0 - 500.0 - 250.0 - 200.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfsLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfsLevelLookup.xml deleted file mode 100644 index dd43090a50..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfsLevelLookup.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - 1000.0 - 975.0 - 950.0 - 925.0 - 900.0 - 850.0 - 800.0 - 750.0 - 700.0 - 650.0 - 600.0 - 550.0 - 500.0 - 450.0 - 400.0 - 350.0 - 300.0 - 250.0 - 200.0 - 150.0 - 100.0 - 70.0 - 50.0 - 30.0 - 20.0 - 10.0 - \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfs_2p5LevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfs_2p5LevelLookup.xml deleted file mode 100644 index 96a86d0c5d..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfs_2p5LevelLookup.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - 1000.0 - 975.0 - 950.0 - 925.0 - 900.0 - 850.0 - 800.0 - 750.0 - 700.0 - 650.0 - 600.0 - 550.0 - 500.0 - 450.0 - 400.0 - 350.0 - 300.0 - 250.0 - 200.0 - 150.0 - 100.0 - 70.0 - 50.0 - 30.0 - 20.0 - 10.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfs_hdLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfs_hdLevelLookup.xml deleted file mode 100644 index 9c32afbf49..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/gfs_hdLevelLookup.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - 1000.0 - 975.0 - 950.0 - 925.0 - 900.0 - 875.0 - 850.0 - 825.0 - 800.0 - 775.0 - 750.0 - 725.0 - 700.0 - 675.0 - 650.0 - 625.0 - 600.0 - 575.0 - 550.0 - 525.0 - 500.0 - 475.0 - 450.0 - 425.0 - 400.0 - 375.0 - 350.0 - 325.0 - 300.0 - 275.0 - 250.0 - 225.0 - 200.0 - 175.0 - 150.0 - 125.0 - 100.0 - 70.0 - 50.0 - 30.0 - 20.0 - 10.0 - 7.0 - 5.0 - 3.0 - 2.0 - 1.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/hireswLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/hireswLevelLookup.xml deleted file mode 100644 index ccf28104b4..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/hireswLevelLookup.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - 1000.0 - 925.0 - 850.0 - 700.0 - 600.0 - 500.0 - 400.0 - 300.0 - 250.0 - 200.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/naefs_bcLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/naefs_bcLevelLookup.xml deleted file mode 100644 index eeb016cb52..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/naefs_bcLevelLookup.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - 1000.0 - 925.0 - 850.0 - 700.0 - 500.0 - 250.0 - 200.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/namLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/namLevelLookup.xml deleted file mode 100644 index d1a5b0eef9..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/namLevelLookup.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - 1000.0 - 975.0 - 950.0 - 925.0 - 900.0 - 875.0 - 850.0 - 825.0 - 800.0 - 775.0 - 750.0 - 725.0 - 700.0 - 675.0 - 650.0 - 625.0 - 600.0 - 575.0 - 550.0 - 525.0 - 500.0 - 475.0 - 450.0 - 425.0 - 400.0 - 375.0 - 350.0 - 325.0 - 300.0 - 275.0 - 250.0 - 225.0 - 200.0 - 175.0 - 150.0 - 125.0 - 100.0 - 75.0 - 50.0 - 20.0 - 10.0 - 5.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/ofsLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/ofsLevelLookup.xml deleted file mode 100644 index fb041d3a97..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/ofsLevelLookup.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - 6000.0 - 5500.0 - 5000.0 - 4500.0 - 4000.0 - 3500.0 - 3000.0 - 2500.0 - 2000.0 - 1500.0 - 1000.0 - 950.0 - 900.0 - 850.0 - 800.0 - 750.0 - 700.0 - 650.0 - 600.0 - 550.0 - 500.0 - 450.0 - 400.0 - 350.0 - 300.0 - 250.0 - 200.0 - 150.0 - 100.0 - 90.0 - 80.0 - 70.0 - 60.0 - 50.0 - 30.0 - 20.0 - 10.0 - 6.0 - 3.0 - 0.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rapLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rapLevelLookup.xml deleted file mode 100644 index 9996d3048a..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rapLevelLookup.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - 1000.0 - 975.0 - 950.0 - 925.0 - 900.0 - 875.0 - 850.0 - 825.0 - 800.0 - 775.0 - 750.0 - 725.0 - 700.0 - 675.0 - 650.0 - 625.0 - 600.0 - 575.0 - 550.0 - 525.0 - 500.0 - 475.0 - 450.0 - 425.0 - 400.0 - 375.0 - 350.0 - 325.0 - 300.0 - 275.0 - 250.0 - 225.0 - 200.0 - 175.0 - 150.0 - 125.0 - 100.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rucLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rucLevelLookup.xml deleted file mode 100644 index 9996d3048a..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/rucLevelLookup.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - 1000.0 - 975.0 - 950.0 - 925.0 - 900.0 - 875.0 - 850.0 - 825.0 - 800.0 - 775.0 - 750.0 - 725.0 - 700.0 - 675.0 - 650.0 - 625.0 - 600.0 - 575.0 - 550.0 - 525.0 - 500.0 - 475.0 - 450.0 - 425.0 - 400.0 - 375.0 - 350.0 - 325.0 - 300.0 - 275.0 - 250.0 - 225.0 - 200.0 - 175.0 - 150.0 - 125.0 - 100.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/srefLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/srefLevelLookup.xml deleted file mode 100644 index 892534c4a7..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/srefLevelLookup.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - 1000.0 - 975.0 - 950.0 - 925.0 - 900.0 - 875.0 - 850.0 - 825.0 - 800.0 - 775.0 - 750.0 - 725.0 - 700.0 - 675.0 - 650.0 - 625.0 - 600.0 - 575.0 - 550.0 - 525.0 - 500.0 - 475.0 - 450.0 - 425.0 - 400.0 - 375.0 - 350.0 - 325.0 - 300.0 - 275.0 - 250.0 - 225.0 - 200.0 - 175.0 - 150.0 - 125.0 - 100.0 - 75.0 - 50.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/sref_bcLevelLookup.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/sref_bcLevelLookup.xml deleted file mode 100644 index e04f191f0b..0000000000 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.harvester/utility/common_static/base/datadelivery/lookups/sref_bcLevelLookup.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - 1000.0 - 850.0 - 700.0 - 500.0 - 250.0 - diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/metadata/adapters/GridMetadataAdapter.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/metadata/adapters/GridMetadataAdapter.java index 3e8f524583..7649d934b3 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/metadata/adapters/GridMetadataAdapter.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/metadata/adapters/GridMetadataAdapter.java @@ -20,6 +20,8 @@ package com.raytheon.uf.edex.datadelivery.retrieval.metadata.adapters; import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import com.raytheon.edex.util.Util; import com.raytheon.uf.common.datadelivery.registry.GriddedCoverage; @@ -60,11 +62,18 @@ public class GridMetadataAdapter extends AbstractMetadataAdapter { Level[] levels = getLevels(attXML); int size = levels.length; + List ensembles = null; + if (attXML.getEnsemble() != null && attXML.getEnsemble().hasSelection()) { + ensembles = attXML.getEnsemble().getSelectedMembers(); + size *= ensembles.size(); + } else { + ensembles = Arrays.asList((String) null); + } + if (attXML.getTime().getSelectedTimeIndices() != null) { if (levels.length > 1 || attXML.getTime().getSelectedTimeIndices().size() > 1) { - size = levels.length - * attXML.getTime().getSelectedTimeIndices().size(); + size *= attXML.getTime().getSelectedTimeIndices().size(); } } @@ -80,20 +89,21 @@ public class GridMetadataAdapter extends AbstractMetadataAdapter { } if (attXML.getTime().getSelectedTimeIndices() != null) { - - for (int i = 0; i < attXML.getTime().getSelectedTimeIndices() - .size(); i++) { - for (int j = 0; j < levels.length; j++) { - int bin = (levels.length * i) + j; - pdos[bin] = populateGridRecord(attXML.getSubName(), - attXML.getParameter(), - levels[j], gridCoverage); + int bin = 0; + for (String ensemble : ensembles) { + for (int i = 0; i < attXML.getTime().getSelectedTimeIndices() + .size(); i++) { + for (int j = 0; j < levels.length; j++) { + pdos[bin++] = populateGridRecord(attXML.getSubName(), + attXML.getParameter(), levels[j], ensemble, + gridCoverage); + } } } } else { pdos[0] = populateGridRecord(attXML.getSubName(), - attXML.getParameter(), levels[0], + attXML.getParameter(), levels[0], ensembles.get(0), gridCoverage); } @@ -108,10 +118,9 @@ public class GridMetadataAdapter extends AbstractMetadataAdapter { * @return */ private GridRecord populateGridRecord(String name, Parameter parm, - Level level, - GridCoverage gridCoverage) { + Level level, String ensembleId, GridCoverage gridCoverage) { return ResponseProcessingUtilities.getGridRecord(name, parm, level, - gridCoverage); + ensembleId, gridCoverage); } /** diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPMetaDataParser.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPMetaDataParser.java index af804b230a..03457fd269 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPMetaDataParser.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPMetaDataParser.java @@ -37,6 +37,7 @@ import com.raytheon.uf.common.datadelivery.registry.DataSet; import com.raytheon.uf.common.datadelivery.registry.DataSetMetaData; import com.raytheon.uf.common.datadelivery.registry.DataType; import com.raytheon.uf.common.datadelivery.registry.GriddedCoverage; +import com.raytheon.uf.common.datadelivery.registry.GriddedDataSet; import com.raytheon.uf.common.datadelivery.registry.GriddedDataSetMetaData; import com.raytheon.uf.common.datadelivery.registry.Levels; import com.raytheon.uf.common.datadelivery.registry.OpenDapGriddedDataSet; @@ -88,6 +89,8 @@ import dods.dap.DAS; * Dec 12, 2012 supplement dhladky Restored operation of ensembles. * Dec 10, 2012 1259 bsteffen Switch Data Delivery from LatLon to referenced envelopes. * Jan 08, 2013 dhladky Performance enhancements, specific model fixes. + * Jan 18, 2013 1513 dhladky Level look up improvements. + * Jan 24, 2013 1527 dhladky Changed 0DEG to FRZ * * * @@ -134,8 +137,10 @@ class OpenDAPMetaDataParser extends MetaDataParser { // create new default lookups if (levelType.equals(LevelType.MB) || levelType.equals(LevelType.SEAB)) { + + List levelList = OpenDAPParseUtility.getInstance().parseLevels(gdsmd.getUrl(), serviceConfig.getConstantValue("LEV")); LookupManager.getInstance().modifyLevelLookups( - collectionName, dz, levMin, levMax); + collectionName, dz, levMin, levMax, levelList); } } @@ -179,7 +184,8 @@ class OpenDAPMetaDataParser extends MetaDataParser { * @param dataDateFormat * @return */ - private Map getParameters(DAS das, DataSet dataSet, + private Map getParameters(DAS das, + GriddedDataSet dataSet, GriddedDataSetMetaData gdsmd, Link link, Collection collection, String dataDateFormat) { @@ -336,7 +342,8 @@ class OpenDAPMetaDataParser extends MetaDataParser { if (das.getAttributeTable(ens) != null) { try { AttributeTable at = das.getAttributeTable(ens); - gdsmd.setEnsemble(OpenDAPParseUtility.getInstance().parseEnsemble(at)); + dataSet.setEnsemble(OpenDAPParseUtility.getInstance() + .parseEnsemble(at)); } catch (Exception en) { logParsingException(ens, "Ensemble", collectionName, url); } @@ -413,12 +420,6 @@ class OpenDAPMetaDataParser extends MetaDataParser { parm.setLevels(getLevels(type, collectionName, gdsmd, dz, levMin, levMax)); parm.addLevelType(type); - - // set if an ensemble member - if (gdsmd.getEnsemble() != null) { - parm.setEnsemble(gdsmd.getEnsemble().getSize()); - } - parameters.put(name, parm); } catch (Exception le) { @@ -493,6 +494,11 @@ class OpenDAPMetaDataParser extends MetaDataParser { type.addLayer(new Double(10).doubleValue()); type.setUnit(serviceConfig.getConstantValue("METER")); } + // FRZ freezing level, catches one's with on the end of the param name + // hgt0c etc + else if (param.getProviderName().endsWith(LevelType.FRZ.getLevelType())) { + type = new DataLevelType(LevelType.FRZ); + } // Really special cases presented by NOMADS data sets if (type == null) { @@ -572,8 +578,8 @@ class OpenDAPMetaDataParser extends MetaDataParser { type = new DataLevelType(LevelType.MSL); } else if (w1.equals(LevelType.EA.getLevelType())) { type = new DataLevelType(LevelType.EA); - } else if (w1.equals(LevelType.ODEG.getLevelType())) { - type = new DataLevelType(LevelType.ODEG); + } else if (w1.equals(LevelType.FRZ.getLevelType())) { + type = new DataLevelType(LevelType.FRZ); } else if (w1.equals(LevelType.LCY.getLevelType())) { type = new DataLevelType(LevelType.LCY); } else if (w1.equals(LevelType.MCY.getLevelType())) { @@ -656,12 +662,12 @@ class OpenDAPMetaDataParser extends MetaDataParser { } DAS das = (DAS) link.getLinks().get(DAP_TYPE.DAS.getDapType()); - dataSet.setParameters(getParameters(das, dataSet, gdsmd, link, - collection, dataDateFormat)); - + // set url first, used for level lookups gdsmd.setUrl(link.getUrl().replace( serviceConfig.getConstantValue("META_DATA_SUFFIX"), serviceConfig.getConstantValue("BLANK"))); + dataSet.setParameters(getParameters(das, dataSet, gdsmd, link, + collection, dataDateFormat)); Time dataSetTime = gdsmd.getTime(); if (dataSetTime == null) { throw new IllegalStateException( diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPParseUtility.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPParseUtility.java index 37c865d6c4..9ce0350fa0 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPParseUtility.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPParseUtility.java @@ -21,8 +21,13 @@ import com.raytheon.uf.common.datadelivery.retrieval.xml.UnitLookup; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.edex.datadelivery.retrieval.util.ConnectionUtil; import dods.dap.AttributeTable; +import dods.dap.DArray; +import dods.dap.DConnect; +import dods.dap.DataDDS; +import dods.dap.PrimitiveVector; /** * Constants for working with OpenDAP. This class should remain package-private, @@ -43,15 +48,18 @@ import dods.dap.AttributeTable; * Nov 09, 2012 1163 dhladky Made pre-load for service config * Nov 19, 2012 1166 djohnson Clean up JAXB representation of registry objects. * Jan 08, 2013 1466 dhladky NCOM dataset name parsing fix. + * Jan 18, 2013 1513 dhladky Level Lookup improvements. * * * @author dhladky * @version 1.0 */ -final class OpenDAPParseUtility { +public final class OpenDAPParseUtility { private static final Pattern QUOTES_PATTERN = Pattern.compile("\""); + private static final Pattern COMMA_PATTERN = Pattern.compile(","); + /** Singleton instance of this class */ private static OpenDAPParseUtility instance = null; @@ -252,35 +260,16 @@ final class OpenDAPParseUtility { */ public Ensemble parseEnsemble(AttributeTable table) { - String stime = serviceConfig.getConstantValue("TIMEINIT"); - String slength = serviceConfig.getConstantValue("LENGTH"); String sname = serviceConfig.getConstantValue("NAME"); - int size = new Integer(trim(table.getAttribute( - serviceConfig.getConstantValue("SIZE")).getValueAt(0))) - .intValue(); - String name = null; - String length = null; - String tinit = null; - - if (table.getAttribute(slength) != null) { - length = table.getAttribute(slength).getValueAt(0); - } + Ensemble ens = new Ensemble(); if (table.getAttribute(sname) != null) { - name = table.getAttribute(sname).getValueAt(0); + String name = trim(table.getAttribute(sname).getValueAt(0)); + String[] members = COMMA_PATTERN.split(name); + ens.setMembers(Arrays.asList(members)); } - - if (table.getAttribute(stime) != null) { - tinit = table.getAttribute(stime).getValueAt(0); - } - - Ensemble ens = new Ensemble(); - ens.setSize(size); - ens.setLength(length); - ens.setName(name); - ens.setInit(tinit); - return ens; + } /** @@ -353,7 +342,35 @@ final class OpenDAPParseUtility { return QUOTES_PATTERN.matcher(val).replaceAll( serviceConfig.getConstantValue("BLANK")); } - + /** + * Parse out the levels from the dods + * @param url + * @param lev + * @return + */ + public List parseLevels(String url, String lev) { + + List levels = null; + + try { + DConnect connect = ConnectionUtil.getDConnect(url + "?" + lev); + DataDDS data = connect.getData(null); + DArray array = (DArray) data.getVariable(lev); + PrimitiveVector pm = array.getPrimitiveVector(); + double[] values = (double[]) pm.getInternalStorage(); + levels = new ArrayList(); + for (double value : values) { + levels.add(value); + } + + } catch (Exception e) { + statusHandler.handle(Priority.PROBLEM, "Error downloading/parsing levels: " + + url, e); + } + + return levels; + + } } diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPRequestBuilder.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPRequestBuilder.java index 2aa40d5e24..f917f94bc0 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPRequestBuilder.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPRequestBuilder.java @@ -22,6 +22,7 @@ package com.raytheon.uf.edex.datadelivery.retrieval.opendap; import com.google.common.annotations.VisibleForTesting; import com.raytheon.uf.common.datadelivery.registry.Coverage; +import com.raytheon.uf.common.datadelivery.registry.Ensemble; import com.raytheon.uf.common.datadelivery.registry.GriddedCoverage; import com.raytheon.uf.common.datadelivery.registry.Levels; import com.raytheon.uf.common.datadelivery.registry.Parameter; @@ -216,17 +217,17 @@ class OpenDAPRequestBuilder extends RequestBuilder { */ public String processEnsemble() { - StringBuilder buf = new StringBuilder(); - - if (getRetrievalAttribute().getParameter().getEnsemble() != null) { - buf.append("[" - + (getRetrievalAttribute().getParameter().getEnsemble() - 1) - + "]"); + if (getRetrievalAttribute().getEnsemble() != null) { + Ensemble e = getRetrievalAttribute().getEnsemble(); + int[] range = e.getSelectedRange(); + if (range[0] == range[1]) { + return "[" + range[0] + "]"; + } else { + return "[" + range[0] + ":" + range[1] + "]"; + } } else { - buf.append(""); + return ""; } - - return buf.toString(); } @Override diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPRetrievalGenerator.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPRetrievalGenerator.java index 40fbe7ffdb..f05db83d6e 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPRetrievalGenerator.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/opendap/OpenDAPRetrievalGenerator.java @@ -22,14 +22,15 @@ package com.raytheon.uf.edex.datadelivery.retrieval.opendap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import com.google.common.annotations.VisibleForTesting; import com.raytheon.uf.common.datadelivery.registry.Coverage; import com.raytheon.uf.common.datadelivery.registry.DataSet; import com.raytheon.uf.common.datadelivery.registry.DataSetMetaData; +import com.raytheon.uf.common.datadelivery.registry.Ensemble; import com.raytheon.uf.common.datadelivery.registry.GriddedCoverage; import com.raytheon.uf.common.datadelivery.registry.GriddedDataSetMetaData; import com.raytheon.uf.common.datadelivery.registry.Levels; @@ -265,13 +266,14 @@ class OpenDAPRetrievalGenerator extends RetrievalGenerator { * @param parm * @return */ - protected HashMap> getGridDuplicates( + protected Map> getGridDuplicates( String name, - Parameter parm, ArrayList times, ArrayList levels, + Parameter parm, List times, List levels, + List ensembleMembers, GriddedCoverage cov) { return RetrievalGeneratorUtilities.findGridDuplicates(name, times, - levels, + levels, ensembleMembers, parm, cov.getRequestGridCoverage()); } @@ -319,6 +321,13 @@ class OpenDAPRetrievalGenerator extends RetrievalGenerator { return Collections.emptyList(); } + List ensembles = null; + if (sub.getEnsemble() == null) { + ensembles = Arrays.asList((Ensemble) null); + } else { + ensembles = sub.getEnsemble().split(1); + } + for (List timeSequence : subTime.getTimeSequences(sfactor)) { for (Parameter param : sub.getParameter()) { @@ -332,9 +341,11 @@ class OpenDAPRetrievalGenerator extends RetrievalGenerator { sub.getTime()); for (Time time : times) { - Retrieval retrieval = getRetrieval(sub, bundle, - param, paramLevels, time); - retrievals.add(retrieval); + for (Ensemble ensemble : ensembles) { + Retrieval retrieval = getRetrieval(sub, bundle, + param, paramLevels, time, ensemble); + retrievals.add(retrieval); + } } } else { @@ -350,9 +361,12 @@ class OpenDAPRetrievalGenerator extends RetrievalGenerator { // and time for (Time time : times) { for (Levels level : levels) { - Retrieval retrieval = getRetrieval(sub, - bundle, param, level, time); - retrievals.add(retrieval); + for (Ensemble ensemble : ensembles) { + Retrieval retrieval = getRetrieval(sub, + bundle, param, level, time, + ensemble); + retrievals.add(retrieval); + } } } } @@ -375,7 +389,7 @@ class OpenDAPRetrievalGenerator extends RetrievalGenerator { * @return */ private Retrieval getRetrieval(Subscription sub, SubscriptionBundle bundle, - Parameter param, Levels level, Time time) { + Parameter param, Levels level, Time time, Ensemble ensemble) { Retrieval retrieval = new Retrieval(); retrieval.setSubscriptionName(sub.getName()); @@ -404,6 +418,7 @@ class OpenDAPRetrievalGenerator extends RetrievalGenerator { lparam.setLevels(level); att.setTime(time); att.setParameter(lparam); + att.setEnsemble(ensemble); att.setSubName(retrieval.getSubscriptionName()); att.setPlugin(pt.getPlugin()); att.setProvider(sub.getProvider()); @@ -488,7 +503,6 @@ class OpenDAPRetrievalGenerator extends RetrievalGenerator { param.setBaseType(origParm.getBaseType()); param.setDataType(origParm.getDataType()); param.setDefinition(origParm.getDefinition()); - param.setEnsemble(origParm.getEnsemble()); param.setFillValue(origParm.getFillValue()); param.setLevelType(origParm.getLevelType()); param.setMissingValue(origParm.getMissingValue()); @@ -536,6 +550,13 @@ class OpenDAPRetrievalGenerator extends RetrievalGenerator { int sfactor = getSizingFactor(getDimensionalSize(sub.getCoverage())); + List ensembles = null; + if (sub.getEnsemble() != null && sub.getEnsemble().hasSelection()) { + ensembles = sub.getEnsemble().getSelectedMembers(); + } else { + ensembles = Arrays.asList((String) null); + } + for (List timeSequence : sub.getTime().getTimeSequences( sfactor)) { @@ -557,14 +578,14 @@ class OpenDAPRetrievalGenerator extends RetrievalGenerator { ArrayList levels = ResponseProcessingUtilities .getOpenDAPGridLevels(param.getLevels()); - HashMap> dups = getGridDuplicates( + Map> dups = getGridDuplicates( sub.getName(), - param, times, levels, + param, times, levels, ensembles, (GriddedCoverage) sub.getCoverage()); for (int i = 0; i < times.size(); i++) { DataTime dtime = times.get(i); - ArrayList levDups = dups.get(dtime); + List levDups = dups.get(dtime); if (levDups != null) { // single level, remove the time @@ -594,14 +615,14 @@ class OpenDAPRetrievalGenerator extends RetrievalGenerator { .getOpenDAPGridLevels(level); } - HashMap> dups = getGridDuplicates( - sub.getName(), - param, times, plevels, + Map> dups = getGridDuplicates( + sub.getName(), param, times, plevels, + ensembles, ((GriddedCoverage) sub.getCoverage())); for (int i = 0; i < times.size(); i++) { DataTime dtime = times.get(i); - ArrayList levDups = dups.get(dtime); + List levDups = dups.get(dtime); if (levDups != null) { diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/response/OpenDAPTranslator.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/response/OpenDAPTranslator.java index c3c790be13..75b4c933a0 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/response/OpenDAPTranslator.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/response/OpenDAPTranslator.java @@ -23,6 +23,7 @@ package com.raytheon.uf.edex.datadelivery.retrieval.response; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; +import java.util.List; import com.raytheon.uf.common.datadelivery.registry.GriddedCoverage; import com.raytheon.uf.common.datadelivery.retrieval.xml.RetrievalAttribute; @@ -149,33 +150,41 @@ public class OpenDAPTranslator extends RetrievalTranslator { PrimitiveVector pm = darray.getPrimitiveVector(); float[] values = (float[]) pm.getInternalStorage(); + List ensembles = null; + if (attXML.getEnsemble() != null && attXML.getEnsemble().hasSelection()) { + ensembles = attXML.getEnsemble().getSelectedMembers(); + } else { + ensembles = Arrays.asList((String) null); + } + // time dependencies int start = 0; - PluginDataObject[] records = new PluginDataObject[numLevels * numTimes]; + PluginDataObject[] records = new PluginDataObject[numLevels * numTimes + * ensembles.size()]; - for (int i = 0; i < times.size(); i++) { + int bin = 0; + for (int i = 0; i < ensembles.size(); i++) { + for (DataTime dataTime : times) { + for (int j = 0; j < numLevels; j++) { + PluginDataObject record = getPdo(bin); + record.setDataTime(dataTime); + record.constructDataURI(); - DataTime dataTime = times.get(i); + int end = start + gridSize; - for (int j = 0; j < numLevels; j++) { - int bin = (numLevels * i) + j; - PluginDataObject record = getPdo(bin); - record.setDataTime(dataTime); - record.constructDataURI(); + float[] subValues = Arrays.copyOfRange(values, start, end); - int end = start + gridSize; + subValues = GridMetadataAdapter.adjustGrid(nx, ny, + subValues, Float.parseFloat(attXML.getParameter() + .getMissingValue()), true); - float[] subValues = Arrays.copyOfRange(values, start, end); - - subValues = GridMetadataAdapter.adjustGrid(nx, ny, subValues, - Float.parseFloat(attXML.getParameter() - .getMissingValue()), true); - - record.setMessageData(subValues); - record.setOverwriteAllowed(true); - records[bin] = record; - statusHandler.info("Creating record: " + record.getDataURI()); - start = end; + record.setMessageData(subValues); + record.setOverwriteAllowed(true); + records[bin++] = record; + statusHandler.info("Creating record: " + + record.getDataURI()); + start = end; + } } } diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/ResponseProcessingUtilities.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/ResponseProcessingUtilities.java index bdd987f7b6..1250b30a4f 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/ResponseProcessingUtilities.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/ResponseProcessingUtilities.java @@ -61,7 +61,7 @@ public class ResponseProcessingUtilities { .getHandler(ResponseProcessingUtilities.class); public static GridRecord getGridRecord(String name, Parameter parm, - Level level, + Level level, String ensembleId, GridCoverage gridCoverage) { com.raytheon.uf.common.parameter.Parameter parameter = new com.raytheon.uf.common.parameter.Parameter(); @@ -75,7 +75,7 @@ public class ResponseProcessingUtilities { record.setLevel(level); record.setParameter(parameter); record.setDatasetId(name); - + record.setEnsembleId(ensembleId); return record; } diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/RetrievalGeneratorUtilities.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/RetrievalGeneratorUtilities.java index 31da7a43aa..09f717150a 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/RetrievalGeneratorUtilities.java +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/src/com/raytheon/uf/edex/datadelivery/retrieval/util/RetrievalGeneratorUtilities.java @@ -21,6 +21,8 @@ package com.raytheon.uf.edex.datadelivery.retrieval.util; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; +import java.util.Map; import com.raytheon.uf.common.datadelivery.registry.Parameter; import com.raytheon.uf.common.dataplugin.PluginException; @@ -87,35 +89,39 @@ public class RetrievalGeneratorUtilities { * @param cov * @return */ - public static HashMap> findGridDuplicates( - String name, - ArrayList times, ArrayList levels, Parameter parm, + public static Map> findGridDuplicates(String name, + List times, List levels, + List ensembleMembers, Parameter parm, GridCoverage cov) { - HashMap> dups = new HashMap>(); + HashMap> dups = new HashMap>(); for (DataTime time : times) { - ArrayList levDups = dups.get(time); + List levDups = dups.get(time); if (levDups == null) { levDups = new ArrayList(); } for (Level level : levels) { - try { + for (String ensembleMember : ensembleMembers) { + try { - GridRecord rec = ResponseProcessingUtilities.getGridRecord( - name, parm, level, cov); - rec.setDataTime(time); - rec.constructDataURI(); - boolean isDup = findDuplicateUri(rec.getDataURI(), "grid"); - if (isDup) { - levDups.add(level); + GridRecord rec = ResponseProcessingUtilities + .getGridRecord(name, parm, level, + ensembleMember, cov); + rec.setDataTime(time); + rec.constructDataURI(); + boolean isDup = findDuplicateUri(rec.getDataURI(), + "grid"); + if (isDup) { + levDups.add(level); + } + } catch (PluginException e) { + statusHandler.handle(Priority.PROBLEM, + e.getLocalizedMessage(), e); } - } catch (PluginException e) { - statusHandler.handle(Priority.PROBLEM, - e.getLocalizedMessage(), e); } } diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/utility/edex_static/base/stats/retrievalProcessStats.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/utility/edex_static/base/stats/retrievalProcessStats.xml new file mode 100644 index 0000000000..2759dde1d3 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.retrieval/utility/edex_static/base/stats/retrievalProcessStats.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.service/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.datadelivery.service/META-INF/MANIFEST.MF index bec6b2084d..ae74a38fbe 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.service/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.service/META-INF/MANIFEST.MF @@ -21,4 +21,5 @@ Require-Bundle: com.raytheon.uf.common.auth;bundle-version="1.12.1174", com.raytheon.uf.common.registry.event;bundle-version="1.0.0", com.raytheon.uf.common.event;bundle-version="1.0.0", com.google.guava;bundle-version="1.0.0", - com.raytheon.uf.common.datadelivery.event;bundle-version="1.0.0" + com.raytheon.uf.common.datadelivery.event;bundle-version="1.0.0", + com.raytheon.uf.common.datadelivery.service;bundle-version="1.0.0" diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.service/res/spring/datadelivery-request.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.service/res/spring/datadelivery-service-handlers.xml similarity index 65% rename from edexOsgi/com.raytheon.uf.edex.datadelivery.service/res/spring/datadelivery-request.xml rename to edexOsgi/com.raytheon.uf.edex.datadelivery.service/res/spring/datadelivery-service-handlers.xml index c9532a124d..3cd1b2f13d 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.service/res/spring/datadelivery-request.xml +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.service/res/spring/datadelivery-service-handlers.xml @@ -12,13 +12,24 @@ - + + + + - + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.service/src/com/raytheon/uf/edex/datadelivery/service/services/GroupDefinitionServiceHandler.java b/edexOsgi/com.raytheon.uf.edex.datadelivery.service/src/com/raytheon/uf/edex/datadelivery/service/services/GroupDefinitionServiceHandler.java new file mode 100644 index 0000000000..c2b9abb06c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.service/src/com/raytheon/uf/edex/datadelivery/service/services/GroupDefinitionServiceHandler.java @@ -0,0 +1,131 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.datadelivery.service.services; + +import java.util.List; + +import com.raytheon.uf.common.auth.exception.AuthorizationException; +import com.raytheon.uf.common.auth.user.IUser; +import com.raytheon.uf.common.datadelivery.registry.GroupDefinition; +import com.raytheon.uf.common.datadelivery.registry.GroupDefinitionServiceRequest; +import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; +import com.raytheon.uf.common.datadelivery.registry.handlers.ISubscriptionHandler; +import com.raytheon.uf.common.datadelivery.service.IGroupDefinitionService; +import com.raytheon.uf.common.datadelivery.service.ISubscriptionNotificationService; +import com.raytheon.uf.common.registry.handler.RegistryHandlerException; +import com.raytheon.uf.common.util.CollectionUtil; +import com.raytheon.uf.edex.auth.req.AbstractPrivilegedRequestHandler; +import com.raytheon.uf.edex.auth.resp.AuthorizationResponse; + +/** + * Handles request from the {@link IGroupDefinitionService}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 18, 2013 1441       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public class GroupDefinitionServiceHandler extends + AbstractPrivilegedRequestHandler { + + private final ISubscriptionNotificationService notificationService; + + /** + * Constructor. + * + * @param notificationService + * the subscription notification service + */ + public GroupDefinitionServiceHandler( + ISubscriptionNotificationService notificationService) { + this.notificationService = notificationService; + } + + /** + * {@inheritDoc} + */ + @Override + public Object handleRequest(GroupDefinitionServiceRequest request) + throws Exception { + final IUser user = request.getUser(); + switch (request.getType()) { + case DELETE: + handleDelete(request.getGroup(), user); + break; + } + return null; + } + + /** + * Handles the delete of a group. First it updates any subscriptions in the + * group to not have a group, and then deletes the actual group. + * + * @param user + * + * @param groupDefinition + * @return + * @throws RegistryHandlerException + */ + private void handleDelete(GroupDefinition group, IUser user) + throws RegistryHandlerException { + + ISubscriptionHandler handler = DataDeliveryHandlers + .getSubscriptionHandler(); + List subsForGroup = handler.getByGroupName(group + .getGroupName()); + if (!CollectionUtil.isNullOrEmpty(subsForGroup)) { + for (Subscription sub : subsForGroup) { + sub.setGroupName(GroupDefinition.NO_GROUP); + handler.update(sub); + + // TODO: Would be nice to use a subset of the + // SubscriptionService functionality here so we didn't have to + // manually send the subscription updated notification + String username = user != null ? user.uniqueId().toString() + : "none"; + notificationService.sendUpdatedSubscriptionNotification(sub, + username); + } + } + + DataDeliveryHandlers.getGroupDefinitionHandler().delete(group); + } + + /** + * {@inheritDoc} + */ + @Override + public AuthorizationResponse authorized(IUser user, + GroupDefinitionServiceRequest request) + throws AuthorizationException { + return new AuthorizationResponse(true); + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.log/src/com/raytheon/uf/edex/log/EdexLogHandler.java b/edexOsgi/com.raytheon.uf.edex.log/src/com/raytheon/uf/edex/log/EdexLogHandler.java index a4b472d85e..54a7d64a16 100644 --- a/edexOsgi/com.raytheon.uf.edex.log/src/com/raytheon/uf/edex/log/EdexLogHandler.java +++ b/edexOsgi/com.raytheon.uf.edex.log/src/com/raytheon/uf/edex/log/EdexLogHandler.java @@ -98,11 +98,11 @@ public class EdexLogHandler implements IUFStatusHandler { */ @Override public void handle(UFStatus status) { - handle(status, this.category); - } + handle(status, this.category); + } - @Override - public void handle(UFStatus status, String category) { + @Override + public void handle(UFStatus status, String category) { Priority p = status.getPriority(); String statusMsg = status.getMessage(); if (category != null) { @@ -154,11 +154,14 @@ public class EdexLogHandler implements IUFStatusHandler { @Override public void handle(Priority p, String msg) { - handle(p, this.category, msg); - } + handle(p, this.category, msg); + } - @Override - public void handle(Priority p, String category, String msg) { + @Override + public void handle(Priority p, String category, String msg) { + // msg has been null if someone does e.getLocalizedMessage() + // and it is null which causes null pointer exception + msg = String.valueOf(msg); if (category != null) { StringBuilder sb = new StringBuilder(msg.length() + 64); sb.append(category); @@ -197,13 +200,13 @@ public class EdexLogHandler implements IUFStatusHandler { @Override public void handle(Priority p, String msg, Throwable t) { - handle(p, category, msg, t); - } + handle(p, category, msg, t); + } - @Override - public void handle(Priority p, String category, String msg, Throwable t) { - // msg has been null if someone does e.getLocalizedMessage() - // and it is null which causes null pointer exception + @Override + public void handle(Priority p, String category, String msg, Throwable t) { + // msg has been null if someone does e.getLocalizedMessage() + // and it is null which causes null pointer exception msg = String.valueOf(msg); if (category != null) { StringBuilder sb = new StringBuilder(msg.length() + 64); @@ -249,21 +252,21 @@ public class EdexLogHandler implements IUFStatusHandler { } @Override - public void debug(String category, String message) { - if (this.clazzLogger.isDebugEnabled()) { - handle(Priority.DEBUG, category, message); - } - } + public void debug(String category, String message) { + if (this.clazzLogger.isDebugEnabled()) { + handle(Priority.DEBUG, category, message); + } + } - @Override + @Override public void info(String message) { handle(Priority.INFO, message); } - @Override - public void info(String category, String message) { - handle(Priority.INFO, category, message); - } + @Override + public void info(String category, String message) { + handle(Priority.INFO, category, message); + } @Override public void warn(String message) { @@ -271,38 +274,38 @@ public class EdexLogHandler implements IUFStatusHandler { } @Override - public void warn(String category, String message) { - handle(Priority.WARN, category, message); - } + public void warn(String category, String message) { + handle(Priority.WARN, category, message); + } - @Override + @Override public void error(String message) { handle(Priority.ERROR, message); } @Override - public void error(String category, String message) { - handle(Priority.ERROR, category, message); - } + public void error(String category, String message) { + handle(Priority.ERROR, category, message); + } - @Override + @Override public void error(String message, Throwable throwable) { handle(Priority.ERROR, message, throwable); } @Override - public void error(String category, String message, Throwable throwable) { - handle(Priority.ERROR, category, message, throwable); - } + public void error(String category, String message, Throwable throwable) { + handle(Priority.ERROR, category, message, throwable); + } - @Override + @Override public void fatal(String message, Throwable throwable) { handle(Priority.FATAL, message, throwable); } - @Override - public void fatal(String category, String message, Throwable throwable) { - handle(Priority.FATAL, category, message, throwable); - } + @Override + public void fatal(String category, String message, Throwable throwable) { + handle(Priority.FATAL, category, message, throwable); + } } diff --git a/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/ArealQpeGenSrv.java b/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/ArealQpeGenSrv.java index a6411a4ec1..29e73a95a8 100644 --- a/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/ArealQpeGenSrv.java +++ b/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/ArealQpeGenSrv.java @@ -70,6 +70,7 @@ import com.vividsolutions.jts.geom.Coordinate; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Jan 26, 2011 snaples Initial creation + * Jan 10, 2013 1448 bgonzale Added app context check in processArealQpe(). * * * @@ -209,6 +210,9 @@ public class ArealQpeGenSrv { private SimpleDateFormat fdf = new SimpleDateFormat("yyyyMMddHH"); public Object processArealQpe() { + if (!AppsDefaults.getInstance().setAppContext(this)) { + return null; + } // Check to see if we need to run String gen = appsDefaults.getToken("mpe_generate_areal_qpe"); diff --git a/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/MpeLightningSrv.java b/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/MpeLightningSrv.java index 98653ac91e..f1e80fe538 100644 --- a/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/MpeLightningSrv.java +++ b/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/MpeLightningSrv.java @@ -37,6 +37,7 @@ import com.raytheon.uf.common.datastorage.DataStoreFactory; import com.raytheon.uf.common.datastorage.IDataStore; import com.raytheon.uf.common.datastorage.StorageException; import com.raytheon.uf.common.hydro.spatial.HRAP; +import com.raytheon.uf.common.ohd.AppsDefaults; import com.raytheon.uf.edex.core.EdexException; import com.raytheon.uf.edex.core.props.EnvProperties; import com.raytheon.uf.edex.core.props.PropertiesFactory; @@ -54,6 +55,7 @@ import com.vividsolutions.jts.geom.Coordinate; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Jan 06, 2011 5951 jnjanga Initial creation + * Jan 10, 2013 1448 bgonzale Added app context check in runOnSchedule(). * * * @@ -218,6 +220,9 @@ public class MpeLightningSrv { * @throws EdexException */ public void runOnSchedule() throws EdexException { + if (!AppsDefaults.getInstance().setAppContext(this)) { + return; + } QueryResultRow[] rows = getMostRecentStrikes(); ifhsInsertMostRecentStrikes(rows); } diff --git a/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/MpeRUCFreezingLevel.java b/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/MpeRUCFreezingLevel.java index 954bae7509..9e525fef4e 100644 --- a/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/MpeRUCFreezingLevel.java +++ b/edexOsgi/com.raytheon.uf.edex.ohd/src/com/raytheon/uf/edex/ohd/pproc/MpeRUCFreezingLevel.java @@ -55,24 +55,24 @@ import com.raytheon.uf.edex.core.props.PropertiesFactory; import com.raytheon.uf.edex.dat.utils.FreezingLevel; import com.vividsolutions.jts.geom.Coordinate; +/** + * MPE RUC calculator + * + *
+ * SOFTWARE HISTORY
+ * Date         Ticket#  Engineer    Description
+ * ------------ -------- --------- --------------------------
+ * Nov 19, 2011          dhladky    Initial Creation.
+ * Oct 09, 2012 15168    wkwock     Fix incorrect values.
+ * Jan 10, 2013 1448     bgonzale   Made methods that are used internally private.
+ * 
+ * 
+ * + * @author dhladky + * @version 1.0 + */ public class MpeRUCFreezingLevel { - /** - * MPE RUC calculator - * - *
-     * SOFTWARE HISTORY
-     * Date         Ticket#  Engineer    Description
-     * ------------ -------- --------- --------------------------
-     * Nov 19, 2011          dhladky    Initial Creation.
-     * Oct 09, 2012 15168    wkwock     Fix incorrect values.
-     * 
-     * 
- * - * @author dhladky - * @version 1.0 - */ - private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(MpeRUCFreezingLevel.class); @@ -441,7 +441,7 @@ public class MpeRUCFreezingLevel { * * @return */ - public String getAbsoluteTempFileName(int forecastHour, String modelName) { + private String getAbsoluteTempFileName(int forecastHour, String modelName) { return modelOutputFilePath + File.separatorChar + modelName + forecastHour + "zFreezingLevel" + ".bin"; } @@ -451,7 +451,7 @@ public class MpeRUCFreezingLevel { * * @return */ - public String getAbsoluteOutFileName(Date date, String site) { + private String getAbsoluteOutFileName(Date date, String site) { return modelOutputFilePath + File.separatorChar + "freezing_1_" + site + "_point_" + getFormattedDate(date); } @@ -461,7 +461,7 @@ public class MpeRUCFreezingLevel { * * @param FreezingLevelXML */ - public void writeFreezingLevelTemp(FreezingLevelXML freezingLevel, + private void writeFreezingLevelTemp(FreezingLevelXML freezingLevel, String modelName) { try { diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.cwa/utility/edex_static/base/distribution/cwa.xml b/edexOsgi/com.raytheon.uf.edex.plugin.cwa/utility/edex_static/base/distribution/cwa.xml index 3510a85960..a6fdefdf81 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.cwa/utility/edex_static/base/distribution/cwa.xml +++ b/edexOsgi/com.raytheon.uf.edex.plugin.cwa/utility/edex_static/base/distribution/cwa.xml @@ -20,5 +20,5 @@ --> ^FAAK2.* - ^FAUS2.* + ^FAUS2[0-6].* diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/res/spring/ffmp-ingest.xml b/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/res/spring/ffmp-ingest.xml index 7e563040f4..5ac1430bef 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/res/spring/ffmp-ingest.xml +++ b/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/res/spring/ffmp-ingest.xml @@ -14,8 +14,8 @@
- - + + diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/FFMPGenerator.java b/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/FFMPGenerator.java index 74dc7d497c..9b743dc7de 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/FFMPGenerator.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/FFMPGenerator.java @@ -31,15 +31,19 @@ import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.regex.Pattern; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; import com.raytheon.edex.msg.DataURINotificationMessage; import com.raytheon.edex.plugin.radar.dao.RadarStationDao; import com.raytheon.edex.urifilter.URIFilter; import com.raytheon.edex.urifilter.URIGenerateMessage; +import com.raytheon.uf.common.dataplugin.ffmp.FFMPAggregateRecord; import com.raytheon.uf.common.dataplugin.ffmp.FFMPBasinData; import com.raytheon.uf.common.dataplugin.ffmp.FFMPDataContainer; import com.raytheon.uf.common.dataplugin.ffmp.FFMPRecord; @@ -79,6 +83,7 @@ import com.raytheon.uf.common.serialization.SerializationUtil; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.common.util.FileUtil; import com.raytheon.uf.edex.core.EDEXUtil; import com.raytheon.uf.edex.core.props.PropertiesFactory; @@ -105,6 +110,7 @@ import com.raytheon.uf.edex.plugin.ffmp.common.FFTIProcessor; * 06/21/2009 2521 dhladky Initial Creation. * 02/03/2011 6500 cjeanbap Fixed NullPointerException. * 07/31/2011 578 dhladky FFTI modifications + * 01/27/13 1478 D. Hladky Added creation of full cache records to help read write stress on NAS * * * @author dhladky @@ -134,6 +140,18 @@ public class FFMPGenerator extends CompositeProductGenerator implements private static final String productType = "ffmp"; + /** + * The thought was this will eventually be dynamic when We start writing + * long time source records to a DAO. This is the time backward limit for FFTI and cache load data. + */ + public static final int SOURCE_CACHE_TIME = 6; + + /** + * The thought was this will eventually be dynamic, static in AWIPS I. + * This is the time back limit for Flash Flood Guidance sources + */ + public static final int FFG_SOURCE_CACHE_TIME = 24; + /** ArrayList of domains to filter for */ private ArrayList domains = null; @@ -199,7 +217,7 @@ public class FFMPGenerator extends CompositeProductGenerator implements this.pathManager = PathManagerFactory.getPathManager(); - statusHandler.handle(Priority.DEBUG, getGeneratorName() + statusHandler.handle(Priority.INFO, getGeneratorName() + " process Filter Config..."); domains = new ArrayList(); boolean configValid = getRunConfig().isPopulated(); @@ -418,7 +436,7 @@ public class FFMPGenerator extends CompositeProductGenerator implements } } else { statusHandler - .debug(getGeneratorName() + .info(getGeneratorName() + ": templates not loaded yet. Skipping product"); } } @@ -500,7 +518,8 @@ public class FFMPGenerator extends CompositeProductGenerator implements statusHandler.handle(Priority.DEBUG, "Checking status ..." + fftiDone); } catch (InterruptedException e) { - e.printStackTrace(); + statusHandler.handle(Priority.DEBUG, + "Checking status failed!" + e); } } @@ -574,16 +593,19 @@ public class FFMPGenerator extends CompositeProductGenerator implements @Override public void run() { try { - logger.debug("ProcessProduct: Starting thread " - + ffmpProduct.getSourceName()); + statusHandler.handle( + Priority.DEBUG, + "ProcessProduct: Starting thread " + + ffmpProduct.getSourceName()); process(); - logger.debug("ProcessProduct: Finishing thread " - + ffmpProduct.getSourceName()); + statusHandler.handle( + Priority.DEBUG, + "ProcessProduct: Finishing thread " + + ffmpProduct.getSourceName()); } catch (Exception e) { processes.remove(ffmpProduct.getSourceName()); - logger.error("ProcessProduct: removed " - + ffmpProduct.getSourceName()); - e.printStackTrace(); + statusHandler.handle(Priority.ERROR, "ProcessProduct: removed " + + ffmpProduct.getSourceName(), e); } } @@ -713,7 +735,6 @@ public class FFMPGenerator extends CompositeProductGenerator implements generator, ffmpRec, ffmp.getFFTISource()); fftiSources.add(ffmp.getFFTISource()); - // System.out.println("Adding source to FFTISources!!!!!!!!!!!!"+ffmpRec.getSourceName()); ffti.processFFTI(); } } @@ -735,7 +756,7 @@ public class FFMPGenerator extends CompositeProductGenerator implements while (productKeys.size() > 0) { // wait for all threads to finish before returning try { - Thread.sleep(50); + Thread.sleep(100); statusHandler.handle(Priority.DEBUG, "Checking status ..." + productKeys.size()); for (String source : productKeys.keySet()) { @@ -743,7 +764,8 @@ public class FFMPGenerator extends CompositeProductGenerator implements "Still processing ..." + source); } } catch (InterruptedException e) { - e.printStackTrace(); + statusHandler.handle(Priority.WARN, + "Product Procesing Interrupted! " + e); } } } @@ -865,7 +887,8 @@ public class FFMPGenerator extends CompositeProductGenerator implements try { Thread.sleep(100); } catch (InterruptedException e) { - + statusHandler.handle(Priority.WARN, + "Domain processing Interrupted!", e); } } } @@ -974,8 +997,8 @@ public class FFMPGenerator extends CompositeProductGenerator implements getAbsoluteSourceFileName(sourceId)); try { - sbl = (SourceBinList) SerializationUtil - .transformFromThrift(FileUtil.file2bytes(f.getFile(), true)); + sbl = SerializationUtil + .transformFromThrift(SourceBinList.class, FileUtil.file2bytes(f.getFile(), true)); } catch (FileNotFoundException fnfe) { statusHandler.handle(Priority.ERROR, "Unable to locate file " + f.getName()); @@ -983,7 +1006,8 @@ public class FFMPGenerator extends CompositeProductGenerator implements statusHandler.handle(Priority.ERROR, "Unable to read file " + f.getName()); } catch (IOException ioe) { - ioe.printStackTrace(); + statusHandler.handle(Priority.ERROR, "General IO problem with file " + + f.getName(), ioe); } return sbl; @@ -1092,7 +1116,7 @@ public class FFMPGenerator extends CompositeProductGenerator implements statusHandler.handle( Priority.ERROR, "Unable to locate new FFG file. " - + pattern.toString()); + + pattern.toString(), e); } } } @@ -1124,11 +1148,8 @@ public class FFMPGenerator extends CompositeProductGenerator implements siteKey = parts[0]; } - container = loadFFMPDataContainer(siteSourceKey, - - hucs, siteKey, - - config.getCWA(), backDate); + container = loadFFMPDataContainer(siteSourceKey, hucs, siteKey, + config.getCWA(), backDate); if (container != null) { ffmpData.put(siteSourceKey, container); @@ -1200,7 +1221,6 @@ public class FFMPGenerator extends CompositeProductGenerator implements statusHandler.handle(Priority.ERROR, getGeneratorName() + ": filter: " + filter.getName() + ": failed to route filter to generator", e); - e.printStackTrace(); } filter.setValidTime(new Date(System.currentTimeMillis())); @@ -1262,7 +1282,7 @@ public class FFMPGenerator extends CompositeProductGenerator implements boolean write = true; try { - // write out the fast loader buddy file + // write out the fast loader cache file long ptime = System.currentTimeMillis(); SourceXML source = getSourceConfig().getSource( @@ -1274,15 +1294,16 @@ public class FFMPGenerator extends CompositeProductGenerator implements sourceName = source.getDisplayName(); sourceSiteDataKey = sourceName; // FFG is so infrequent go back a day - backDate = new Date(config.getDate().getTime() - - (3600 * 1000 * 24)); + backDate = new Date( + config.getDate().getTime() + - (TimeUtil.MILLIS_PER_HOUR * FFG_SOURCE_CACHE_TIME)); } else { sourceName = ffmpRec.getSourceName(); sourceSiteDataKey = sourceName + "-" + ffmpRec.getSiteKey() + "-" + dataKey; backDate = new Date(ffmpRec.getDataTime().getRefTime() .getTime() - - (3600 * 1000 * 6)); + - (TimeUtil.MILLIS_PER_HOUR * SOURCE_CACHE_TIME)); } // deal with setting of needed HUCS @@ -1336,7 +1357,7 @@ public class FFMPGenerator extends CompositeProductGenerator implements if (newDate != null && oldDate != null) { if ((ffmpRec.getDataTime().getRefTime().getTime() - newDate .getTime()) >= (source - .getExpirationMinutes(ffmpRec.getSiteKey()) * 60 * 1000)) { + .getExpirationMinutes(ffmpRec.getSiteKey()) * TimeUtil.MILLIS_PER_MINUTE)) { // force a re-query back to the newest time in // existing source container, this will fill in // gaps @@ -1348,10 +1369,12 @@ public class FFMPGenerator extends CompositeProductGenerator implements ffmpRec.getWfo(), source, ffmpRec .getSiteKey()); - } else if (oldDate.after(new Date(backDate - .getTime() - - (source.getExpirationMinutes(ffmpRec - .getSiteKey()) * 60 * 1000)))) { + } else if (oldDate + .after(new Date( + backDate.getTime() + - (source + .getExpirationMinutes(ffmpRec + .getSiteKey()) * TimeUtil.MILLIS_PER_MINUTE)))) { // force a re-query back to barrierTime for // existing source container, this happens if // the @@ -1423,14 +1446,14 @@ public class FFMPGenerator extends CompositeProductGenerator implements // this is defensive for if errors get thrown if (backDate == null) { backDate = new Date((System.currentTimeMillis()) - - (3600 * 1000 * 6)); + - (TimeUtil.MILLIS_PER_HOUR * SOURCE_CACHE_TIME)); } fdc.purge(backDate); if (write) { // write it out - writeLoaderBuddyFiles(fdc); + writeCacheFiles(fdc); } } } @@ -1451,37 +1474,31 @@ public class FFMPGenerator extends CompositeProductGenerator implements long time = System.currentTimeMillis(); FFMPDataContainer fdc = null; + FFMPAggregateRecord record = null; + boolean populated = false; - synchronized (hucs) { - for (String huc : hucs) { - - FFMPBasinData basinData = null; - - if (checkBuddyFile(sourceSiteDataKey, huc, wfo, backDate)) { - try { - basinData = readLoaderBuddyFile(sourceSiteDataKey, huc, - wfo, backDate); - } catch (Exception e) { - statusHandler.handle( - Priority.ERROR, - "General Error Reading buddy file: " - + e.getMessage()); - } - - if (fdc == null) { - fdc = new FFMPDataContainer(sourceSiteDataKey, hucs); - } - } - - if (basinData != null) { - fdc.setBasinBuddyData(basinData, huc); - } + if (checkCacheFile(sourceSiteDataKey, wfo, backDate)) { + try { + record = readCacheFile(sourceSiteDataKey, wfo, backDate); + } catch (Exception e) { + statusHandler.handle(Priority.ERROR, + "General Error Reading cache file: " + e.getMessage()); } + + if (fdc == null && record != null) { + // creates a place holder for this source + fdc = new FFMPDataContainer(sourceSiteDataKey, hucs, record); + populated = true; + } + } + + if (record != null && !populated) { + fdc.setCacheData(record); } if (fdc != null) { long time2 = System.currentTimeMillis(); - statusHandler.handle(Priority.DEBUG, "Loaded Source files: in " + statusHandler.handle(Priority.INFO, "Loaded Source files: in " + (time2 - time) + " ms: source: " + sourceSiteDataKey); } @@ -1489,60 +1506,59 @@ public class FFMPGenerator extends CompositeProductGenerator implements } /** - * Load existing buddy file + * Load existing cache file * * @param sourceSiteDataKey - * @param huc * @param wfo * @return * @throws IOException */ - private FFMPBasinData readLoaderBuddyFile(String sourceSiteDataKey, - String huc, String wfo, Date backDate) throws IOException { + private FFMPAggregateRecord readCacheFile(String sourceSiteDataKey, String wfo, + Date backDate) throws IOException { - File file = new File(sharePath + wfo + "/" + sourceSiteDataKey + "-" - + huc + ".bin"); - FFMPBasinData basinData = null; - BufferedInputStream is = null; + File file = new File(sharePath + wfo + "/" + sourceSiteDataKey + ".bin"); + FFMPAggregateRecord record = null; + GZIPInputStream gis = null; try { - is = new BufferedInputStream(new FileInputStream(file)); + gis = new GZIPInputStream(new BufferedInputStream(new FileInputStream(file))); DynamicSerializationManager dsm = DynamicSerializationManager .getManager(SerializationType.Thrift); - basinData = (FFMPBasinData) dsm.deserialize(is); + record = (FFMPAggregateRecord) dsm.deserialize(gis); } catch (SerializationException e) { statusHandler .handle(Priority.ERROR, - "Serialization Error Reading buddy file: " + "Serialization Error Reading cache file: " + e.getMessage()); + } catch (IOException e) { statusHandler.handle(Priority.ERROR, - "IO Error Reading buddy file: " + e.getMessage()); + "IO Error Reading cache file: " + e.getMessage()); } catch (Exception e) { statusHandler.handle(Priority.ERROR, - "General Error Reading buddy file: " + e.getMessage()); + "General Error Reading cache file: " + e.getMessage()); } catch (Throwable t) { statusHandler.handle(Priority.ERROR, - "Bogus Thrift Error Reading buddy file: " + t.getMessage()); + "Bogus Thrift Error Reading cache file: " + t.getMessage()); } finally { - if (is != null) { - is.close(); + if (gis != null) { + gis.close(); } } - return basinData; + return record; } /** - * Write buddy file + * Write cache file * * @param sourceSiteDataKey * @param huc * @param wfo * @return */ - public void writeLoaderBuddyFiles(FFMPDataContainer fdc) { + public void writeCacheFiles(FFMPDataContainer fdc) { // Write all huc levels in separate files File fileDir = new File("" + sharePath + config.getCWA()); @@ -1555,7 +1571,7 @@ public class FFMPGenerator extends CompositeProductGenerator implements } /** - * Inner class to thread writing of BuddyFiles + * Inner class to thread writing of cache files * * @author dhladky * @@ -1569,7 +1585,7 @@ public class FFMPGenerator extends CompositeProductGenerator implements long time = System.currentTimeMillis(); write(); long time2 = System.currentTimeMillis(); - statusHandler.handle(Priority.DEBUG, "Wrote loader files: in " + statusHandler.handle(Priority.INFO, "Wrote cache file: in " + (time2 - time) + " ms :" + fdc.getFilePath()); } catch (Exception e) { statusHandler.handle(Priority.ERROR, @@ -1604,61 +1620,69 @@ public class FFMPGenerator extends CompositeProductGenerator implements if (lockfile.canWrite()) { // write the lock if we can even write to anything - synchronized (fdc.getKeys()) { - for (String huc : fdc.getKeys()) { + FFMPAggregateRecord cacheRecord = null; - FFMPBasinData fbd = fdc.getBasinData(huc); + synchronized (fdc) { - if (fbd.getBasins().size() > 0) { + cacheRecord = new FFMPAggregateRecord(); + // times for Guidance basins will be null + cacheRecord.setTimes(fdc.getOrderedTimes()); - String tmpFilePath = fileName + "-" + huc - + ".tmp"; - BufferedOutputStream os = null; + for (Entry entry : fdc + .getBasinMap().entrySet()) { + FFMPBasinData fbd = entry.getValue(); + fbd.setCache(); + cacheRecord.setBasinData(fbd); + } + } - try { - File file = new File(tmpFilePath); - file.createNewFile(); + if (cacheRecord.getBasinsMap().size() > 0) { - if (file.canWrite()) { - os = new BufferedOutputStream( - new FileOutputStream(file)); - DynamicSerializationManager dsm = DynamicSerializationManager - .getManager(SerializationType.Thrift); - dsm.serialize(fbd, os); - fileNames.put(tmpFilePath, fileName - + "-" + huc + ".bin"); - } else { - statusHandler - .handle(Priority.WARN, - "Can not write buddy file: " - + file.getAbsolutePath()); - } - } catch (SerializationException e) { - statusHandler.handle(Priority.ERROR, - "Serialization Error Writing buddy file: " - + e.getMessage()); - } catch (IOException e) { - statusHandler.handle(Priority.ERROR, - "IO Error Writing buddy file: " - + e.getMessage()); - } catch (Exception e) { - statusHandler.handle(Priority.ERROR, - "General Error Writing buddy file: " - + e.getMessage()); - } finally { - if (os != null) { - os.close(); - } - } + String tmpFilePath = fileName + ".tmp"; + GZIPOutputStream gos = null; + + try { + File file = new File(tmpFilePath); + file.createNewFile(); + + if (file.canWrite()) { + gos = new GZIPOutputStream(new BufferedOutputStream( + new FileOutputStream(file))); + DynamicSerializationManager dsm = DynamicSerializationManager + .getManager(SerializationType.Thrift); + dsm.serialize(cacheRecord, gos); + fileNames.put(tmpFilePath, fileName + + ".bin"); + } else { + statusHandler.handle( + Priority.WARN, + "Can not write cache file: " + + file.getAbsolutePath()); + } + } catch (SerializationException e) { + statusHandler.handle(Priority.ERROR, + "Serialization Error Writing cache file: " + + e.getMessage()); + } catch (IOException e) { + statusHandler.handle( + Priority.ERROR, + "IO Error Writing cache file: " + + e.getMessage()); + } catch (Exception e) { + statusHandler.handle(Priority.ERROR, + "General Error Writing cache file: " + + e.getMessage()); + } finally { + if (gos != null) { + gos.close(); } } } } + } catch (Exception e) { - statusHandler - .handle(Priority.ERROR, - "Error writing Buddy File group: " - + e.getMessage()); + statusHandler.handle(Priority.ERROR, + "Error writing cache File: " + e.getMessage()); } finally { // rename the files to real path try { @@ -1684,31 +1708,29 @@ public class FFMPGenerator extends CompositeProductGenerator implements } catch (Exception e) { statusHandler.handle( Priority.ERROR, - "IO Error Renaming buddy file: " + "IO Error Renaming cache file: " + e.getMessage()); } } } catch (Exception e) { statusHandler.handle(Priority.ERROR, - "IO Error writing buddy files: " + e.getMessage()); + "IO Error writing cache files: " + e.getMessage()); } } } /** - * Load existing buddy file + * Load existing cache file * * @param sourceSiteDataKey - * @param huc * @param wfo * @return */ - public boolean checkBuddyFile(String sourceSiteDataKey, String huc, - String wfo, Date backDate) { + public boolean checkCacheFile(String sourceSiteDataKey, String wfo, + Date backDate) { - File file = new File(sharePath + wfo + "/" + sourceSiteDataKey + "-" - + huc + ".bin"); + File file = new File(sharePath + wfo + "/" + sourceSiteDataKey + ".bin"); String sourceName = sourceSiteDataKey.split("-")[0]; SourceXML source = getSourceConfig().getSourceByDisplayName(sourceName); @@ -1875,8 +1897,8 @@ public class FFMPGenerator extends CompositeProductGenerator implements getAbsoluteFFTIFileName(fftiName)); try { - ffti = (FFTIData) SerializationUtil.transformFromThrift(FileUtil - .file2bytes(f.getFile(), true)); + ffti = SerializationUtil.transformFromThrift(FFTIData.class, + FileUtil.file2bytes(f.getFile(), true)); } catch (FileNotFoundException fnfe) { statusHandler.handle(Priority.ERROR, "Unable to locate file " + f.getName(), fnfe); diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFMPConfig.java b/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFMPConfig.java index 4be04071ce..68459bae77 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFMPConfig.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFMPConfig.java @@ -221,12 +221,12 @@ public class FFMPConfig { } /** - * Get the DHR record + * Get the RADAR record * * @param uri * @return */ - private Object getDHRRecord(String uri) { + private Object getRADARRecord(String uri) { Object record = null; try { record = ScanCommonUtils.getRadarRecord(uri); @@ -398,7 +398,7 @@ public class FFMPConfig { } else if (source.getDataType().equals( FFMPSourceConfigurationManager.DATA_TYPE.RADAR .getDataType())) { - Object dataObject = getDHRRecord(dataUri); + Object dataObject = getRADARRecord(dataUri); if (dataObject != null) { // process as a VGB too diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFMPInterpolatedGuidanceDelay.java b/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFMPInterpolatedGuidanceDelay.java index be051647fa..c192b23d84 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFMPInterpolatedGuidanceDelay.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFMPInterpolatedGuidanceDelay.java @@ -22,6 +22,7 @@ package com.raytheon.uf.edex.plugin.ffmp.common; import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Map.Entry; import com.raytheon.uf.common.dataplugin.ffmp.FFMPBasin; @@ -30,6 +31,7 @@ import com.raytheon.uf.common.dataplugin.ffmp.FFMPDataContainer; import com.raytheon.uf.common.dataplugin.ffmp.FFMPGuidanceBasin; import com.raytheon.uf.common.dataplugin.ffmp.FFMPRecord; import com.raytheon.uf.common.monitor.xml.SourceXML; +import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.edex.plugin.ffmp.FFMPGenerator; /** @@ -41,6 +43,7 @@ import com.raytheon.uf.edex.plugin.ffmp.FFMPGenerator; * ------------ ---------- ----------- -------------------------- * 29 July, 2011 6772 dhladky Initial creation * 29 July, 2012 578 dhladky memory work + * 27 Jan, 2013 1478 dhladky Changed arraylist to list for times, more constants * * * @author dhladky @@ -96,15 +99,16 @@ public class FFMPInterpolatedGuidanceDelay { qpeContainer = generator.getFFMPDataContainer(qpeSource.getSourceName() + "-" + siteKey + "-" + siteKey, hucs, backDate); - long expirationTime = qpeSource.getExpirationMinutes(siteKey) * 60 * 1000; - // determine lag_time + long expirationTime = qpeSource.getExpirationMinutes(siteKey) + * TimeUtil.MILLIS_PER_MINUTE; + // determine lag_time long lagTime = (currentRecord.getDataTime().getRefTime().getTime()) - + (long) (ffgSource.getDurationHour() * 60 * 1000); + + (long) (ffgSource.getDurationHour() * TimeUtil.MILLIS_PER_MINUTE); // Determine hour fraction. int fraction_Hr = (int) (((float) (currentRecord.getDataTime() .getRefTime().getTime() - (lagTime - guidFrequency))) / (float) guidFrequency); // Gets the ordered times for QPE - ArrayList orderedTimes = qpeContainer + List orderedTimes = qpeContainer .getOrderedTimes(currentRecord.getDataTime().getRefTime()); // EQUATION: Guid = GuidOld + R i/d (GuidNew - GuidOld) diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFTI.java b/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFTI.java index 022f857a15..dafc0fbcc0 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFTI.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.ffmp/src/com/raytheon/uf/edex/plugin/ffmp/common/FFTI.java @@ -44,6 +44,7 @@ import com.raytheon.uf.common.monitor.xml.SourceXML; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.edex.plugin.ffmp.FFMPGenerator; /** @@ -54,8 +55,8 @@ import com.raytheon.uf.edex.plugin.ffmp.FFMPGenerator; * SOFTWARE HISTORY * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Apr 01, 2011 dhladky Initial creation - * July 13, 2012 dhladky Revamped to help memory + * Apr 01, 2011 dhladky Initial creation + * July 13, 2012 dhladky Revamped to help memory * * * @@ -443,7 +444,6 @@ public class FFTI implements Runnable { "Failed to evaluate Ratio/Diff. " + attribute.getAttributeName() + ": " + displayName + "\n" + e); - e.printStackTrace(); } } @@ -826,9 +826,9 @@ public class FFTI implements Runnable { } long cur = config.getDate().getTime(); - long timeBack = (long) (duration * 3600 * 1000); + long timeBack = (long) (duration * TimeUtil.MILLIS_PER_HOUR); Date backDate = new Date(cur - timeBack); - long expirationTime = ffmpSource.getExpirationMinutes(fftiSiteKey) * 60 * 1000; + long expirationTime = ffmpSource.getExpirationMinutes(fftiSiteKey) * TimeUtil.MILLIS_PER_MINUTE; FFMPDataContainer fdc = null; @@ -894,6 +894,15 @@ public class FFTI implements Runnable { return accumulator; } + /** + * Gets the ratio and difference values for this site + * @param qSourceKey + * @param qSiteKey + * @param ffgType + * @param duration + * @param unit + * @return + */ private FFTIRatioDiff getRatioAndDiffForSite(String qSourceKey, String qSiteKey, String ffgType, double duration, String unit) { @@ -923,13 +932,13 @@ public class FFTI implements Runnable { values.setUnit(unit); long cur = config.getDate().getTime(); - long timeBack = (long) (duration * 3600 * 1000); + long timeBack = (long) (duration * TimeUtil.MILLIS_PER_HOUR); Date backDate = new Date(cur - timeBack); - long expirationTime = ffmpQSource.getExpirationMinutes(qSiteKey) * 60 * 1000; + long expirationTime = ffmpQSource.getExpirationMinutes(qSiteKey) * TimeUtil.MILLIS_PER_MINUTE; // make sure we have data Date ffgBackDate = new Date(config.getDate().getTime() - - (3600 * 1000 * 24)); + - (TimeUtil.MILLIS_PER_HOUR * FFMPGenerator.FFG_SOURCE_CACHE_TIME)); String primarySource = ffmpgen.fscm.getPrimarySource(ffmpQSource); ProductXML product = ffmpgen.fscm.getProduct(primarySource); @@ -950,7 +959,7 @@ public class FFTI implements Runnable { if (guidSourceExpiration == 0l) { guidSourceExpiration = iguidSource - .getExpirationMinutes(qSiteKey) * 60 * 1000; + .getExpirationMinutes(qSiteKey) * TimeUtil.MILLIS_PER_MINUTE; break; } } @@ -1046,7 +1055,7 @@ public class FFTI implements Runnable { SourceXML ffmpQSource, double duration, String qSiteKey) { long cur = config.getDate().getTime(); - long timeBack = (long) (duration * 3600 * 1000); + long timeBack = (long) (duration * TimeUtil.MILLIS_PER_HOUR); Date backDate = new Date(cur - timeBack); long expirationTime = ffmpQSource.getExpirationMinutes(qSiteKey); Double gapVal = 0.0; @@ -1054,14 +1063,14 @@ public class FFTI implements Runnable { if (qpeContainer.getOrderedTimes(backDate) != null) { gapVal = 0.0; - ArrayList gaps = FFMPGap.getGaps( + List gaps = FFMPGap.getGaps( qpeContainer.getOrderedTimes(backDate), expirationTime, backDate, config.getDate()); for (FFMPGap gap : gaps) { gapVal += gap.getGap(); } - gapVal = gapVal / 60; + gapVal = gapVal / TimeUtil.MINUTES_PER_HOUR; } return gapVal; diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/META-INF/MANIFEST.MF index 32525a99e7..4b8090eb4f 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/META-INF/MANIFEST.MF @@ -11,7 +11,8 @@ Require-Bundle: com.raytheon.uf.edex.auth;bundle-version="1.12.2", com.raytheon.uf.common.status;bundle-version="1.12.1174", com.raytheon.uf.common.localization, com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174", - com.raytheon.uf.common.useradmin;bundle-version="1.0.0" + com.raytheon.uf.common.useradmin;bundle-version="1.0.0", + com.raytheon.uf.common.time;bundle-version="1.12.1174" Import-Package: com.raytheon.uf.common.localization, com.raytheon.uf.common.serialization, com.raytheon.uf.common.status, diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/src/com/raytheon/uf/edex/plugin/nwsauth/FileManager.java b/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/src/com/raytheon/uf/edex/plugin/nwsauth/FileManager.java index c308db748d..13d71d3320 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/src/com/raytheon/uf/edex/plugin/nwsauth/FileManager.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/src/com/raytheon/uf/edex/plugin/nwsauth/FileManager.java @@ -19,9 +19,11 @@ **/ package com.raytheon.uf.edex.plugin.nwsauth; -import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; import javax.xml.bind.JAXBException; @@ -40,6 +42,7 @@ import com.raytheon.uf.common.serialization.JAXBManager; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.util.TimeUtil; /** * Uses localization data to determine role/permissions. Intentionally @@ -51,7 +54,9 @@ import com.raytheon.uf.common.status.UFStatus.Priority; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Jan 09, 2013 1412 djohnson Moved file writing from viz plugin to server-side. + * Jan 09, 2013 1412 djohnson Moved file writing from viz plugin to server-side. + * Jan 17, 2013 1412 djohnson Check files for having been modified each time data is requested, + * in case they were written by another member of the cluster. * * * @@ -69,14 +74,22 @@ class FileManager { private final String ROLE_DIR = "roles"; - private final Map roleDataMap = new HashMap(); + private final AtomicLong lastReadTime = new AtomicLong(-1L); + + /** + * Application name -> Role Data. + */ + private final ConcurrentMap roleDataMap = new ConcurrentHashMap(); /** * Application name -> LocalizationFile map. */ - private final Map roleFileMap = new HashMap(); + private final ConcurrentMap roleFileMap = new ConcurrentHashMap(); - private FileManager() { + /** + * Package-level visibility so tests can create new instances. + */ + FileManager() { readXML(); } @@ -117,31 +130,54 @@ class FileManager { private void readXML() { try { - getJaxbManager(); - - IPathManager pm = PathManagerFactory.getPathManager(); - LocalizationContext[] contexts = new LocalizationContext[2]; - contexts[0] = pm.getContext(LocalizationType.COMMON_STATIC, - LocalizationLevel.BASE); - contexts[1] = pm.getContext(LocalizationType.COMMON_STATIC, - LocalizationLevel.SITE); - LocalizationFile[] roleFiles = pm.listFiles(contexts, ROLE_DIR, - new String[] { ".xml" }, false, true); - + LocalizationFile[] roleFiles = getUserRoleLocalizationFiles(); + boolean needToReadFiles = false; for (LocalizationFile lf : roleFiles) { - NwsRoleData roleData = lf.jaxbUnmarshal(NwsRoleData.class, - getJaxbManager()); + final long fileLastModified = lf.getFile().lastModified(); + final long lastTimeFilesWereRead = lastReadTime.get(); - if (roleData != null) { - this.roleDataMap.put(roleData.getApplication(), roleData); - this.roleFileMap.put(roleData.getApplication(), lf); + if (fileLastModified > lastTimeFilesWereRead) { + needToReadFiles = true; + break; } } + + if (needToReadFiles) { + for (LocalizationFile lf : roleFiles) { + final long fileLastModified = lf.getFile().lastModified(); + final long lastTimeFilesWereRead = lastReadTime.get(); + + if (fileLastModified < lastTimeFilesWereRead) { + continue; + } + NwsRoleData roleData = lf.jaxbUnmarshal(NwsRoleData.class, + getJaxbManager()); + + if (roleData != null) { + final String application = roleData.getApplication(); + this.roleDataMap.put(application, roleData); + this.roleFileMap.put(application, lf); + } + } + } + lastReadTime.set(TimeUtil.currentTimeMillis()); } catch (Exception e) { statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e); } } + private LocalizationFile[] getUserRoleLocalizationFiles() { + IPathManager pm = PathManagerFactory.getPathManager(); + LocalizationContext[] contexts = new LocalizationContext[2]; + contexts[0] = pm.getContext(LocalizationType.COMMON_STATIC, + LocalizationLevel.BASE); + contexts[1] = pm.getContext(LocalizationType.COMMON_STATIC, + LocalizationLevel.SITE); + LocalizationFile[] roleFiles = pm.listFiles(contexts, ROLE_DIR, + new String[] { ".xml" }, false, true); + return roleFiles; + } + private JAXBManager getJaxbManager() throws JAXBException { if (jaxbManager == null) { jaxbManager = new JAXBManager(NwsRoleData.class, @@ -154,13 +190,15 @@ class FileManager { * @return */ public Map getRoleDataMap() { + readXML(); return roleDataMap; } /** * @param roleDataWithChanges */ - public void writeApplicationRoleData(Map roleDataWithChanges) { + public void writeApplicationRoleData( + Map roleDataWithChanges) { for (Entry entry : roleDataWithChanges.entrySet()) { final String application = entry.getKey(); roleDataMap.put(application, entry.getValue()); diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/utility/common_static/base/roles/userRoles.xml b/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/utility/common_static/base/roles/userRoles.xml index 67ab28709d..61c231cbea 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/utility/common_static/base/roles/userRoles.xml +++ b/edexOsgi/com.raytheon.uf.edex.plugin.nwsauth/utility/common_static/base/roles/userRoles.xml @@ -89,6 +89,8 @@ + + com.raytheon.localization.site/common_static/purge com.raytheon.localization.site/cave_static/colormaps @@ -119,6 +121,7 @@ com.raytheon.localization.site/common_static/radar/rmr/rmrAvailableRequests.xml com.raytheon.localization.site/common_static/shef com.raytheon.localization.site/common_static/roles + com.raytheon.localization.site/common_static/datadelivery diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/scripts/RegistryIndices.sql b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/scripts/RegistryIndices.sql new file mode 100644 index 0000000000..cb1fa73597 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/res/scripts/RegistryIndices.sql @@ -0,0 +1,4 @@ +CREATE INDEX "intlstring_localizedStrings_idx" ON intlstring_localizedstrings USING btree (intlstring_key); +CREATE INDEX "versionInfo_idx" ON versioninfo USING btree (versionname,userversionname); +CREATE INDEX registryobject_slot_idx ON registryobject_slot USING btree (registryobject_id); +CREATE INDEX value_value_idx ON value_value USING btree (value_key); \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/DbInit.java b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/DbInit.java index 3385e3a615..609b624349 100644 --- a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/DbInit.java +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/src/com/raytheon/uf/edex/registry/ebxml/dao/DbInit.java @@ -20,7 +20,11 @@ package com.raytheon.uf.edex.registry.ebxml.dao; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.ResultSet; @@ -28,7 +32,10 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; +import java.util.Enumeration; import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; import oasis.names.tc.ebxml.regrep.wsdl.registry.services.v4.MsgRegistryException; import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.SubmitObjectsRequest; @@ -48,6 +55,7 @@ import com.raytheon.uf.common.serialization.SerializationUtil; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.util.ReflectionUtil; +import com.raytheon.uf.edex.core.props.PropertiesFactory; import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException; import com.raytheon.uf.edex.registry.ebxml.services.lifecycle.LifecycleManagerImpl; import com.raytheon.uf.edex.registry.ebxml.services.util.RegistrySessionManager; @@ -169,6 +177,15 @@ public class DbInit extends RegistryDao { e); } + statusHandler.info("Executing additional registry SQL..."); + try { + executeRegistrySql(); + } catch (EbxmlRegistryException e) { + throw new EbxmlRegistryException( + "An unexpected database error occurred while executing additional sql on the registry", + e); + } + try { populateDB(); } catch (SerializationException e) { @@ -398,6 +415,84 @@ public class DbInit extends RegistryDao { } + /** + * Executes any additional SQL statements contained in the res/scripts + * directory of this jar. The purpose of this method is primarily to add + * additional indices that cannot be automaically be generated by Hibernate + * + * @throws EbxmlRegistryException + */ + private void executeRegistrySql() throws EbxmlRegistryException { + JarFile jar = null; + + try { + jar = new JarFile(PropertiesFactory.getInstance() + .getEnvProperties().getEnvValue("PLUGINDIR") + + "com.raytheon.uf.edex.registry.ebxml.jar"); + } catch (IOException e) { + throw new EbxmlRegistryException("Unable to find registry jar!", e); + } + + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String name = entry.getName(); + if (name.startsWith("res/scripts") && name.endsWith(".sql")) { + BufferedReader reader = null; + InputStream stream = null; + + try { + stream = jar.getInputStream(entry); + reader = new BufferedReader(new InputStreamReader(stream)); + String line = null; + final StringBuilder buffer = new StringBuilder(); + while ((line = reader.readLine()) != null) { + buffer.append(line); + } + this.doInTransaction(new RegistryTransactionCallback() { + @Override + public Object execute(Session session) + throws EbxmlRegistryException { + session.doWork(new Work() { + @Override + public void execute(Connection connection) + throws SQLException { + Statement stmt = connection + .createStatement(); + stmt.execute(buffer.toString()); + connection.commit(); + } + }); + return null; + } + }); + } catch (Exception e) { + throw new EbxmlRegistryException( + "Unable to execute SQL Scripts for registry", e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + throw new EbxmlRegistryException( + "Unable to close file reader while reading registry SQL files", + e); + } + } + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + throw new EbxmlRegistryException( + "Unable to close file input stream while reading registry SQL files", + e); + } + } + } + } + } + } + /** * Method used to ensure that all objects added during the registry * initialization have an owner assigned to them. If no owner is assigned, diff --git a/edexOsgi/com.raytheon.uf.edex.registry.ebxml/utility/edex_static/base/stats/registryProcessStats.xml b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/utility/edex_static/base/stats/registryProcessStats.xml new file mode 100644 index 0000000000..7c3ed01ee8 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.edex.registry.ebxml/utility/edex_static/base/stats/registryProcessStats.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/AggregateManager.java b/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/AggregateManager.java index 44c27f32d7..40af314884 100644 --- a/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/AggregateManager.java +++ b/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/AggregateManager.java @@ -19,7 +19,9 @@ **/ package com.raytheon.uf.edex.stats; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; @@ -28,11 +30,17 @@ import java.util.List; import java.util.Map; import java.util.TimeZone; +import javax.xml.bind.JAXBException; + +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.raytheon.uf.common.event.Event; +import com.raytheon.uf.common.serialization.JAXBManager; import com.raytheon.uf.common.serialization.SerializationUtil; import com.raytheon.uf.common.stats.AggregateRecord; +import com.raytheon.uf.common.stats.StatsGrouping; +import com.raytheon.uf.common.stats.StatsGroupingColumn; import com.raytheon.uf.common.stats.StatsRecord; import com.raytheon.uf.common.stats.xml.StatisticsAggregate; import com.raytheon.uf.common.stats.xml.StatisticsEvent; @@ -61,6 +69,7 @@ import com.raytheon.uf.edex.stats.util.ConfigLoader; * Nov 07, 2012 1317 mpduff Updated Configuration Files. * Nov 28, 2012 1350 rjpeter Simplied aggregation and added aggregation with current db aggregate records. * Jan 07, 2013 1451 djohnson Use newGmtCalendar(). + * Jan 15, 2013 1487 djohnson Use xml for the grouping information on an {@link AggregateRecord}. * * * @author jsanchez @@ -70,6 +79,17 @@ public class AggregateManager { private static final IUFStatusHandler statusHandler = UFStatus .getHandler(AggregateManager.class); + private static final Object[] EMPTY_OBJ_ARR = new Object[0]; + + private static final JAXBManager JAXB_MANAGER; + static { + try { + JAXB_MANAGER = new JAXBManager(StatsGroupingColumn.class); + } catch (JAXBException e) { + throw new ExceptionInInitializerError(e); + } + } + /** In minutes */ private int bucketInterval; @@ -255,8 +275,6 @@ public class AggregateManager { Map> rval = new HashMap>(); TimeRange timeRange = null; Multimap eventsByGroup = null; - final Object[] EMPTY_OBJ_ARR = new Object[0]; - StringBuilder group = new StringBuilder(); for (StatsRecord record : records) { if ((timeRange == null) @@ -275,30 +293,11 @@ public class AggregateManager { Event event = SerializationUtil.transformFromThrift( Event.class, record.getEvent()); - // determine group - boolean addDelim = false; - Iterator gMethodIter = statEvent.getGroupByMethods() - .iterator(); - Iterator gFieldNameIter = statEvent - .getGroupList().iterator(); - group.setLength(0); - - while (gMethodIter.hasNext() && gFieldNameIter.hasNext()) { - Method m = gMethodIter.next(); - String field = gFieldNameIter.next().getName(); - String gVal = String - .valueOf(m.invoke(event, EMPTY_OBJ_ARR)); - - if (addDelim) { - group.append('-'); - } else { - addDelim = true; - } - - group.append(field).append(':').append(gVal); + String groupAsString = determineGroupRepresentationForEvent( + statEvent, event); + if (groupAsString != null) { + eventsByGroup.put(groupAsString, event); } - - eventsByGroup.put(group.toString(), event); } catch (Exception e) { statusHandler .error("Error processing event. Aggregation may be inaccurate. ", @@ -309,6 +308,30 @@ public class AggregateManager { return rval; } + @VisibleForTesting + static String determineGroupRepresentationForEvent( + StatisticsEvent statEvent, Event event) + throws IllegalAccessException, InvocationTargetException, + JAXBException { + Iterator gMethodIter = statEvent.getGroupByMethods().iterator(); + Iterator gFieldNameIter = statEvent.getGroupList() + .iterator(); + List groupings = new ArrayList(); + + while (gMethodIter.hasNext() && gFieldNameIter.hasNext()) { + Method m = gMethodIter.next(); + String field = gFieldNameIter.next().getName(); + String gVal = String.valueOf(m.invoke(event, EMPTY_OBJ_ARR)); + + groupings.add(new StatsGrouping(field, gVal)); + } + + StatsGroupingColumn column = new StatsGroupingColumn(); + column.setGroup(groupings); + + return JAXB_MANAGER.marshalToXml(column); + } + /** * Tests if the bucket interval is a valid value. If value is invalid then * value will be set to default value. diff --git a/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/data/StatsDataAccumulator.java b/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/data/StatsDataAccumulator.java index c21c31ff5e..d207d2d13d 100644 --- a/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/data/StatsDataAccumulator.java +++ b/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/data/StatsDataAccumulator.java @@ -20,58 +20,72 @@ package com.raytheon.uf.edex.stats.data; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; -import java.util.TreeSet; -import java.util.regex.Pattern; + +import javax.xml.bind.JAXBException; import com.google.common.annotations.VisibleForTesting; -import com.raytheon.uf.common.serialization.SerializationException; -import com.raytheon.uf.common.serialization.SerializationUtil; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.raytheon.uf.common.serialization.JAXBManager; import com.raytheon.uf.common.stats.AggregateRecord; +import com.raytheon.uf.common.stats.StatsGrouping; +import com.raytheon.uf.common.stats.StatsGroupingColumn; import com.raytheon.uf.common.stats.data.GraphData; import com.raytheon.uf.common.stats.data.StatsBin; import com.raytheon.uf.common.stats.data.StatsData; import com.raytheon.uf.common.stats.data.StatsLabelData; -import com.raytheon.uf.common.stats.util.UnitUtils; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.TimeRange; import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.common.util.CollectionUtil; /** * Accumulates the statistics data. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Nov 15, 2012    728     mpduff      Initial creation
- *
+ * Jan 15, 2013 1487       djohnson    Use xml for the grouping information on an {@link AggregateRecord}.
+ * Jan 17, 2013   1357     mpduff      Remove unit conversions, add time step, other cleanup.
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ public class StatsDataAccumulator { - private static final Pattern COLON_PATTERN = Pattern.compile(":"); - - private static final Pattern DASH_PATTERN = Pattern.compile("-"); - - private static final String COLON = ":"; private static final IUFStatusHandler statusHandler = UFStatus .getHandler(StatsDataAccumulator.class); + /** + * Constant. + */ + private static final String COLON = ":"; + + /** JaxB manager instance. */ + private static final JAXBManager JAXB_MANAGER; + static { + try { + JAXB_MANAGER = new JAXBManager(StatsGroupingColumn.class); + } catch (JAXBException e) { + throw new ExceptionInInitializerError(e); + } + } + /** List of records */ private AggregateRecord[] records; @@ -108,7 +122,7 @@ public class StatsDataAccumulator { /** * Set the AggregateRecord[] - * + * * @param records * array of AggregateRecord objects */ @@ -122,28 +136,27 @@ public class StatsDataAccumulator { @VisibleForTesting public void setupGroupings() { for (AggregateRecord aggRec : records) { - String grouping = aggRec.getGrouping(); - String[] groupString = DASH_PATTERN.split(grouping); - String group; - String member; - for (String grp : groupString) { - String[] parts = COLON_PATTERN.split(grp); - group = parts[0]; - member = parts[1]; - if (!groupMemberMap.containsKey(group)) { - groupMemberMap.put(group, new TreeSet()); - } + StatsGroupingColumn columnValue = unmarshalGroupingColumnFromRecord(aggRec); - groupMemberMap.get(group).add(member); + final List groups = columnValue.getGroup(); + if (CollectionUtil.isNullOrEmpty(groups)) { + continue; + } + for (StatsGrouping group : groups) { + final String groupName = group.getName(); + if (!groupMemberMap.containsKey(groupName)) { + groupMemberMap.put(groupName, Sets. newTreeSet()); + } + groupMemberMap.get(groupName).add(group.getValue()); } } - groups = new ArrayList(groupMemberMap.keySet()); + groups = Lists.newArrayList(groupMemberMap.keySet()); } /** * Get the GraphData object - * + * * @param groups * List of groups * @return The GraphData object @@ -154,8 +167,6 @@ public class StatsDataAccumulator { // Loop backwards over the data StatsLabelData prevLabelData = null; StatsLabelData statsLabelData = null; - UnitUtils unitUtils = new UnitUtils(eventType, dataType); - unitUtils.setDisplayUnit(displayUnit); for (int i = groups.size() - 1; i >= 0; i--) { String group = groups.get(i); @@ -167,7 +178,7 @@ public class StatsDataAccumulator { prevLabelData = statsLabelData; } - gather(unitUtils, groups); + gather(groups); // StatsLabelData is created and holds all the keys GraphData graphData = new GraphData(); @@ -176,22 +187,24 @@ public class StatsDataAccumulator { graphData.setStatsDataMap(statsDataMap); graphData.setTimeRange(timeRange); graphData.setKeys(new ArrayList(this.statsDataMap.keySet())); - graphData.setUnitUtils(unitUtils); graphData.setKeySequence(groups); + graphData.setTimeStep(this.timeStep); + graphData.setEventType(eventType); + graphData.setDataType(dataType); return graphData; } /** * Create the StatsDataMap keys - * + * * @param unitUtils * UnitUtils object * @param groups * List of groups */ @VisibleForTesting - void createStatsDataMap(UnitUtils unitUtils, List groups) { + void createStatsDataMap(List groups) { Map keySequenceMap = new LinkedHashMap(); for (String key : groups) { keySequenceMap.put(key, ""); @@ -202,21 +215,25 @@ public class StatsDataAccumulator { if (record.getEventType().equals(eventType) && record.getField().equals(dataType)) { + StatsGroupingColumn columnValue = unmarshalGroupingColumnFromRecord(record); + + final List columnValueGroups = columnValue + .getGroup(); + if (CollectionUtil.isNullOrEmpty(columnValueGroups)) { + continue; + } + // Have a matching record for (String key : keySequenceMap.keySet()) { keySequenceMap.put(key, ""); } - String[] groupings = DASH_PATTERN.split(record.getGrouping()); - for (String grouping : groupings) { - String[] parts = COLON_PATTERN.split(grouping); - String group = parts[0]; - String groupMember = parts[1]; + for (StatsGrouping group : columnValueGroups) { for (String key : keySequenceMap.keySet()) { - if (group.equals(key)) { + if (group.getName().equals(key)) { keySequenceMap.put(key, keySequenceMap.get(key) - .concat(groupMember + COLON)); + .concat(group.getValue() + COLON)); break; } } @@ -233,7 +250,7 @@ public class StatsDataAccumulator { if (!statsDataMap.containsKey(builtKey)) { statsDataMap.put(builtKey, new StatsData(builtKey, - timeStep, this.timeRange, unitUtils)); + timeStep, this.timeRange)); } statsDataMap.get(builtKey).addRecord(record); @@ -242,29 +259,48 @@ public class StatsDataAccumulator { } } + /** + * Unmarshals the {@link StatsGroupingColumn} from the + * {@link AggregateRecord}. + * + * @param record + * the aggregate record + * @return the unmarshalled column, or an empty column if unable to + * unmarshal + */ + private static StatsGroupingColumn unmarshalGroupingColumnFromRecord( + AggregateRecord record) { + String groupingXmlAsString = record.getGrouping(); + try { + return (StatsGroupingColumn) JAXB_MANAGER + .unmarshalFromXml(groupingXmlAsString); + } catch (JAXBException e) { + statusHandler.handle(Priority.PROBLEM, + "Unable to unmarshal stats grouping column, returning empty record, xml:\n" + + groupingXmlAsString, e); + return new StatsGroupingColumn(); + } + } + /** * Gather the data together in each bin. - * + * * @param unitUtils * UnitUtils object * @param groups * List of groups */ - @SuppressWarnings("unchecked") - private void gather(UnitUtils unitUtils, List groups) { - createStatsDataMap(unitUtils, groups); + private void gather(List groups) { + createStatsDataMap(groups); calculateBins(); + Map newMap = new TreeMap(); for (String key : statsDataMap.keySet()) { - Map newMap = Collections.emptyMap(); - try { - newMap = SerializationUtil.transformFromThrift(Map.class, - SerializationUtil.transformToThrift(bins)); - } catch (SerializationException e) { - statusHandler - .handle(Priority.PROBLEM, - "Error serializing/deserializing StatsBin data. Skipping...", - e); + // Copy the bins object + for (long lkey : bins.keySet()) { + StatsBin sb = new StatsBin(bins.get(lkey)); + newMap.put(lkey, sb); } + StatsData data = statsDataMap.get(key); data.setBins(newMap); data.accumulate(); @@ -323,7 +359,7 @@ public class StatsDataAccumulator { /** * Set the display units. - * + * * @param displayUnit * the displayUnit to set */ @@ -333,7 +369,7 @@ public class StatsDataAccumulator { /** * TimeStep in minutes - * + * * @param timeStep */ public void setTimeStep(int timeStep) { diff --git a/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/util/Archiver.java b/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/util/Archiver.java index 9150f940a2..59dd45cd2e 100644 --- a/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/util/Archiver.java +++ b/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/util/Archiver.java @@ -54,6 +54,7 @@ import com.raytheon.uf.common.time.TimeRange; * ------------ ---------- ----------- -------------------------- * Aug 21, 2012 jsanchez Initial creation. * Nov 09, 2012 dhladky Changed to CSV output + * Jan 24, 2013 1357 mpduff Fix comma output and paths. * * * @@ -91,6 +92,8 @@ public class Archiver { private static final String COMMA = ","; + private static final Pattern NLPattern = Pattern.compile("[\\n\\r]+"); + private static final IUFStatusHandler statusHandler = UFStatus .getHandler(Archiver.class); @@ -116,15 +119,13 @@ public class Archiver { * @param items * @return */ - private String createFilename(TimeRange tr, String eventType, String group) { + private String createFilename(TimeRange tr, String eventType) { SimpleDateFormat fileDateFormatter = new SimpleDateFormat( FILE_DATE_FORMAT); StringBuilder sb = new StringBuilder("stats/aggregates"); String[] chunks = PERIOD_PATTERN.split(eventType); sb.append("/"); - sb.append(group); - sb.append("/"); sb.append(chunks[chunks.length - 1]); sb.append("."); sb.append(fileDateFormatter.format(tr.getStart())); @@ -156,24 +157,29 @@ public class Archiver { double count = agrec.getCount(); if (eventType != null) { - sb.append(eventType).append(COMMA); + sb.append(eventType); } + sb.append(COMMA); if (startDate != null) { - sb.append(dateFormat.format(startDate.getTime())) - .append(COMMA); + sb.append(dateFormat.format(startDate.getTime())); } + sb.append(COMMA); if (endDate != null) { - sb.append(dateFormat.format(endDate.getTime())).append( - COMMA); + sb.append(dateFormat.format(endDate.getTime())); } + sb.append(COMMA); + if (grouping != null) { - sb.append(grouping).append(COMMA); + sb.append(NLPattern.matcher(grouping).replaceAll("")); } + sb.append(COMMA); + if (field != null) { - sb.append(field).append(COMMA); + sb.append(field); } + sb.append(COMMA); sb.append(max).append(COMMA); sb.append(min).append(COMMA); @@ -212,10 +218,9 @@ public class Archiver { for (StatisticsKey key : statisticsMap.keySet()) { String eventType = key.eventType; - String grouping = key.grouping; List records = statisticsMap.get(key); - String filename = createFilename(key.timeRange, eventType, grouping); + String filename = createFilename(key.timeRange, eventType); try { writeToFile(filename, records); } catch (JAXBException e) { @@ -243,8 +248,7 @@ public class Archiver { siteLocalization.getFile().getParentFile().mkdirs(); // Write this to output CSV try { - bw = new BufferedWriter(new FileWriter( - outputFilePath)); + bw = new BufferedWriter(new FileWriter(outputFilePath)); if (bw != null) { for (AggregateRecord agrec : records) { bw.write(getCSVOutput(agrec, dateFormatter)); diff --git a/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/util/ConfigLoader.java b/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/util/ConfigLoader.java index e4e6e01d29..239ebfc79d 100644 --- a/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/util/ConfigLoader.java +++ b/edexOsgi/com.raytheon.uf.edex.stats/src/com/raytheon/uf/edex/stats/util/ConfigLoader.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.google.common.annotations.VisibleForTesting; import com.raytheon.uf.common.event.Event; import com.raytheon.uf.common.localization.IPathManager; import com.raytheon.uf.common.localization.LocalizationContext; @@ -57,6 +58,7 @@ import com.raytheon.uf.common.util.ReflectionUtil; * Aug 21, 2012 jsanchez Updated error handling and validated config files. * Nov 07, 2012 1317 mpduff Update config files. * Nov 29, 2012 1350 rjpeter Updated to static, fixed localization, increased validation. + * Jan 15, 2013 1487 djohnson Make validate() static and public, so it can be run independently. * * * @author jsanchez @@ -158,7 +160,8 @@ public class ConfigLoader { * * @param config */ - private void validate(Map eventMap, + @VisibleForTesting + public static void validate(Map eventMap, StatisticsConfig config) { for (Iterator iter = config.getEvents().iterator(); iter .hasNext();) { diff --git a/edexOsgi/com.raytheon.uf.edex.stats/utility/edex_static/base/stats/edexProcessStats.xml b/edexOsgi/com.raytheon.uf.edex.stats/utility/edex_static/base/stats/edexProcessStats.xml index ed85b9c2e7..90c2d74058 100644 --- a/edexOsgi/com.raytheon.uf.edex.stats/utility/edex_static/base/stats/edexProcessStats.xml +++ b/edexOsgi/com.raytheon.uf.edex.stats/utility/edex_static/base/stats/edexProcessStats.xml @@ -3,6 +3,8 @@ + $TEMPNAME mv $TEMPNAME $LOGFILE -fi +fi # echo "------------------------------ " >> $LOGFILE @@ -42,18 +42,10 @@ echo "------------------------------ " >> $LOGFILE Dte=`date -u ` echo Starting alarm_whfs at $Dte >> $LOGFILE -Dte=`date -u` -echo Invoking roc_checker at $Dte >> $LOGFILE - $WHFS_LOCAL_BIN_DIR/run_roc_checker -# TODO re-enabled report_alarm if needed +$WHFS_LOCAL_BIN_DIR/run_report_alarm -#Dte=`date -u` -#echo Invoking report_alarm at $Dte >> $LOGFILE - -#$WHFS_LOCAL_BIN_DIR/run_report_alarm - -#Dte=`date -u ` -#echo Completed alarm_whfs at $Dte >> $LOGFILE +Dte=`date -u ` +echo Completed alarm_whfs at $Dte >> $LOGFILE diff --git a/pythonPackages/dynamicserialize/dstypes/com/raytheon/uf/common/dataplugin/gfe/db/objects/ParmID.py b/pythonPackages/dynamicserialize/dstypes/com/raytheon/uf/common/dataplugin/gfe/db/objects/ParmID.py index 68d276abfa..2ac291d476 100644 --- a/pythonPackages/dynamicserialize/dstypes/com/raytheon/uf/common/dataplugin/gfe/db/objects/ParmID.py +++ b/pythonPackages/dynamicserialize/dstypes/com/raytheon/uf/common/dataplugin/gfe/db/objects/ParmID.py @@ -48,50 +48,30 @@ class ParmID(object): else: self.parmLevel = level - self.compositeName = self.parmName + "_" + self.parmLevel self.__encodeIdentifier() elif parmIdentifier is not None: self.__decodeIdentifier(parmIdentifier) - self.compositeName = self.parmName + "_" + self.parmLevel self.__encodeIdentifier() def getParmName(self): return self.parmName - def setParmName(self, parmName): - self.parmName = parmName - def getParmLevel(self): return self.parmLevel - def setParmLevel(self, parmLevel): - self.parmLevel = parmLevel - def getDbId(self): return self.dbId - def setDbId(self, dbId): - self.dbId = dbId - def getCompositeName(self): return self.compositeName - def setCompositeName(self, compositeName): - self.compositeName = compositeName - def getShortParmId(self): return self.shortParmId - def setShortParmId(self, shortParmId): - self.shortParmId = shortParmId - def getParmId(self): return self.parmId - def setParmId(self, parmId): - self.parmId = parmId - def __decodeIdentifier(self, parmIdentifier): parts = parmIdentifier.split(":") nameLevel = parts[0].split("_") @@ -104,9 +84,9 @@ class ParmID(object): self.parmLevel = self.defaultLevel() def __encodeIdentifier(self): + self.compositeName = self.parmName + "_" + self.parmLevel self.shortParmId = self.compositeName + ":" + self.dbId.getShortModelId() - if self.parmId is None or len(self.parmId) == 0: - self.parmId = self.compositeName + ":" + self.dbId.getModelId() + self.parmId = self.compositeName + ":" + self.dbId.getModelId() def isValid(self): if len(self.parmName) is None or len(self.parmLevel) is None or self.dbId is None: diff --git a/tests/.classpath b/tests/.classpath index 65be975a6f..a139e358aa 100644 --- a/tests/.classpath +++ b/tests/.classpath @@ -67,5 +67,9 @@ + + + + diff --git a/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/AbstractBandwidthManagerIntTest.java b/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/AbstractBandwidthManagerIntTest.java index 48b88f5ca7..32b1c29f6a 100644 --- a/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/AbstractBandwidthManagerIntTest.java +++ b/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/AbstractBandwidthManagerIntTest.java @@ -151,7 +151,15 @@ public abstract class AbstractBandwidthManagerIntTest { */ protected Subscription createSubscriptionThatFillsUpABucket() { return createSubscriptionWithDataSetSizeInBytes(fullBucketSize); + } + /** + * Create a subscription the fills up ten buckets. + * + * @return the subscription + */ + protected Subscription createSubscriptionThatFillsUpTenBuckets() { + return createSubscriptionWithDataSetSizeInBytes(fullBucketSize * 10); } /** diff --git a/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthManagerIntTest.java b/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthManagerIntTest.java index e1d4e17338..2e43aef07b 100644 --- a/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthManagerIntTest.java +++ b/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthManagerIntTest.java @@ -19,8 +19,11 @@ **/ package com.raytheon.uf.edex.datadelivery.bandwidth; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.text.ParseException; @@ -47,6 +50,7 @@ import com.raytheon.uf.common.datadelivery.registry.OpenDapGriddedDataSetMetaDat import com.raytheon.uf.common.datadelivery.registry.OpenDapGriddedDataSetMetaDataFixture; import com.raytheon.uf.common.datadelivery.registry.ParameterFixture; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.uf.common.datadelivery.registry.SubscriptionFixture; import com.raytheon.uf.common.datadelivery.registry.Time; import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; @@ -81,6 +85,9 @@ import com.raytheon.uf.edex.datadelivery.retrieval.RetrievalManagerNotifyEvent; * Oct 12, 2012 0726 djohnson Initial creation * Oct 23, 2012 1286 djohnson Create reusable abstract int test. * Dec 11, 2012 1286 djohnson Add test verifying fulfilled retrievals won't cause NPEs when the subscription is updated. + * Jan 25, 2013 1528 djohnson Compare priorities as primitive ints. + * Jan 28, 2013 1530 djohnson Test that all allocations are unscheduled for subscription that doesn't fully schedule. + * Jan 30, 2013 1501 djohnson Fix broken calculations for determining required latency. * * * @@ -313,7 +320,7 @@ public class BandwidthManagerIntTest extends AbstractBandwidthManagerIntTest { Subscription subscription2 = createSubscriptionThatFillsUpABucket(); // subscription2 will have higher priority - subscription2.setPriority(subscription.getPriority() + 1); + subscription2.setPriority(SubscriptionPriority.HIGH); // they conflict for cycle hour 8 subscription.getTime().setCycleTimes( @@ -335,16 +342,45 @@ public class BandwidthManagerIntTest extends AbstractBandwidthManagerIntTest { BandwidthAllocation unscheduledAllocation = iter.next(); assertEquals( "The first subscription with lower priority should have been the one unscheduled.", - subscription.getPriority().intValue(), + subscription.getPriority().getPriorityValue(), unscheduledAllocation.getPriority(), 0.0); unscheduledAllocation = iter.next(); assertEquals( "The first subscription with lower priority should have been the one unscheduled.", - subscription.getPriority().intValue(), + subscription.getPriority().getPriorityValue(), unscheduledAllocation.getPriority(), 0.0); } + @Test + public void unscheduledSubscriptionUnschedulesAllAllocations() { + String unscheduledSubDataSetName = "willBeUnscheduled"; + Subscription subscription = createSubscriptionThatFillsUpABucket(); + subscription.setDataSetName(unscheduledSubDataSetName); + Subscription subscription2 = createSubscriptionThatFillsUpABucket(); + + // subscription2 will have higher priority + subscription2.setPriority(SubscriptionPriority.HIGH); + + // they conflict for cycle hour 8 + subscription.getTime().setCycleTimes( + Arrays.asList(Integer.valueOf(6), Integer.valueOf(8))); + subscription2.getTime().setCycleTimes( + Arrays.asList(Integer.valueOf(3), Integer.valueOf(8))); + + bandwidthManager.schedule(subscription); + bandwidthManager.schedule(subscription2); + + final List subscriptionRetrievals = bandwidthDao + .getSubscriptionRetrievals(subscription.getProvider(), + unscheduledSubDataSetName); + + for (SubscriptionRetrieval subscriptionRetrieval : subscriptionRetrievals) { + assertThat(subscriptionRetrieval.getStatus(), + is(equalTo(RetrievalStatus.UNSCHEDULED))); + } + } + @Test public void testScheduleSubscriptionWithHigherPrioritySetsOtherAllocationsToUnscheduled() { @@ -352,7 +388,7 @@ public class BandwidthManagerIntTest extends AbstractBandwidthManagerIntTest { Subscription subscription2 = createSubscriptionThatFillsUpABucket(); // subscription2 will have higher priority - subscription2.setPriority(subscription.getPriority() + 1); + subscription2.setPriority(SubscriptionPriority.HIGH); // they conflict for cycle hour 8 subscription.getTime().setCycleTimes( @@ -389,7 +425,7 @@ public class BandwidthManagerIntTest extends AbstractBandwidthManagerIntTest { Subscription subscription2 = createSubscriptionThatFillsUpABucket(); // subscription2 will have higher priority - subscription2.setPriority(subscription.getPriority() + 1); + subscription2.setPriority(SubscriptionPriority.HIGH); // they conflict for cycle hour 8 subscription.getTime().setCycleTimes( @@ -419,8 +455,6 @@ public class BandwidthManagerIntTest extends AbstractBandwidthManagerIntTest { // Subscription starts out too big Subscription subscription = createSubscriptionThatFillsUpTwoBuckets(); - - // they conflict for cycle hour 8 subscription.getTime().setCycleTimes(Arrays.asList(Integer.valueOf(6))); List unscheduled = bandwidthManager @@ -432,6 +466,7 @@ public class BandwidthManagerIntTest extends AbstractBandwidthManagerIntTest { // Hey look, this subscription will fit now! subscription.setDataSetSize(subscription.getDataSetSize() / 2); + subscription.setUnscheduled(false); unscheduled = bandwidthManager.subscriptionUpdated(subscription); @@ -456,15 +491,14 @@ public class BandwidthManagerIntTest extends AbstractBandwidthManagerIntTest { public void testDetermineRequiredLatencyReturnsNecessaryLatency() throws SerializationException { - // Subscription starts out too big - Subscription subscription = createSubscriptionThatFillsUpTwoBuckets(); + Subscription subscription = createSubscriptionThatFillsUpTenBuckets(); subscription.getTime().setCycleTimes(Arrays.asList(Integer.valueOf(0))); subscription.setLatencyInMinutes(0); int requiredLatency = bandwidthManager .determineRequiredLatency(subscription); - assertEquals("The required latency was calculated incorrectly", 6, + assertEquals("The required latency was calculated incorrectly", 30, requiredLatency); } @@ -712,7 +746,7 @@ public class BandwidthManagerIntTest extends AbstractBandwidthManagerIntTest { final List bandwidthAllocations = bandwidthDao .getBandwidthAllocations(subscription.getRoute()); - assertEquals("Incorrect number of allocations found.", 4, + assertEquals("Incorrect number of allocations found.", 0, bandwidthAllocations.size()); sendDeletedSubscriptionEvent(subscription); @@ -745,7 +779,7 @@ public class BandwidthManagerIntTest extends AbstractBandwidthManagerIntTest { final List subscriptionDaos = bandwidthDao .getSubscriptionDao(subscription); - assertEquals("Incorrect number of subscription daos found.", 4, + assertEquals("Incorrect number of subscription daos found.", 0, subscriptionDaos.size()); sendDeletedSubscriptionEvent(subscription); diff --git a/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthServiceIntTest.java b/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthServiceIntTest.java index 31cab0bd6b..3af60822f1 100644 --- a/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthServiceIntTest.java +++ b/tests/integration/com/raytheon/uf/edex/datadelivery/bandwidth/BandwidthServiceIntTest.java @@ -47,6 +47,7 @@ import com.raytheon.uf.common.datadelivery.registry.AdhocSubscription; import com.raytheon.uf.common.datadelivery.registry.AdhocSubscriptionFixture; import com.raytheon.uf.common.datadelivery.registry.Network; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.uf.common.serialization.SerializationUtil; import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.edex.datadelivery.bandwidth.dao.BandwidthAllocation; @@ -425,7 +426,7 @@ public class BandwidthServiceIntTest extends AbstractBandwidthManagerIntTest { Subscription subscription = createSubscriptionThatFillsUpTwoBuckets(); subscription.setLatencyInMinutes(6); - subscription.setPriority(2); + subscription.setPriority(SubscriptionPriority.HIGH); // Reserves a full bucket at 19700103 18:03:00 which fragments the // subscription to 19700103 18:00:00 and 18:06:00 @@ -538,9 +539,9 @@ public class BandwidthServiceIntTest extends AbstractBandwidthManagerIntTest { // Two subscriptions that will fill up a bucket exactly Subscription subscription = createSubscriptionThatFillsUpABucket(); - subscription.setPriority(2); + subscription.setPriority(SubscriptionPriority.NORMAL); Subscription subscription2 = createSubscriptionThatFillsUpABucket(); - subscription.setPriority(4); + subscription.setPriority(SubscriptionPriority.HIGH); // subscription2 will not be able to schedule for cycle hour 8 subscription.getTime().setCycleTimes( @@ -552,7 +553,8 @@ public class BandwidthServiceIntTest extends AbstractBandwidthManagerIntTest { service.schedule(subscription2); BandwidthGraphData graphData = service.getBandwidthGraphData(); - final Map priorityMap = graphData.getPriorityMap(); + final Map priorityMap = graphData + .getPriorityMap(); assertThat(priorityMap.get(subscription.getName()), is(equalTo(subscription.getPriority()))); diff --git a/tests/resources/META-INF/services/com.raytheon.uf.common.datadelivery.retrieval.util.LevelXmlWriter b/tests/resources/META-INF/services/com.raytheon.uf.common.datadelivery.retrieval.util.LevelXmlWriter deleted file mode 100644 index eec9b4aec4..0000000000 --- a/tests/resources/META-INF/services/com.raytheon.uf.common.datadelivery.retrieval.util.LevelXmlWriter +++ /dev/null @@ -1 +0,0 @@ -com.raytheon.uf.common.datadelivery.retrieval.util.NullXmlWriter \ No newline at end of file diff --git a/tests/resources/META-INF/services/com.raytheon.uf.common.datadelivery.retrieval.util.ParameterXmlWriter b/tests/resources/META-INF/services/com.raytheon.uf.common.datadelivery.retrieval.util.ParameterXmlWriter deleted file mode 100644 index eec9b4aec4..0000000000 --- a/tests/resources/META-INF/services/com.raytheon.uf.common.datadelivery.retrieval.util.ParameterXmlWriter +++ /dev/null @@ -1 +0,0 @@ -com.raytheon.uf.common.datadelivery.retrieval.util.NullXmlWriter \ No newline at end of file diff --git a/tests/unit/com/raytheon/uf/common/datadelivery/registry/BaseSubscriptionFixture.java b/tests/unit/com/raytheon/uf/common/datadelivery/registry/BaseSubscriptionFixture.java index 93696f46c1..465a39abb1 100644 --- a/tests/unit/com/raytheon/uf/common/datadelivery/registry/BaseSubscriptionFixture.java +++ b/tests/unit/com/raytheon/uf/common/datadelivery/registry/BaseSubscriptionFixture.java @@ -23,6 +23,7 @@ import java.util.Date; import java.util.Random; import com.google.common.collect.Lists; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.uf.common.registry.ebxml.RegistryUtil; import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.common.util.AbstractFixture; @@ -79,7 +80,7 @@ public abstract class BaseSubscriptionFixture extends subscription.setParameter(Lists. newArrayList()); // Same priority for all, individual tests needing to test specific // priorities should set it manually anyway - subscription.setPriority(1); + subscription.setPriority(SubscriptionPriority.NORMAL); subscription.setProvider(ProviderFixture.INSTANCE.get(seedValue) .getName()); subscription.setSubscriptionStart(subscription.getActivePeriodStart()); diff --git a/tests/unit/com/raytheon/uf/common/datadelivery/registry/OpenDapGriddedDataSetFixture.java b/tests/unit/com/raytheon/uf/common/datadelivery/registry/OpenDapGriddedDataSetFixture.java index 12c01faea7..1e522d47ca 100644 --- a/tests/unit/com/raytheon/uf/common/datadelivery/registry/OpenDapGriddedDataSetFixture.java +++ b/tests/unit/com/raytheon/uf/common/datadelivery/registry/OpenDapGriddedDataSetFixture.java @@ -76,6 +76,7 @@ public class OpenDapGriddedDataSetFixture extends obj.setDataSetName("dataSetName" + seedValue); obj.setDataSetType(DataType.GRID); obj.setForecastHours(CollectionUtil.asSet(0)); + obj.setTime(TimeFixture.INSTANCE.get(seedValue)); // TODO: ParameterFixture obj.setParameters(Collections. emptyMap()); obj.setProviderName(ProviderFixture.INSTANCE.get(seedValue).getName()); diff --git a/tests/unit/com/raytheon/uf/common/datadelivery/registry/ParameterFixture.java b/tests/unit/com/raytheon/uf/common/datadelivery/registry/ParameterFixture.java index 1b1c4a8749..c9b5767533 100644 --- a/tests/unit/com/raytheon/uf/common/datadelivery/registry/ParameterFixture.java +++ b/tests/unit/com/raytheon/uf/common/datadelivery/registry/ParameterFixture.java @@ -59,7 +59,6 @@ public class ParameterFixture extends AbstractFixture { obj.setBaseType("baseType" + seedValue); obj.setDataType(DataType.GRID); obj.setDefinition("definition" + seedValue); - obj.setEnsemble(0); obj.setFillValue("fillValue" + seedValue); obj.setLevels(LevelsFixture.INSTANCE.get(seedValue)); obj.setLevelType(Arrays.asList(DataLevelTypeFixture.INSTANCE diff --git a/tests/unit/com/raytheon/uf/common/datadelivery/registry/ProviderTest.java b/tests/unit/com/raytheon/uf/common/datadelivery/registry/ProviderTest.java index 87b0c27f28..4efdc39352 100644 --- a/tests/unit/com/raytheon/uf/common/datadelivery/registry/ProviderTest.java +++ b/tests/unit/com/raytheon/uf/common/datadelivery/registry/ProviderTest.java @@ -31,6 +31,8 @@ import javax.xml.bind.JAXBException; import org.junit.Test; +import com.raytheon.uf.common.time.domain.Durations; +import com.raytheon.uf.common.time.domain.api.IDuration; import com.raytheon.uf.edex.datadelivery.harvester.config.HarvesterConfig; import com.raytheon.uf.edex.datadelivery.harvester.config.HarvesterConfigFixture; @@ -53,30 +55,13 @@ import com.raytheon.uf.edex.datadelivery.harvester.config.HarvesterConfigFixture public class ProviderTest { - @Test - public void testSetPostedFileDelayAllowsSpacesSurrounding() { - Provider provider = new Provider(); - provider.setPostedFileDelay(" 2 MICROSECONDS "); - - assertEquals(2, provider.getPostedFileDelayValue()); - assertEquals(TimeUnit.MICROSECONDS, provider.getPostedFileDelayUnits()); - } - - @Test - public void testSetPostedFileDelayCanParseText() { - Provider provider = new Provider(); - provider.setPostedFileDelay("5 HOURS"); - - assertEquals(5, provider.getPostedFileDelayValue()); - assertEquals(TimeUnit.HOURS, provider.getPostedFileDelayUnits()); - } - @Test public void testSetPostedFileDelayIsCalledOnJaxbUnmarshall() throws JAXBException { HarvesterConfig config = HarvesterConfigFixture.INSTANCE.get(); Provider provider = config.getProvider(); - provider.setPostedFileDelay("3 DAYS"); + final IDuration originalDuration = Durations.of(3, TimeUnit.DAYS); + provider.setPostedFileDelay(originalDuration); Writer writer = new StringWriter(); JAXBContext ctx = JAXBContext.newInstance(HarvesterConfig.class); @@ -85,19 +70,6 @@ public class ProviderTest { HarvesterConfig restored = (HarvesterConfig) ctx.createUnmarshaller() .unmarshal(new StringReader(writer.toString())); Provider restoredProvider = restored.getProvider(); - assertEquals(3, restoredProvider.getPostedFileDelayValue()); - assertEquals(TimeUnit.DAYS, restoredProvider.getPostedFileDelayUnits()); - } - - @Test(expected = IllegalArgumentException.class) - public void testSetPostedFileDelayThrowsExceptionOnInvalidUnits() { - Provider provider = new Provider(); - provider.setPostedFileDelay("5 HOUR"); - } - - @Test(expected = IllegalArgumentException.class) - public void testSetPostedFileDelayThrowsExceptionOnValueLessThanZero() { - Provider provider = new Provider(); - provider.setPostedFileDelay("-1 DAYS"); + assertEquals(originalDuration, restoredProvider.getPostedFileDelay()); } } diff --git a/tests/unit/com/raytheon/uf/common/datadelivery/registry/SubscriptionBuilder.java b/tests/unit/com/raytheon/uf/common/datadelivery/registry/SubscriptionBuilder.java index b43b0cf01c..181e54dae9 100644 --- a/tests/unit/com/raytheon/uf/common/datadelivery/registry/SubscriptionBuilder.java +++ b/tests/unit/com/raytheon/uf/common/datadelivery/registry/SubscriptionBuilder.java @@ -21,6 +21,7 @@ package com.raytheon.uf.common.datadelivery.registry; import java.util.Date; +import com.raytheon.uf.common.datadelivery.registry.Subscription.SubscriptionPriority; import com.raytheon.uf.common.registry.ebxml.RegistryUtil; import com.raytheon.uf.common.time.util.TimeUtil; @@ -73,7 +74,7 @@ public class SubscriptionBuilder { private String owner = "your_user"; - private int priority = 1; + private SubscriptionPriority priority = SubscriptionPriority.NORMAL; private Date subscriptionStart = TimeUtil.newDate(); @@ -256,7 +257,7 @@ public class SubscriptionBuilder { * @param priority * the priority to set */ - public SubscriptionBuilder withPriority(int priority) { + public SubscriptionBuilder withPriority(SubscriptionPriority priority) { this.priority = priority; return this; } diff --git a/tests/unit/com/raytheon/uf/common/datadelivery/registry/handlers/GroupDefinitionServiceTest.java b/tests/unit/com/raytheon/uf/common/datadelivery/registry/handlers/GroupDefinitionServiceTest.java new file mode 100644 index 0000000000..0ef1a3125c --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/datadelivery/registry/handlers/GroupDefinitionServiceTest.java @@ -0,0 +1,135 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.datadelivery.registry.handlers; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.emptyCollectionOf; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.junit.Before; +import org.junit.Test; + +import com.raytheon.uf.common.datadelivery.registry.GroupDefinition; +import com.raytheon.uf.common.datadelivery.registry.GroupDefinitionServiceRequest; +import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.SubscriptionBuilder; +import com.raytheon.uf.common.datadelivery.service.GroupDefinitionService; +import com.raytheon.uf.common.datadelivery.service.ISubscriptionNotificationService; +import com.raytheon.uf.common.registry.RegistryManagerTest; +import com.raytheon.uf.common.registry.handler.RegistryHandlerException; +import com.raytheon.uf.common.registry.handler.RegistryObjectHandlersUtil; +import com.raytheon.uf.edex.datadelivery.service.services.GroupDefinitionServiceHandler; + +/** + * Test {@link GroupDefinitionHandler}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 18, 2013 1441       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public class GroupDefinitionServiceTest { + + private static final String GROUP_NAME = "someGroup"; + + private ISubscriptionHandler subscriptionHandler; + + private IGroupDefinitionHandler groupHandler; + + private final ISubscriptionNotificationService subscriptionNotificationService = mock(ISubscriptionNotificationService.class); + + private final GroupDefinitionService service = new GroupDefinitionService() { + @Override + protected Object sendRequest(GroupDefinitionServiceRequest request) + throws RegistryHandlerException { + try { + return new GroupDefinitionServiceHandler( + subscriptionNotificationService).handleRequest(request); + } catch (Exception e) { + throw new RegistryHandlerException(e); + } + } + }; + + private final GroupDefinition group = new GroupDefinition(); + + @Before + public void setUp() throws RegistryHandlerException { + RegistryObjectHandlersUtil.initMemory(); + RegistryManagerTest.setMockInstance(); + + subscriptionHandler = DataDeliveryHandlers.getSubscriptionHandler(); + groupHandler = DataDeliveryHandlers.getGroupDefinitionHandler(); + + group.setGroupName(GROUP_NAME); + groupHandler.store(group); + + Subscription subscription = new SubscriptionBuilder().withGroupName( + GROUP_NAME).build(); + Subscription subscription2 = new Subscription(subscription, "sub2"); + + subscriptionHandler.store(subscription); + subscriptionHandler.store(subscription2); + } + + @Test + public void deletingAGroupUpdatesSubscriptionsToNotHaveAGroupName() + throws RegistryHandlerException { + + service.deleteGroupDefinition(group); + + assertThat(subscriptionHandler.getByGroupName(GROUP_NAME), + is(emptyCollectionOf(Subscription.class))); + } + + @Test + public void deletingAGroupNotifiesOfSubscriptionUpdates() + throws RegistryHandlerException { + service.deleteGroupDefinition(group); + + verify(subscriptionNotificationService, times(2)) + .sendUpdatedSubscriptionNotification(any(Subscription.class), + anyString()); + } + + @Test + public void deletingAGroupDeletesTheGroup() throws RegistryHandlerException { + + service.deleteGroupDefinition(group); + + assertNull(groupHandler.getByName(GROUP_NAME)); + } + +} diff --git a/tests/unit/com/raytheon/uf/common/localization/TestPathManager.java b/tests/unit/com/raytheon/uf/common/localization/TestPathManager.java index 6967828aac..dbd105ca8e 100644 --- a/tests/unit/com/raytheon/uf/common/localization/TestPathManager.java +++ b/tests/unit/com/raytheon/uf/common/localization/TestPathManager.java @@ -40,6 +40,7 @@ import com.raytheon.uf.common.util.FileUtil; * ------------ ---------- ----------- -------------------------- * Jul 18, 2012 740 djohnson Initial creation * Oct 23, 2012 1286 djohnson Change to find more localization files. + * Jan 16, 2013 1487 djohnson Avoid adding new localization files to baseline utility directories. * * * @@ -131,21 +132,44 @@ public class TestPathManager extends PathManager { } if (foundFile == null - || !foundFile.exists() || foundFile.getAbsolutePath().startsWith( savedLocalizationFileDir.getAbsolutePath())) { return foundFile; } - // Make a copy in the savedFile folder, this way if any - // modifications are performed we don't mess with the file in - // the baseline + + File savedFile = createTestIsolatedVersionOfLocalizationFile( + context, fileName, foundFile); + return savedFile; + } + + /** + * Creates a test isolated version of the localization file. Allows the + * file to be written to, and changes to be read back, without affecting + * the baselined version of the file. + * + * @param context + * the context + * @param fileName + * the file path + * @param baselinedVersion + * the file reference + * @return + */ + private File createTestIsolatedVersionOfLocalizationFile( + LocalizationContext context, String fileName, File baselinedVersion) { File savedFileBaseDir = new File(savedLocalizationFileDir, context.toPath()); File savedFile = new File(savedFileBaseDir, fileName); savedFile.getParentFile().mkdirs(); try { - FileUtil.copyFile(foundFile, savedFile); + if (baselinedVersion.exists()) { + if (baselinedVersion.isDirectory()) { + FileUtil.copyDirectory(baselinedVersion, savedFile); + } else { + FileUtil.copyFile(baselinedVersion, savedFile); + } + } } catch (IOException e) { throw new RuntimeException(e); } diff --git a/tests/unit/com/raytheon/uf/common/registry/RegistryManagerTest.java b/tests/unit/com/raytheon/uf/common/registry/RegistryManagerTest.java index f71de52158..38ff11d5a7 100644 --- a/tests/unit/com/raytheon/uf/common/registry/RegistryManagerTest.java +++ b/tests/unit/com/raytheon/uf/common/registry/RegistryManagerTest.java @@ -19,8 +19,13 @@ **/ package com.raytheon.uf.common.registry; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyList; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import org.junit.Ignore; -import org.mockito.Mockito; /** * Allows setting a specific {@link RegistryHandler} instance for test purposes. @@ -48,9 +53,23 @@ public class RegistryManagerTest { * * @return the mock {@link RegistryHandler}. */ + @SuppressWarnings({ "rawtypes", "unchecked" }) public static RegistryHandler setMockInstance() { - RegistryHandler mock = Mockito.mock(RegistryHandler.class); + RegistryHandler mock = mock(RegistryHandler.class); RegistryManagerTest.setInstance(mock); + RegistryQueryResponse response = mock(RegistryQueryResponse.class); + when(response.getStatus()).thenReturn(OperationStatus.SUCCESS); + // Handles the responses for deletes, stores, and updates... + // TODO: Handle retrieving objects? + when(mock.removeObjects(any(RegistryQuery.class))).thenReturn(response); + when(mock.removeObjects(anyString(), anyList())).thenReturn(response); + when(mock.removeObjects(anyString(), any(RegistryQuery.class))) + .thenReturn(response); + when(mock.storeObject(any())).thenReturn(response); + when(mock.storeOrReplaceObject(any())).thenReturn(response); + when(mock.removeObjects(anyString(), any(RegistryQuery.class))) + .thenReturn(response); + return mock; } diff --git a/tests/unit/com/raytheon/uf/common/stats/data/DataPointTest.java b/tests/unit/com/raytheon/uf/common/stats/data/DataPointTest.java index 675fa61bb1..e65a4d3530 100644 --- a/tests/unit/com/raytheon/uf/common/stats/data/DataPointTest.java +++ b/tests/unit/com/raytheon/uf/common/stats/data/DataPointTest.java @@ -10,7 +10,7 @@ import java.util.TimeZone; import org.junit.Test; import com.raytheon.uf.common.stats.AggregateRecord; -import com.raytheon.uf.common.stats.util.DataViewUtils; +import com.raytheon.uf.common.stats.util.DataView; public class DataPointTest { private final String eventType = "com.raytheon.uf.common.stats.ProcessEvent"; @@ -38,7 +38,7 @@ public class DataPointTest { assertEquals("Count does not match", expectedCount, point.getCount(), 0); assertEquals("Count does not match", expectedCount, - point.getValue(DataViewUtils.DataView.COUNT.getView()), 0); + point.getValue(DataView.COUNT), 0); } @Test @@ -60,7 +60,7 @@ public class DataPointTest { assertEquals("Sum does not match", expectedSum, point.getSum(), 0); assertEquals("Sum does not match", expectedSum, - point.getValue(DataViewUtils.DataView.SUM.getView()), 0); + point.getValue(DataView.SUM), 0); } @Test @@ -82,7 +82,7 @@ public class DataPointTest { assertEquals("Min does not match", expectedMin, point.getMin(), 0); assertEquals("Min does not match", expectedMin, - point.getValue(DataViewUtils.DataView.MIN.getView()), 0); + point.getValue(DataView.MIN), 0); } @Test @@ -104,7 +104,7 @@ public class DataPointTest { assertEquals("Max does not match", expectedMax, point.getMax(), 0); assertEquals("Max does not match", expectedMax, - point.getValue(DataViewUtils.DataView.MAX.getView()), 0); + point.getValue(DataView.MAX), 0); } @Test @@ -128,7 +128,7 @@ public class DataPointTest { assertEquals("Avg does not match", expectedAvg, point.getAvg(), 0.25); assertEquals("Avg does not match", expectedAvg, - point.getValue(DataViewUtils.DataView.AVG.getView()), 0.25); + point.getValue(DataView.AVG), 0.25); } // Build the Aggregate records diff --git a/tests/unit/com/raytheon/uf/common/stats/data/StatsDataTest.java b/tests/unit/com/raytheon/uf/common/stats/data/StatsDataTest.java index a809993eff..39f11bb83d 100644 --- a/tests/unit/com/raytheon/uf/common/stats/data/StatsDataTest.java +++ b/tests/unit/com/raytheon/uf/common/stats/data/StatsDataTest.java @@ -17,7 +17,9 @@ import com.raytheon.uf.common.time.util.TimeUtil; public class StatsDataTest { private final String eventType = "com.raytheon.uf.common.stats.ProcessEvent"; + private final String field = "processingTime"; + private final String grouping = "pluginName:obs"; final Map bins = new TreeMap(); @@ -41,7 +43,8 @@ public class StatsDataTest { UnitUtils unitUtils = new UnitUtils(eventType, field); unitUtils.setDisplayUnit("ms"); - StatsData statsData = new StatsData("key", TimeUtil.MILLIS_PER_MINUTE, null, unitUtils); + StatsData statsData = new StatsData("key", TimeUtil.MILLIS_PER_MINUTE, + null); statsData.setBins(bins); statsData.addRecord(records.get(0)); statsData.addRecord(records.get(1)); @@ -50,11 +53,10 @@ public class StatsDataTest { List pointList = statsData.getData(); int expectedPointCount = 2; - assertEquals("Point Counts differ", expectedPointCount, pointList.size(), 0); + assertEquals("Point Counts differ", expectedPointCount, + pointList.size(), 0); } - - // Build the Aggregate records private List getTestRecords() { List records = new ArrayList(); diff --git a/tests/unit/com/raytheon/uf/common/stats/util/UnitUtilsTest.java b/tests/unit/com/raytheon/uf/common/stats/util/UnitUtilsTest.java new file mode 100644 index 0000000000..3515ba3021 --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/stats/util/UnitUtilsTest.java @@ -0,0 +1,179 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.stats.util; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.raytheon.uf.common.stats.ProcessEvent; +import com.raytheon.uf.common.stats.util.UnitUtils.TimeConversion; +import com.raytheon.uf.common.stats.util.UnitUtils.UnitTypes; +import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.common.units.DataSizeUnit; + +/** + * TODO Add Description + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 17, 2013   1357      mpduff     Initial creation
+ * 
+ * 
+ * + * @author mpduff + * @version 1.0 + */ + +public class UnitUtilsTest { + + private static final String EVENT_TYPE = ProcessEvent.class.getName(); + + private static final String DATA_TYPE = "processingTime"; + + @Test + public void testConvertBytesToBytes() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(DataSizeUnit.BYTE.getUnit()); + uu.setDisplayUnit(DataSizeUnit.BYTE.getUnit()); + + double value = uu.convertDataSizeValue(DataSizeUnit.BYTE, 100); + + assertEquals(100, value, 0); + } + + @Test + public void testConvertBytesToKb() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(DataSizeUnit.BYTE.getUnit()); + uu.setDisplayUnit(DataSizeUnit.KB.getUnit()); + + double value = uu.convertDataSizeValue(DataSizeUnit.BYTE, 1024); + + assertEquals(1, value, 0); + } + + @Test + public void testConvertBytesToMb() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(DataSizeUnit.BYTE.getUnit()); + uu.setDisplayUnit(DataSizeUnit.MB.getUnit()); + + double value = uu.convertDataSizeValue(DataSizeUnit.BYTE, 1048576); + + assertEquals(1, value, 0); + } + + @Test + public void testConvertValueFromMsToSecond() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(TimeConversion.MS.getDataUnit()); + uu.setDisplayUnit(TimeConversion.Second.getDataUnit()); + + double value = uu.convertTimeValue(TimeConversion.MS, + TimeUtil.MILLIS_PER_SECOND * 3); + + assertEquals(3, value, 0); + } + + @Test + public void testConvertValueFromMsToMinute() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(TimeConversion.MS.getDataUnit()); + uu.setDisplayUnit(TimeConversion.Minute.getDataUnit()); + + double value = uu.convertTimeValue(TimeConversion.MS, + TimeUtil.MILLIS_PER_MINUTE * 2); + + assertEquals(2, value, 0); + } + + @Test + public void testConvertValueFromMsToHours() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(TimeConversion.MS.getDataUnit()); + uu.setDisplayUnit(TimeConversion.Hour.getDataUnit()); + + double value = uu.convertTimeValue(TimeConversion.MS, + TimeUtil.MILLIS_PER_HOUR); + + assertEquals(1, value, 0); + } + + @Test + public void testConvertValueFromHoursToMs() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(TimeConversion.Hour.getDataUnit()); + uu.setDisplayUnit(TimeConversion.MS.getDataUnit()); + + double value = uu.convertTimeValue(TimeConversion.Hour, 1); + + assertEquals(TimeUtil.MILLIS_PER_HOUR, value, 0); + } + + @Test + public void testVerifyDisplayUnitIsTime() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(TimeConversion.Hour.getDataUnit()); + uu.setDisplayUnit(TimeConversion.MS.getDataUnit()); + + UnitTypes type = uu.getUnitType(); + + assertEquals(UnitTypes.TIME, type); + } + + @Test + public void testVerifyDisplayUnitIsSize() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(DataSizeUnit.KB.getUnit()); + uu.setDisplayUnit(DataSizeUnit.MB.getUnit()); + + UnitTypes type = uu.getUnitType(); + + assertEquals(UnitTypes.DATA_SIZE, type); + } + + @Test + public void testConvertValueToSec() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(TimeConversion.MS.getDataUnit()); + uu.setDisplayUnit(TimeConversion.Second.getDataUnit()); + + double value = uu.convertValue(TimeUtil.MILLIS_PER_SECOND * 3); + + assertEquals(3, value, 0); + } + + @Test + public void testConvertValueToMinute() { + UnitUtils uu = new UnitUtils(EVENT_TYPE, DATA_TYPE); + uu.setUnitType(TimeConversion.MS.getDataUnit()); + uu.setDisplayUnit(TimeConversion.Minute.getDataUnit()); + + double value = uu.convertValue(TimeUtil.MILLIS_PER_MINUTE * 3); + + assertEquals(3, value, 0); + } + +} diff --git a/tests/unit/com/raytheon/uf/common/time/domain/DurationTest.java b/tests/unit/com/raytheon/uf/common/time/domain/DurationTest.java new file mode 100644 index 0000000000..8ab3593e2d --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/time/domain/DurationTest.java @@ -0,0 +1,302 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import static com.raytheon.uf.common.serialization.SerializationUtil.transformFromThrift; +import static com.raytheon.uf.common.serialization.SerializationUtil.transformToThrift; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.xml.bind.JAXBException; + +import org.junit.Test; + +import com.raytheon.uf.common.serialization.JAXBManager; +import com.raytheon.uf.common.serialization.SerializationException; +import com.raytheon.uf.common.time.domain.api.IDuration; +import com.raytheon.uf.common.util.TestUtil; + +/** + * Test {@link Duration}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 10, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public class DurationTest { + + private static final long TWO_DAYS_IN_NANOS = TimeUnit.DAYS.toNanos(2); + + private static final long TWO_DAYS_IN_MICROS = TimeUnit.DAYS.toMicros(2); + + private static final long TWO_DAYS_IN_MILLIS = TimeUnit.DAYS.toMillis(2); + + private static final long TWO_DAYS_IN_SECONDS = TimeUnit.DAYS.toSeconds(2); + + private static final long TWO_DAYS_IN_MINUTES = TimeUnit.DAYS.toMinutes(2); + + private static final long TWO_DAYS_IN_HOURS = TimeUnit.DAYS.toHours(2); + + private static final long TWO_DAYS_IN_DAYS = TimeUnit.DAYS.toDays(2); + + @Test + public void testNanosecondsConvertToEntireRange() { + IDuration duration = new Duration(TWO_DAYS_IN_NANOS, + TimeUnit.NANOSECONDS); + + assertThat(TWO_DAYS_IN_NANOS, is(equalTo(duration.getNanos()))); + assertThat(TWO_DAYS_IN_MICROS, is(equalTo(duration.getMicros()))); + assertThat(TWO_DAYS_IN_MILLIS, is(equalTo(duration.getMillis()))); + assertThat(TWO_DAYS_IN_SECONDS, is(equalTo(duration.getSeconds()))); + assertThat(TWO_DAYS_IN_MINUTES, is(equalTo(duration.getMinutes()))); + assertThat(TWO_DAYS_IN_HOURS, is(equalTo(duration.getHours()))); + assertThat(TWO_DAYS_IN_DAYS, is(equalTo(duration.getDays()))); + } + + @Test + public void testNanosecondsConvertToZeroWhenNotEnoughOfTargetUnit() { + final long startValue = 5L; + IDuration duration = new Duration(startValue, TimeUnit.NANOSECONDS); + + assertThat(startValue, is(equalTo(duration.getNanos()))); + assertThat(0L, is(equalTo(duration.getMicros()))); + assertThat(0L, is(equalTo(duration.getMillis()))); + assertThat(0L, is(equalTo(duration.getSeconds()))); + assertThat(0L, is(equalTo(duration.getMinutes()))); + assertThat(0L, is(equalTo(duration.getHours()))); + assertThat(0L, is(equalTo(duration.getDays()))); + } + + @Test + public void testMicrosecondsConvertToEntireRange() { + IDuration duration = new Duration(TWO_DAYS_IN_MICROS, + TimeUnit.MICROSECONDS); + + assertThat(TWO_DAYS_IN_NANOS, is(equalTo(duration.getNanos()))); + assertThat(TWO_DAYS_IN_MICROS, is(equalTo(duration.getMicros()))); + assertThat(TWO_DAYS_IN_MILLIS, is(equalTo(duration.getMillis()))); + assertThat(TWO_DAYS_IN_SECONDS, is(equalTo(duration.getSeconds()))); + assertThat(TWO_DAYS_IN_MINUTES, is(equalTo(duration.getMinutes()))); + assertThat(TWO_DAYS_IN_HOURS, is(equalTo(duration.getHours()))); + assertThat(TWO_DAYS_IN_DAYS, is(equalTo(duration.getDays()))); + } + + @Test + public void testMicrosecondsConvertToZeroWhenNotEnoughOfTargetUnit() { + final long startValue = 5L; + IDuration duration = new Duration(startValue, TimeUnit.MICROSECONDS); + + assertThat(startValue, is(equalTo(duration.getMicros()))); + assertThat(0L, is(equalTo(duration.getMillis()))); + assertThat(0L, is(equalTo(duration.getSeconds()))); + assertThat(0L, is(equalTo(duration.getMinutes()))); + assertThat(0L, is(equalTo(duration.getHours()))); + assertThat(0L, is(equalTo(duration.getDays()))); + } + + @Test + public void testMillisecondsConvertToEntireRange() { + IDuration duration = new Duration(TWO_DAYS_IN_MILLIS, + TimeUnit.MILLISECONDS); + + assertThat(TWO_DAYS_IN_NANOS, is(equalTo(duration.getNanos()))); + assertThat(TWO_DAYS_IN_MICROS, is(equalTo(duration.getMicros()))); + assertThat(TWO_DAYS_IN_MILLIS, is(equalTo(duration.getMillis()))); + assertThat(TWO_DAYS_IN_SECONDS, is(equalTo(duration.getSeconds()))); + assertThat(TWO_DAYS_IN_MINUTES, is(equalTo(duration.getMinutes()))); + assertThat(TWO_DAYS_IN_HOURS, is(equalTo(duration.getHours()))); + assertThat(TWO_DAYS_IN_DAYS, is(equalTo(duration.getDays()))); + } + + @Test + public void testMillisecondsConvertToZeroWhenNotEnoughOfTargetUnit() { + final long startValue = 5L; + IDuration duration = new Duration(startValue, TimeUnit.MILLISECONDS); + + assertThat(startValue, is(equalTo(duration.getMillis()))); + assertThat(0L, is(equalTo(duration.getSeconds()))); + assertThat(0L, is(equalTo(duration.getMinutes()))); + assertThat(0L, is(equalTo(duration.getHours()))); + assertThat(0L, is(equalTo(duration.getDays()))); + } + + @Test + public void testSecondsConvertToEntireRange() { + IDuration duration = new Duration(TWO_DAYS_IN_SECONDS, TimeUnit.SECONDS); + + assertThat(TWO_DAYS_IN_NANOS, is(equalTo(duration.getNanos()))); + assertThat(TWO_DAYS_IN_MICROS, is(equalTo(duration.getMicros()))); + assertThat(TWO_DAYS_IN_MILLIS, is(equalTo(duration.getMillis()))); + assertThat(TWO_DAYS_IN_SECONDS, is(equalTo(duration.getSeconds()))); + assertThat(TWO_DAYS_IN_MINUTES, is(equalTo(duration.getMinutes()))); + assertThat(TWO_DAYS_IN_HOURS, is(equalTo(duration.getHours()))); + assertThat(TWO_DAYS_IN_DAYS, is(equalTo(duration.getDays()))); + } + + @Test + public void testSecondsConvertToZeroWhenNotEnoughOfTargetUnit() { + final long startValue = 5L; + IDuration duration = new Duration(startValue, TimeUnit.SECONDS); + + assertThat(startValue, is(equalTo(duration.getSeconds()))); + assertThat(0L, is(equalTo(duration.getMinutes()))); + assertThat(0L, is(equalTo(duration.getHours()))); + assertThat(0L, is(equalTo(duration.getDays()))); + } + + @Test + public void testMinutesConvertToEntireRange() { + IDuration duration = new Duration(TWO_DAYS_IN_MINUTES, TimeUnit.MINUTES); + + assertThat(TWO_DAYS_IN_NANOS, is(equalTo(duration.getNanos()))); + assertThat(TWO_DAYS_IN_MICROS, is(equalTo(duration.getMicros()))); + assertThat(TWO_DAYS_IN_MILLIS, is(equalTo(duration.getMillis()))); + assertThat(TWO_DAYS_IN_SECONDS, is(equalTo(duration.getSeconds()))); + assertThat(TWO_DAYS_IN_MINUTES, is(equalTo(duration.getMinutes()))); + assertThat(TWO_DAYS_IN_HOURS, is(equalTo(duration.getHours()))); + assertThat(TWO_DAYS_IN_DAYS, is(equalTo(duration.getDays()))); + } + + @Test + public void testMinutesConvertToZeroWhenNotEnoughOfTargetUnit() { + final long startValue = 5L; + IDuration duration = new Duration(startValue, TimeUnit.MINUTES); + + assertThat(startValue, is(equalTo(duration.getMinutes()))); + assertThat(0L, is(equalTo(duration.getHours()))); + assertThat(0L, is(equalTo(duration.getDays()))); + } + + @Test + public void testHoursConvertToEntireRange() { + IDuration duration = new Duration(TWO_DAYS_IN_HOURS, TimeUnit.HOURS); + + assertThat(TWO_DAYS_IN_NANOS, is(equalTo(duration.getNanos()))); + assertThat(TWO_DAYS_IN_MICROS, is(equalTo(duration.getMicros()))); + assertThat(TWO_DAYS_IN_MILLIS, is(equalTo(duration.getMillis()))); + assertThat(TWO_DAYS_IN_SECONDS, is(equalTo(duration.getSeconds()))); + assertThat(TWO_DAYS_IN_MINUTES, is(equalTo(duration.getMinutes()))); + assertThat(TWO_DAYS_IN_HOURS, is(equalTo(duration.getHours()))); + assertThat(TWO_DAYS_IN_DAYS, is(equalTo(duration.getDays()))); + } + + @Test + public void testHoursConvertToZeroWhenNotEnoughOfTargetUnit() { + final long startValue = 5L; + IDuration duration = new Duration(startValue, TimeUnit.HOURS); + + assertThat(startValue, is(equalTo(duration.getHours()))); + assertThat(0L, is(equalTo(duration.getDays()))); + } + + @Test + public void testDaysConvertToEntireRange() { + IDuration duration = new Duration(TWO_DAYS_IN_DAYS, TimeUnit.DAYS); + + assertThat(TWO_DAYS_IN_NANOS, is(equalTo(duration.getNanos()))); + assertThat(TWO_DAYS_IN_MICROS, is(equalTo(duration.getMicros()))); + assertThat(TWO_DAYS_IN_MILLIS, is(equalTo(duration.getMillis()))); + assertThat(TWO_DAYS_IN_SECONDS, is(equalTo(duration.getSeconds()))); + assertThat(TWO_DAYS_IN_MINUTES, is(equalTo(duration.getMinutes()))); + assertThat(TWO_DAYS_IN_HOURS, is(equalTo(duration.getHours()))); + assertThat(TWO_DAYS_IN_DAYS, is(equalTo(duration.getDays()))); + } + + @Test + public void testAddDurationReturnsCorrectAmount() { + IDuration dur1 = new Duration(2, TimeUnit.HOURS); + IDuration dur2 = new Duration(2, TimeUnit.DAYS); + + assertThat(new Duration(50, TimeUnit.HOURS), + is(equalTo(dur1.plus(dur2)))); + } + + @Test + public void testSubtractDurationReturnsCorrectAmount() { + IDuration dur1 = new Duration(2, TimeUnit.DAYS); + IDuration dur2 = new Duration(2, TimeUnit.HOURS); + + assertThat(new Duration(46, TimeUnit.HOURS), + is(equalTo(dur1.minus(dur2)))); + } + + @Test + public void testConversionToAndFromDynamicSerialize() + throws SerializationException { + IDuration original = new Duration(2, TimeUnit.DAYS); + UsesDuration usesDuration = new UsesDuration(); + usesDuration.setDuration(original); + + IDuration restored = transformFromThrift(UsesDuration.class, + transformToThrift(usesDuration)).getDuration(); + + assertThat(restored, is(equalTo(original))); + } + + @Test + public void testConversionToAndFromJaxb() throws SerializationException, + JAXBException { + IDuration original = new Duration(2, TimeUnit.DAYS); + UsesDuration usesDuration = new UsesDuration(); + usesDuration.setDuration(original); + + JAXBManager manager = new JAXBManager(UsesDuration.class); + final String xml = manager.marshalToXml(usesDuration); + + IDuration restored = ((UsesDuration) manager.unmarshalFromXml(xml)) + .getDuration(); + + assertThat(restored, is(equalTo(original))); + } + + @Test + public void testEqualsAndHashcodeContract() { + IDuration objectUnderTest = Durations.of(TWO_DAYS_IN_DAYS, + TimeUnit.DAYS); + + List equalObjects = Arrays.asList( + Durations.of(TWO_DAYS_IN_HOURS, TimeUnit.HOURS), + Durations.of(TWO_DAYS_IN_MINUTES, TimeUnit.MINUTES), + Durations.of(TWO_DAYS_IN_SECONDS, TimeUnit.SECONDS)); + + List unequalObjects = Arrays.asList( + Durations.of(TWO_DAYS_IN_HOURS + 1, TimeUnit.HOURS), + Durations.of(TWO_DAYS_IN_MINUTES + 1, TimeUnit.MINUTES), + Durations.of(TWO_DAYS_IN_SECONDS + 1, TimeUnit.SECONDS)); + + TestUtil.assertEqualsAndHashcodeContract(objectUnderTest, equalObjects, + unequalObjects); + } +} diff --git a/tests/unit/com/raytheon/uf/common/time/domain/DurationsTest.java b/tests/unit/com/raytheon/uf/common/time/domain/DurationsTest.java new file mode 100644 index 0000000000..80b6d244e2 --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/time/domain/DurationsTest.java @@ -0,0 +1,94 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import com.raytheon.uf.common.time.domain.api.IDuration; + +/** + * Test {@link Durations}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 11, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public class DurationsTest { + + @Test + public void testParseFromString() { + IDuration duration = Durations.fromString("3 SECONDS"); + + assertThat(duration, is(equalTo(Durations.of(3, TimeUnit.SECONDS)))); + } + + @Test(expected = IllegalArgumentException.class) + public void testUnparseableStringThrowsException() { + Durations.fromString("unparseable"); + } + + @Test + public void testToStringWritesOutLargestUnitNotLosingPrecision() { + final String original = "3 SECONDS"; + IDuration duration = Durations.fromString(original); + + assertThat(Durations.toString(duration), is(equalTo(original))); + } + + @Test + public void testToStringForSmallestUnit() { + final String original = "1 NANOSECONDS"; + IDuration duration = Durations.fromString(original); + + assertThat(Durations.toString(duration), is(equalTo(original))); + } + + @Test + public void testToStringForLargestUnit() { + final String original = "7 DAYS"; + IDuration duration = Durations.fromString(original); + + assertThat(Durations.toString(duration), is(equalTo(original))); + } + + @Test + public void test128MinutesDoesNotUseHours() { + final String original = "128 MINUTES"; + IDuration duration = Durations.fromString(original); + + assertThat(Durations.toString(duration), is(equalTo(original))); + } +} diff --git a/tests/unit/com/raytheon/uf/common/time/domain/TimeIntervalTest.java b/tests/unit/com/raytheon/uf/common/time/domain/TimeIntervalTest.java new file mode 100644 index 0000000000..ea67921f7d --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/time/domain/TimeIntervalTest.java @@ -0,0 +1,157 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import static com.raytheon.uf.common.serialization.SerializationUtil.transformFromThrift; +import static com.raytheon.uf.common.serialization.SerializationUtil.transformToThrift; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.xml.bind.JAXBException; + +import org.junit.Test; + +import com.raytheon.uf.common.serialization.JAXBManager; +import com.raytheon.uf.common.serialization.SerializationException; +import com.raytheon.uf.common.time.domain.api.ITimeInterval; +import com.raytheon.uf.common.time.domain.api.ITimePoint; +import com.raytheon.uf.common.util.TestUtil; + +/** + * Test {@link TimeInterval}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +public class TimeIntervalTest { + + private final ITimePoint intervalStart = TimePoints.fromMillis(100L); + + private final ITimePoint intervalEnd = TimePoints.fromMillis(500L); + + private final ITimeInterval interval = new TimeInterval(intervalStart, + intervalEnd); + + @Test + public void testConversionToAndFromDynamicSerialize() + throws SerializationException { + UsesTimeInterval usesTimeInterval = new UsesTimeInterval(); + usesTimeInterval.setTimeInterval(interval); + + ITimeInterval restored = transformFromThrift(UsesTimeInterval.class, + transformToThrift(usesTimeInterval)).getTimeInterval(); + + assertThat(restored, is(equalTo(interval))); + } + + @Test + public void testConversionToAndFromJaxb() throws SerializationException, + JAXBException { + UsesTimeInterval usesTimeInterval = new UsesTimeInterval(); + usesTimeInterval.setTimeInterval(interval); + + JAXBManager manager = new JAXBManager(UsesTimeInterval.class); + final String xml = manager.marshalToXml(usesTimeInterval); + + ITimeInterval restored = ((UsesTimeInterval) manager + .unmarshalFromXml(xml)).getTimeInterval(); + + assertThat(restored, is(equalTo(interval))); + } + + @Test + public void testGetStartReturnsCorrectTimePoint() { + assertThat(interval.getStart(), is(equalTo(intervalStart))); + } + + @Test + public void testGetEndReturnsCorrectTimePoint() { + assertThat(interval.getEnd(), is(equalTo(intervalEnd))); + } + + @Test + public void testContainsTimePointReturnsTrueForMidPointWithinInterval() { + final ITimePoint withinInterval = TimePoints.fromMillis((intervalStart + .asMilliseconds() + intervalEnd.asMilliseconds()) / 2); + + assertTrue( + "The interval should have returned true for a time point contained in it!", + interval.containsTimePoint(withinInterval)); + } + + @Test + public void testContainsTimePointReturnsTrueForIntervalStart() { + assertTrue( + "The interval should have returned true for a time point contained in it!", + interval.containsTimePoint(intervalStart)); + } + + @Test + public void testContainsTimePointReturnsTrueForIntervalEnd() { + assertTrue( + "The interval should have returned true for a time point contained in it!", + interval.containsTimePoint(intervalEnd)); + } + + @Test + public void testGetDurationReturnsCorrectAmount() { + assertThat(interval.getDuration(), is(equalTo(Durations.of( + intervalEnd.asMilliseconds() - intervalStart.asMilliseconds(), + TimeUnit.MILLISECONDS)))); + } + + @Test + public void testEqualsAndHashcodeContract() { + ITimeInterval sameInterval = new TimeInterval( + TimePoints.fromMillis(intervalStart.asMilliseconds()), + TimePoints.fromMillis(intervalEnd.asMilliseconds())); + List equalObjects = Arrays + . asList(sameInterval); + + ITimeInterval startOneMillisecondEarlier = new TimeInterval( + TimePoints.fromMillis(intervalStart.asMilliseconds() - 1L), + TimePoints.fromMillis(intervalEnd.asMilliseconds())); + ITimeInterval endOneMillisecondLater = new TimeInterval( + TimePoints.fromMillis(intervalStart.asMilliseconds()), + TimePoints.fromMillis(intervalEnd.asMilliseconds() + 1L)); + + List unequalObjects = Arrays. asList( + startOneMillisecondEarlier, endOneMillisecondLater); + + TestUtil.assertEqualsAndHashcodeContract(interval, equalObjects, + unequalObjects); + } +} diff --git a/tests/unit/com/raytheon/uf/common/time/domain/TimeIntervalsTest.java b/tests/unit/com/raytheon/uf/common/time/domain/TimeIntervalsTest.java new file mode 100644 index 0000000000..872b010043 --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/time/domain/TimeIntervalsTest.java @@ -0,0 +1,48 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import org.junit.Test; + +/** + * Test {@link TimeIntervals}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +public class TimeIntervalsTest { + + @Test(expected = IllegalArgumentException.class) + public void testEndCantBeBeforeStart() { + TimeIntervals.fromTimePoints(TimePoints.fromMillis(20L), + TimePoints.fromMillis(10L)); + } + +} diff --git a/tests/unit/com/raytheon/uf/common/time/domain/TimePointTest.java b/tests/unit/com/raytheon/uf/common/time/domain/TimePointTest.java new file mode 100644 index 0000000000..ac2ab6b50e --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/time/domain/TimePointTest.java @@ -0,0 +1,202 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import static com.raytheon.uf.common.serialization.SerializationUtil.transformFromThrift; +import static com.raytheon.uf.common.serialization.SerializationUtil.transformToThrift; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import javax.xml.bind.JAXBException; + +import org.junit.Test; + +import com.raytheon.uf.common.serialization.JAXBManager; +import com.raytheon.uf.common.serialization.SerializationException; +import com.raytheon.uf.common.time.domain.api.ITimeInterval; +import com.raytheon.uf.common.time.domain.api.ITimePoint; +import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.common.util.TestUtil; + +/** + * Test {@link TimePoint}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public class TimePointTest { + + private final ITimePoint earlierPoint = new TimePoint(1L); + + private final ITimePoint laterPoint = new TimePoint(2L); + + private final ITimePoint sameAsEarlierPoint = new TimePoint(earlierPoint); + + @Test + public void testConversionToAndFromDynamicSerialize() + throws SerializationException { + UsesTimePoint usesTimePoint = new UsesTimePoint(); + usesTimePoint.setTimePoint(laterPoint); + + ITimePoint restored = transformFromThrift(UsesTimePoint.class, + transformToThrift(usesTimePoint)).getTimePoint(); + + assertThat(restored, is(equalTo(laterPoint))); + } + + @Test + public void testConversionToAndFromJaxb() throws SerializationException, + JAXBException { + UsesTimePoint usesTimePoint = new UsesTimePoint(); + usesTimePoint.setTimePoint(laterPoint); + + JAXBManager manager = new JAXBManager(UsesTimePoint.class); + final String xml = manager.marshalToXml(usesTimePoint); + + ITimePoint restored = ((UsesTimePoint) manager.unmarshalFromXml(xml)) + .getTimePoint(); + + assertThat(restored, is(equalTo(laterPoint))); + } + + @Test + public void testAsDateReturnsSameInstance() { + Date date = new Date(); + + TimePoint timePoint = new TimePoint(date.getTime()); + + assertThat(timePoint.asDate(), is(equalTo(date))); + } + + @Test + public void testAsMillisecondsReturnsOriginalValue() { + final long originalMillis = TimeUtil.currentTimeMillis(); + TimePoint timePoint = new TimePoint(originalMillis); + + assertThat(timePoint.asMilliseconds(), is(equalTo(originalMillis))); + } + + @Test + public void testIsAfterReturnsTrueWhenLater() { + assertTrue("The later point should have been recognized as later!", + laterPoint.isAfter(earlierPoint)); + } + + @Test + public void testIsAfterReturnsFalseWhenEarlier() { + assertFalse( + "The earlier point should have been recognized as not later!", + earlierPoint.isAfter(laterPoint)); + } + + @Test + public void testIsAfterReturnsFalseWhenSameTime() { + assertFalse( + "The earlier point should have been recognized as not later!", + sameAsEarlierPoint.isAfter(laterPoint)); + } + + @Test + public void testIsBeforeReturnsTrueWhenEarlier() { + assertTrue("The earlier point should have been recognized as earlier!", + earlierPoint.isBefore(laterPoint)); + } + + @Test + public void testIsBeforeReturnsFalseWhenLater() { + assertFalse( + "The later point should have been recognized as not earlier!", + laterPoint.isBefore(earlierPoint)); + } + + @Test + public void testIsBeforeReturnsFalseWhenSameTime() { + assertFalse( + "The same time point should have been recognized as not earlier!", + sameAsEarlierPoint.isBefore(earlierPoint)); + } + + @Test + public void testIsSameReturnsFalseWhenEarlier() { + assertFalse("The earlier point should not have been the same!", + earlierPoint.isSame(laterPoint)); + } + + @Test + public void testIsSameReturnsFalseWhenLater() { + assertFalse("The later point should not have been the same!", + laterPoint.isSame(earlierPoint)); + } + + @Test + public void testIsSameReturnsTrueWhenSameTime() { + assertTrue( + "The same time point should have been recognized as the same time!", + sameAsEarlierPoint.isSame(earlierPoint)); + } + + @Test + public void testIsWithinReturnsTrueForTimeIntervalThatContainsIt() { + ITimeInterval interval = TimeIntervals.fromTimePoints(earlierPoint, + laterPoint); + assertTrue( + "The time point should have returned true for being within the interval", + earlierPoint.isWithin(interval)); + } + + @Test + public void testIsWithinReturnsFalseForTimeIntervalThatDoesntContainIt() { + ITimeInterval interval = TimeIntervals.fromTimePoints(earlierPoint, + laterPoint); + + assertFalse( + "The time point should have returned false for being within the interval", + new TimePoint(earlierPoint.asMilliseconds() - 1L) + .isWithin(interval)); + } + + @Test + public void testEqualsAndHashcodeContract() { + List equalObjects = Arrays.asList(sameAsEarlierPoint); + List unequalObjects = Arrays.asList(laterPoint, + TimePoints.now()); + + TestUtil.assertEqualsAndHashcodeContract(earlierPoint, equalObjects, + unequalObjects); + } +} diff --git a/tests/unit/com/raytheon/uf/common/time/domain/TimePointsTest.java b/tests/unit/com/raytheon/uf/common/time/domain/TimePointsTest.java new file mode 100644 index 0000000000..86b72b8036 --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/time/domain/TimePointsTest.java @@ -0,0 +1,70 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.common.time.util.TimeUtilTest; + +/** + * Test {@link TimePoints}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public class TimePointsTest { + + @Before + public void setUp() { + TimeUtilTest.freezeTime(); + } + + @After + public void tearDown() { + TimeUtilTest.resumeTime(); + } + + @Test + public void testNowReturnsCurrentTime() { + long expectedTime = TimeUtil.currentTimeMillis(); + + assertThat(TimePoints.now(), + is(equalTo(TimePoints.fromMillis(expectedTime)))); + } + +} diff --git a/tests/unit/com/raytheon/uf/common/time/domain/UsesDuration.java b/tests/unit/com/raytheon/uf/common/time/domain/UsesDuration.java new file mode 100644 index 0000000000..c2e6df58db --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/time/domain/UsesDuration.java @@ -0,0 +1,75 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.junit.Ignore; + +import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; +import com.raytheon.uf.common.time.domain.api.IDuration; + +/** + * Uses an {@link IDuration}. Used by {@link DurationTest} to verify Jaxb + * interoperability. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 11, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@Ignore +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +@DynamicSerialize +public class UsesDuration { + + @DynamicSerializeElement + @XmlElement + private IDuration duration; + + /** + * @return the duration + */ + public IDuration getDuration() { + return duration; + } + + /** + * @param duration + * the duration to set + */ + public void setDuration(IDuration duration) { + this.duration = duration; + } + +} diff --git a/tests/unit/com/raytheon/uf/common/time/domain/UsesTimeInterval.java b/tests/unit/com/raytheon/uf/common/time/domain/UsesTimeInterval.java new file mode 100644 index 0000000000..c381fc9a6c --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/time/domain/UsesTimeInterval.java @@ -0,0 +1,75 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.junit.Ignore; + +import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; +import com.raytheon.uf.common.time.domain.api.ITimeInterval; + +/** + * Uses an {@link ITimeInterval}. Used by {@link TimeIntervalTest} to verify + * Jaxb interoperability. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 11, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@Ignore +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +@DynamicSerialize +public class UsesTimeInterval { + + @DynamicSerializeElement + @XmlElement + private ITimeInterval timeInterval; + + /** + * @return the timeInterval + */ + public ITimeInterval getTimeInterval() { + return timeInterval; + } + + /** + * @param timeInterval + * the timeInterval to set + */ + public void setTimeInterval(ITimeInterval timeInterval) { + this.timeInterval = timeInterval; + } + +} diff --git a/tests/unit/com/raytheon/uf/common/time/domain/UsesTimePoint.java b/tests/unit/com/raytheon/uf/common/time/domain/UsesTimePoint.java new file mode 100644 index 0000000000..1dd572c5da --- /dev/null +++ b/tests/unit/com/raytheon/uf/common/time/domain/UsesTimePoint.java @@ -0,0 +1,75 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.common.time.domain; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.junit.Ignore; + +import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; +import com.raytheon.uf.common.time.domain.api.ITimePoint; + +/** + * Uses an {@link ITimePoint}. Used by {@link TimePointTest} to verify Jaxb + * interoperability. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 11, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@Ignore +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +@DynamicSerialize +public class UsesTimePoint { + + @DynamicSerializeElement + @XmlElement + private ITimePoint timePoint; + + /** + * @return the timePoint + */ + public ITimePoint getTimePoint() { + return timePoint; + } + + /** + * @param timePoint + * the timePoint to set + */ + public void setTimePoint(ITimePoint timePoint) { + this.timePoint = timePoint; + } + +} diff --git a/tests/unit/com/raytheon/uf/edex/datadelivery/harvester/CrawlerTest.java b/tests/unit/com/raytheon/uf/edex/datadelivery/harvester/CrawlerTest.java index 71e70de688..0308ecacc6 100644 --- a/tests/unit/com/raytheon/uf/edex/datadelivery/harvester/CrawlerTest.java +++ b/tests/unit/com/raytheon/uf/edex/datadelivery/harvester/CrawlerTest.java @@ -22,6 +22,7 @@ package com.raytheon.uf.edex.datadelivery.harvester; import static org.junit.Assert.assertEquals; import java.util.List; +import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Before; @@ -30,6 +31,7 @@ import org.junit.Test; import org.mockito.Mockito; import com.raytheon.uf.common.localization.PathManagerFactoryTest; +import com.raytheon.uf.common.time.domain.Durations; import com.raytheon.uf.common.time.util.TimeUtil; import com.raytheon.uf.common.time.util.TimeUtilTest; import com.raytheon.uf.edex.datadelivery.harvester.config.HarvesterConfig; @@ -105,7 +107,8 @@ public class CrawlerTest { TimeUtilTest.freezeTime(time); HarvesterConfig harvesterConfig = HarvesterConfigFixture.INSTANCE.get(); - harvesterConfig.getProvider().setPostedFileDelay("3 DAYS"); + harvesterConfig.getProvider().setPostedFileDelay( + Durations.of(3, TimeUnit.DAYS)); MainSequenceCrawler crawler = new MainSequenceCrawler(harvesterConfig, mockCommunicationStrategy); List modelCrawlConfigs = crawler @@ -129,7 +132,7 @@ public class CrawlerTest { TimeUtilTest.freezeTime(time); HarvesterConfig harvesterConfig = HarvesterConfigFixture.INSTANCE.get(); - harvesterConfig.getProvider().setPostedFileDelay("2 MILLISECONDS"); + harvesterConfig.getProvider().setPostedFileDelay(Durations.of(2, TimeUnit.MILLISECONDS)); MainSequenceCrawler crawler = new MainSequenceCrawler(harvesterConfig, mockCommunicationStrategy); List modelCrawlConfigs = crawler diff --git a/tests/unit/com/raytheon/uf/edex/plugin/nwsauth/FileManagerTest.java b/tests/unit/com/raytheon/uf/edex/plugin/nwsauth/FileManagerTest.java new file mode 100644 index 0000000000..820336d9f7 --- /dev/null +++ b/tests/unit/com/raytheon/uf/edex/plugin/nwsauth/FileManagerTest.java @@ -0,0 +1,156 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.plugin.nwsauth; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Map; + +import javax.xml.bind.JAXBException; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.raytheon.uf.common.localization.IPathManager; +import com.raytheon.uf.common.localization.LocalizationContext; +import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel; +import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType; +import com.raytheon.uf.common.localization.LocalizationFile; +import com.raytheon.uf.common.localization.PathManagerFactory; +import com.raytheon.uf.common.localization.PathManagerFactoryTest; +import com.raytheon.uf.common.localization.exception.LocalizationException; +import com.raytheon.uf.common.plugin.nwsauth.xml.NwsRoleData; +import com.raytheon.uf.common.plugin.nwsauth.xml.UserXML; +import com.raytheon.uf.common.serialization.JAXBManager; +import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.common.time.util.TimeUtilTest; + +/** + * Test {@link FileManager}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 17, 2013 1412       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public class FileManagerTest { + private static JAXBManager jaxbManager; + + private final UserXML someUser = new UserXML("someUser"); + + private FileManager manager; + + @BeforeClass + public static void classSetup() throws JAXBException { + jaxbManager = new JAXBManager(NwsRoleData.class); + } + + @Before + public void setUp() { + TimeUtilTest.freezeTime(); + PathManagerFactoryTest.initLocalization(); + manager = new FileManager(); + } + + @After + public void tearDown() { + TimeUtilTest.resumeTime(); + } + + @Test + public void fileNewerOnDiskIsReadBeforeResponse() + throws LocalizationException { + + addUserToUserAdminFile(); + + verifyUserIsFoundWhenRoleDataRetrieved(); + } + + @Test + public void fileOlderOnDiskIsNotReadBeforeResponse() + throws LocalizationException { + + addUserToUserAdminFile(); + setUserAdminFileModifiedTimeToOneSecondAgo(); + + verifyUserIsNotFoundWhenRoleDataRetrieved(); + } + + private void verifyUserIsFoundWhenRoleDataRetrieved() { + final Map roleDataMap = manager.getRoleDataMap(); + assertTrue( + "Did not find the user added to the role data map!", + roleDataMap.get("TestUserRoles").getUserList() + .contains(someUser)); + } + + /** + * @param someUser + */ + private void verifyUserIsNotFoundWhenRoleDataRetrieved() { + final Map roleDataMap = manager.getRoleDataMap(); + assertFalse( + "Should not have found the user added to the role data map!", + roleDataMap.get("TestUserRoles").getUserList() + .contains(someUser)); + + } + + private void addUserToUserAdminFile() throws LocalizationException { + final LocalizationFile file = getTestUserAdminRolesLocalizationFile(); + NwsRoleData roleData = file.jaxbUnmarshal(NwsRoleData.class, + jaxbManager); + + roleData.getUserList().add(someUser); + file.jaxbMarshal(roleData, jaxbManager); + file.save(); + // The file was written out 1 second after we last read it + file.getFile().setLastModified( + TimeUtil.currentTimeMillis() + TimeUtil.MILLIS_PER_SECOND); + } + + private void setUserAdminFileModifiedTimeToOneSecondAgo() { + // The file was written out 1 second before we last read it + getTestUserAdminRolesLocalizationFile().getFile().setLastModified( + TimeUtil.currentTimeMillis() - TimeUtil.MILLIS_PER_SECOND); + } + + private LocalizationFile getTestUserAdminRolesLocalizationFile() { + IPathManager pathManager = PathManagerFactory.getPathManager(); + final LocalizationFile file = pathManager.getLocalizationFile( + new LocalizationContext(LocalizationType.COMMON_STATIC, + LocalizationLevel.SITE, "OAX"), + "roles/testUserAdminRoles.xml"); + return file; + } + +} diff --git a/tests/unit/com/raytheon/uf/edex/stats/AggregateManagerTest.java b/tests/unit/com/raytheon/uf/edex/stats/AggregateManagerTest.java new file mode 100644 index 0000000000..5590fa147e --- /dev/null +++ b/tests/unit/com/raytheon/uf/edex/stats/AggregateManagerTest.java @@ -0,0 +1,116 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.stats; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.JAXBException; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.common.collect.Maps; +import com.raytheon.uf.common.localization.IPathManager; +import com.raytheon.uf.common.localization.LocalizationContext; +import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel; +import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType; +import com.raytheon.uf.common.localization.LocalizationFile; +import com.raytheon.uf.common.localization.PathManagerFactory; +import com.raytheon.uf.common.localization.PathManagerFactoryTest; +import com.raytheon.uf.common.serialization.JAXBManager; +import com.raytheon.uf.common.stats.StatsGrouping; +import com.raytheon.uf.common.stats.StatsGroupingColumn; +import com.raytheon.uf.common.stats.xml.StatisticsConfig; +import com.raytheon.uf.common.stats.xml.StatisticsEvent; +import com.raytheon.uf.common.util.FileUtil; +import com.raytheon.uf.edex.stats.util.ConfigLoader; + +/** + * Test {@link AggregateManager}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 15, 2013 1487       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public class AggregateManagerTest { + private static JAXBManager jaxbManager; + + @BeforeClass + public static void classSetUp() throws JAXBException { + jaxbManager = new JAXBManager(StatisticsConfig.class, + StatsGroupingColumn.class); + } + + @Before + public void setUp() { + PathManagerFactoryTest.initLocalization(); + } + + @Test + public void testDeterminingGroupForEvent() throws Exception { + IPathManager pm = PathManagerFactory.getPathManager(); + final LocalizationFile lf = pm.getLocalizationFile( + new LocalizationContext(LocalizationType.EDEX_STATIC, + LocalizationLevel.BASE), FileUtil.join("stats", + "mockStats.xml")); + + final StatisticsConfig statisticsConfig = lf.jaxbUnmarshal( + StatisticsConfig.class, jaxbManager); + + ConfigLoader.validate(Maps. newHashMap(), + statisticsConfig); + + MockEvent mockEvent = new MockEvent(); + mockEvent.setPluginName("somePlugin"); + mockEvent.setFileName("someFileName"); + mockEvent.setProcessingTime(1000L); + mockEvent.setProcessingLatency(500L); + + List groupList = new ArrayList(); + groupList.add(new StatsGrouping("pluginName", "somePlugin")); + groupList.add(new StatsGrouping("fileName", "someFileName")); + StatsGroupingColumn column = new StatsGroupingColumn(); + column.setGroup(groupList); + + final String expectedGroupRepresentation = jaxbManager + .marshalToXml(column); + final String actualGroupRepresentation = AggregateManager.determineGroupRepresentationForEvent( + statisticsConfig.getEvents().iterator().next(), mockEvent); + assertThat(actualGroupRepresentation, + is(equalTo(expectedGroupRepresentation))); + } + +} diff --git a/tests/unit/com/raytheon/uf/edex/stats/MockEvent.java b/tests/unit/com/raytheon/uf/edex/stats/MockEvent.java new file mode 100644 index 0000000000..419ed5be0f --- /dev/null +++ b/tests/unit/com/raytheon/uf/edex/stats/MockEvent.java @@ -0,0 +1,169 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.edex.stats; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; +import com.raytheon.uf.common.stats.ProcessEvent; +import com.raytheon.uf.common.stats.StatisticsEvent; + +/** + * Mock event based from {@link ProcessEvent}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 15, 2013 1487       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@DynamicSerialize +public class MockEvent extends StatisticsEvent { + + private static final long serialVersionUID = 1L; + + private static final Map FIELD_UNIT_MAP; + static { + Map m = new HashMap(); + m.put("processingLatency", "ms"); + m.put("processingTime", "ms"); + FIELD_UNIT_MAP = Collections.unmodifiableMap(m); + } + + @DynamicSerializeElement + private String message; + + @DynamicSerializeElement + private String pluginName; + + @DynamicSerializeElement + private String fileName; + + /* + * Processing time in milliseconds + */ + @DynamicSerializeElement + private long processingTime; + + /* + * Processing latency in milliseconds + */ + @DynamicSerializeElement + private long processingLatency; + + public MockEvent() { + } + + @Override + protected Map getFieldUnitMap() { + return FIELD_UNIT_MAP; + } + + /** + * @return the fileName + */ + public String getFileName() { + return fileName; + } + + /** + * @return the message + */ + public String getMessage() { + return message; + } + + /** + * @return the pluginName + */ + public String getPluginName() { + return pluginName; + } + + /** + * @return the processingLatency in milliseconds + */ + public long getProcessingLatency() { + return processingLatency; + } + + /** + * @return the processingTime in milliseconds + */ + public long getProcessingTime() { + return processingTime; + } + + /** + * @param fileName + * the fileName to set + */ + public void setFileName(String fileName) { + this.fileName = fileName; + } + + /** + * @param message + * the message to set + */ + public void setMessage(String message) { + this.message = message; + } + + /** + * @param pluginName + * the pluginName to set + */ + public void setPluginName(String pluginName) { + this.pluginName = pluginName; + } + + /** + * @param processingLatency + * the processingLatency in milliseconds to set + */ + public void setProcessingLatency(long processingLatency) { + this.processingLatency = processingLatency; + } + + /** + * @param processingTime + * the processingTime in milliseconds to set + */ + public void setProcessingTime(long processingTime) { + this.processingTime = processingTime; + } + + @Override + public String toString() { + return super.toString() + " : " + getMessage(); + } + +} \ No newline at end of file diff --git a/tests/unit/com/raytheon/uf/edex/stats/data/StatsDataAccumulatorTest.java b/tests/unit/com/raytheon/uf/edex/stats/data/StatsDataAccumulatorTest.java index 4e6288206e..b07a538238 100644 --- a/tests/unit/com/raytheon/uf/edex/stats/data/StatsDataAccumulatorTest.java +++ b/tests/unit/com/raytheon/uf/edex/stats/data/StatsDataAccumulatorTest.java @@ -1,47 +1,92 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ package com.raytheon.uf.edex.stats.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.ArrayList; -import java.util.Calendar; +import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; -import java.util.TimeZone; + +import javax.xml.bind.JAXBException; import org.junit.Test; +import com.google.common.collect.Maps; +import com.raytheon.uf.common.datadelivery.event.retrieval.DataRetrievalEvent; +import com.raytheon.uf.common.datadelivery.event.retrieval.SubscriptionRetrievalEvent; +import com.raytheon.uf.common.serialization.JAXBManager; import com.raytheon.uf.common.stats.AggregateRecord; +import com.raytheon.uf.common.stats.StatsGrouping; +import com.raytheon.uf.common.stats.StatsGroupingColumn; +import com.raytheon.uf.common.stats.data.StatsData; import com.raytheon.uf.common.stats.util.UnitUtils; import com.raytheon.uf.common.time.TimeRange; +import com.raytheon.uf.common.time.util.TimeUtil; +/** + * + * Test {@link StatsDataAccumulator}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 15, 2013 1487       djohnson     Use XML for grouping column.
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ public class StatsDataAccumulatorTest { + private static final JAXBManager JAXB_MANAGER; + static { + try { + JAXB_MANAGER = new JAXBManager(StatsGroupingColumn.class); + } catch (JAXBException e) { + throw new ExceptionInInitializerError(e); + } + } + @Test public void testCalculateBinsCalculatesCorrectly() { - Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT")); - c.set(Calendar.MILLISECOND, 0); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MINUTE, 0); - c.set(Calendar.HOUR_OF_DAY, 0); - c.set(Calendar.DAY_OF_MONTH, 1); - c.set(Calendar.MONTH, 0); - long start = c.getTimeInMillis(); - - c.add(Calendar.DAY_OF_MONTH, 1); - long end = c.getTimeInMillis(); - - TimeRange tr = new TimeRange(start, end); + TimeRange tr = new TimeRange(0L, TimeUtil.MILLIS_PER_DAY); StatsDataAccumulator acc = new StatsDataAccumulator(); acc.setTimeRange(tr); acc.setTimeStep(5); acc.calculateBins(); - int expectedBinCount = 288; // 5 minute bins 12 per hour, * 24 + int expectedBinCount = 288; // 5 minute bins 12 per hour, * 24 int actualBinCount = acc.bins.keySet().size(); - assertEquals("Bin Counts do not match", expectedBinCount, actualBinCount); + assertEquals("Bin Counts do not match", expectedBinCount, + actualBinCount); int count = 0; for (long bin : acc.bins.keySet()) { @@ -51,7 +96,7 @@ public class StatsDataAccumulatorTest { } @Test - public void testSetupGroupings() { + public void testSetupGroupings() throws JAXBException { List recordList = getTestRecords(); StatsDataAccumulator acc = new StatsDataAccumulator(); acc.setRecords(recordList.toArray(new AggregateRecord[recordList.size()])); @@ -62,33 +107,39 @@ public class StatsDataAccumulatorTest { expectedGroups.add("provider"); expectedGroups.add("plugin"); - List expectedGroupMembers = new ArrayList(); - expectedGroupMembers.add("nomads"); - expectedGroupMembers.add("madis"); - expectedGroupMembers.add("owner0"); - expectedGroupMembers.add("owner1"); - expectedGroupMembers.add("owner2"); - expectedGroupMembers.add("owner3"); - expectedGroupMembers.add("owner4"); - expectedGroupMembers.add("grid"); + List expectedPlugins = Arrays.asList("grid"); + List expectedProviders = Arrays.asList("nomads", "madis"); + List expectedOwners = Arrays.asList("owner0", "owner1", + "owner2", "owner3", "owner4"); + Map> expectedGroupsToValues = Maps.newHashMap(); + expectedGroupsToValues.put("provider", expectedProviders); + expectedGroupsToValues.put("plugin", expectedPlugins); + expectedGroupsToValues.put("owner", expectedOwners); // Check the groups - for (String group : acc.groups) { - assertTrue(expectedGroups.contains(group)); + for (String expected : expectedGroups) { + assertTrue("Did not find group [" + expected + + "] in the group collection!", + acc.groups.contains(expected)); } // Check the group members - for (String key: acc.groupMemberMap.keySet()) { - for (String member: acc.groupMemberMap.get(key)) { - assertTrue(expectedGroupMembers.contains(member)); + final Map> groupMemberMap = acc.groupMemberMap; + for (Entry> entry : expectedGroupsToValues + .entrySet()) { + final String groupName = entry.getKey(); + final Set setToCheck = groupMemberMap.get(groupName); + for (String member : entry.getValue()) { + assertTrue("Did not find entry [" + member + "] for group [" + + groupName + "]!", setToCheck.contains(member)); } } } @Test - public void testCreateStatsDataMapCreation() { - String eventType = "com.raytheon.uf.common.datadelivery.event.retrieval.DataRetrievalEvent"; + public void testCreateStatsDataMapCreation() throws JAXBException { + String eventType = DataRetrievalEvent.class.getName(); String dataType = "bytes"; String displayUnit = "MB"; @@ -102,7 +153,7 @@ public class StatsDataAccumulatorTest { acc.setDataType(dataType); acc.setupGroupings(); - acc.createStatsDataMap(unitUtils, acc.groups); + acc.createStatsDataMap(acc.groups); Set expectedSet = new HashSet(); expectedSet.add("owner0:nomads"); @@ -116,54 +167,54 @@ public class StatsDataAccumulatorTest { expectedSet.add("owner3:madis"); expectedSet.add("owner4:madis"); - for (String key : acc.statsDataMap.keySet()) { - assertTrue(expectedSet.contains(key)); + final Map statsDataMap = acc.statsDataMap; + for (String expected : expectedSet) { + assertTrue("Did not find expected value (" + expected + + "] as key in the statsDataMap!", + statsDataMap.containsKey(expected)); } } // Build the Aggregate records - private List getTestRecords() { + private List getTestRecords() throws JAXBException { String plugin = "plugin"; String provider = "provider"; String nomads = "nomads"; String madis = "madis"; String owner = "owner"; String grid = "grid"; - String dash = "-"; - String colon = ":"; - List groupings = new ArrayList(); - for (int i = 0; i < 5; i++) { - groupings.add(plugin + colon + grid + dash + owner + colon + owner + i); + List groupingColumns = new ArrayList(); + for (int i = 0; i < 15; i++) { + groupingColumns.add(StatsGroupingColumn.withGroupings( + new StatsGrouping(plugin, grid), new StatsGrouping(owner, + owner + i))); } for (int i = 0; i < 5; i++) { - groupings.add(plugin + colon + grid + dash + owner + colon + owner + i); + groupingColumns.add(StatsGroupingColumn.withGroupings( + new StatsGrouping(provider, nomads), new StatsGrouping( + owner, owner + i))); } for (int i = 0; i < 5; i++) { - groupings.add(plugin + colon + grid + dash + owner + colon + owner + i); - } - - for (int i = 0; i < 5; i++) { - groupings.add(provider + colon + nomads + dash + owner + colon + owner + i); - } - for (int i = 0; i < 5; i++) { - groupings.add(provider + colon + madis + dash + owner + colon + owner + i); + groupingColumns.add(StatsGroupingColumn.withGroupings( + new StatsGrouping(provider, madis), new StatsGrouping( + owner, owner + i))); } List records = new ArrayList(); - for (String group : groupings) { + for (StatsGroupingColumn group : groupingColumns) { AggregateRecord r = new AggregateRecord(); - if (group.contains("provider")) { - r.setEventType("com.raytheon.uf.common.datadelivery.event.retrieval.DataRetrievalEvent"); + if ("provider".equals(group.getGroup().iterator().next().getName())) { + r.setEventType(DataRetrievalEvent.class.getName()); r.setField("bytes"); } else { - r.setEventType("com.raytheon.uf.common.datadelivery.event.retrieval.SubscriptionRetrievalEvent"); + r.setEventType(SubscriptionRetrievalEvent.class.getName()); r.setField("numRecords"); } - r.setGrouping(group); + r.setGrouping(JAXB_MANAGER.marshalToXml(group)); records.add(r); } diff --git a/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/AbstractSubscriptionServiceTest.java b/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/AbstractSubscriptionServiceTest.java index ed367b5755..3fbbbd6c89 100644 --- a/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/AbstractSubscriptionServiceTest.java +++ b/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/AbstractSubscriptionServiceTest.java @@ -48,6 +48,7 @@ import com.raytheon.uf.common.datadelivery.registry.Subscription; import com.raytheon.uf.common.datadelivery.registry.SubscriptionFixture; import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers; import com.raytheon.uf.common.datadelivery.registry.handlers.ISubscriptionHandler; +import com.raytheon.uf.common.datadelivery.service.ISubscriptionNotificationService; import com.raytheon.uf.common.registry.handler.RegistryHandlerException; import com.raytheon.uf.common.registry.handler.RegistryObjectHandlersUtil; import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionService.ISubscriptionServiceResult; diff --git a/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/LatencyRuleXMLTest.java b/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/LatencyRuleXMLTest.java new file mode 100644 index 0000000000..2ac91180a3 --- /dev/null +++ b/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/LatencyRuleXMLTest.java @@ -0,0 +1,86 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.datadelivery.subscription.xml; + +import javax.xml.bind.JAXBException; + +import org.junit.Test; + +import com.raytheon.uf.common.datadelivery.registry.SubscriptionFixture; +import com.raytheon.uf.common.units.DataSizeUnit; +import com.raytheon.uf.common.util.CollectionUtil; +import com.raytheon.uf.viz.datadelivery.system.CreateEditRuleDlg.FreqUnitOptions; +import com.raytheon.uf.viz.datadelivery.system.OperatorTypes; +import com.raytheon.uf.viz.datadelivery.system.OpsNetFieldNames; + +/** + * Test {@link LatencyRulesXML}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * Jan 17, 2013 1357       mpduff       DataSizeUnits was moved.
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ + +public class LatencyRuleXMLTest { + + /** + * Rule data size units were being written out as "Byte" but expected to be + * BYTE when running matches. + * + * @throws JAXBException + */ + @Test + public void testDataSizeUnitCanBeUsedInMatches() throws JAXBException { + LatencyRuleXML ruleXml = new LatencyRuleXML(); + ruleXml.setLatency(10); + ruleXml.setRuleField(OpsNetFieldNames.SIZE.toString()); + ruleXml.setRuleName("ruleName"); + ruleXml.setRuleOperator(OperatorTypes.GREATER_THAN); + ruleXml.setRuleUnit(DataSizeUnit.BYTE.getUnit()); + ruleXml.setRuleValue("10"); + + ruleXml.matches(SubscriptionFixture.INSTANCE.get(), + CollectionUtil.asSet(1, 2)); + } + + @Test + public void testFrequencyUnitCanBeUsedInMatches() throws JAXBException { + LatencyRuleXML ruleXml = new LatencyRuleXML(); + ruleXml.setLatency(10); + ruleXml.setRuleField(OpsNetFieldNames.FREQUENCY.toString()); + ruleXml.setRuleName("ruleName"); + ruleXml.setRuleOperator(OperatorTypes.GREATER_THAN); + ruleXml.setRuleUnit(FreqUnitOptions.MIN.getOperation()); + ruleXml.setRuleValue("10"); + + ruleXml.matches(SubscriptionFixture.INSTANCE.get(), + CollectionUtil.asSet(1, 2)); + } +} diff --git a/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/OperatorAdapterTest.java b/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/OperatorAdapterTest.java new file mode 100644 index 0000000000..fe4ca85486 --- /dev/null +++ b/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/OperatorAdapterTest.java @@ -0,0 +1,75 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.datadelivery.subscription.xml; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +import com.raytheon.uf.viz.datadelivery.system.Operator; +import com.raytheon.uf.viz.datadelivery.system.OperatorTypes; +import com.raytheon.uf.viz.datadelivery.utils.NameOperationItems; +import com.raytheon.uf.viz.datadelivery.utils.TypeOperationItems; + +/** + * Test {@link OperatorAdapter}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +@SuppressWarnings({ "rawtypes" }) +public class OperatorAdapterTest { + + @Test + public void testMarshalUnmarshalOperatorNameOperationItems() { + verifyOperatorsUnmarshalAsSameOperator(NameOperationItems.values()); + } + + @Test + public void testMarshalUnmarshalOperatorOperatorTypes() { + verifyOperatorsUnmarshalAsSameOperator(OperatorTypes.values()); + } + + @Test + public void testMarshalUnmarshalOperatorTypeOperationItems() { + verifyOperatorsUnmarshalAsSameOperator(TypeOperationItems.values()); + } + + private void verifyOperatorsUnmarshalAsSameOperator(Operator... operators) { + for (Operator operator : operators) { + Operator expected = OperatorAdapter.fromString(OperatorAdapter + .toString(operator)); + assertThat(operator, is(sameInstance(expected))); + } + } + +} diff --git a/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/RuleXMLTest.java b/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/RuleXMLTest.java index 84a566c9c0..d219a1cbe2 100644 --- a/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/RuleXMLTest.java +++ b/tests/unit/com/raytheon/uf/viz/datadelivery/subscription/xml/RuleXMLTest.java @@ -30,10 +30,11 @@ import org.junit.Test; import com.raytheon.uf.common.datadelivery.registry.DataType; import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.units.DataSizeUnit; import com.raytheon.uf.viz.datadelivery.system.CreateEditRuleDlg.FreqUnitOptions; +import com.raytheon.uf.viz.datadelivery.system.Operator; import com.raytheon.uf.viz.datadelivery.system.OperatorTypes; import com.raytheon.uf.viz.datadelivery.system.OpsNetFieldNames; -import com.raytheon.uf.viz.datadelivery.utils.DataSizeUnit; import com.raytheon.uf.viz.datadelivery.utils.NameOperationItems; import com.raytheon.uf.viz.datadelivery.utils.TypeOperationItems; @@ -46,7 +47,9 @@ import com.raytheon.uf.viz.datadelivery.utils.TypeOperationItems; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Jan 3, 2013 1420 mpduff Initial creation. + * Jan 03, 2013 1420 mpduff Initial creation. + * Jan 14, 2013 1286 djohnson Use the rule operator as an {@link Operator}. + * Jan 17, 2013 1357 mpduff DataSizeUnits was moved. * * * @@ -70,7 +73,7 @@ public class RuleXMLTest { LatencyRuleXML rule = new LatencyRuleXML(); rule.setRuleValue("GFS"); rule.setRuleField(OpsNetFieldNames.NAME.getFieldName()); - rule.setRuleOperator(NameOperationItems.LIKE.getOperation()); + rule.setRuleOperator(NameOperationItems.LIKE); assertTrue("Matches Data Set Name failed", rule.matches(sub, null)); } @@ -80,7 +83,7 @@ public class RuleXMLTest { LatencyRuleXML rule = new LatencyRuleXML(); rule.setRuleValue("GFS2"); rule.setRuleField(OpsNetFieldNames.NAME.getFieldName()); - rule.setRuleOperator(NameOperationItems.LIKE.getOperation()); + rule.setRuleOperator(NameOperationItems.LIKE); assertFalse("Matches Data Set Name false positive", rule.matches(sub, null)); @@ -91,7 +94,7 @@ public class RuleXMLTest { LatencyRuleXML rule = new LatencyRuleXML(); rule.setRuleValue("GRID,OBS"); rule.setRuleField(OpsNetFieldNames.TYPE.getFieldName()); - rule.setRuleOperator(TypeOperationItems.IN.getOperation()); + rule.setRuleOperator(TypeOperationItems.IN); assertTrue("Matches Data Type In Failed", rule.matches(sub, null)); } @@ -101,7 +104,7 @@ public class RuleXMLTest { LatencyRuleXML rule = new LatencyRuleXML(); rule.setRuleValue("FAKE"); rule.setRuleField(OpsNetFieldNames.TYPE.getFieldName()); - rule.setRuleOperator(TypeOperationItems.NOT_IN.getOperation()); + rule.setRuleOperator(TypeOperationItems.NOT_IN); assertTrue("Matches Data Type Not In Failed", rule.matches(sub, null)); } @@ -111,7 +114,7 @@ public class RuleXMLTest { LatencyRuleXML rule = new LatencyRuleXML(); rule.setRuleValue(String.valueOf(100)); rule.setRuleField(OpsNetFieldNames.SIZE.getFieldName()); - rule.setRuleOperator(OperatorTypes.EQUAL.getOperation()); + rule.setRuleOperator(OperatorTypes.EQUAL); rule.setRuleUnit(DataSizeUnit.KB.getUnit()); assertTrue("Matches Dataset Size Equals Failed", @@ -123,7 +126,7 @@ public class RuleXMLTest { LatencyRuleXML rule = new LatencyRuleXML(); rule.setRuleValue(String.valueOf(100)); rule.setRuleField(OpsNetFieldNames.SIZE.getFieldName()); - rule.setRuleOperator(OperatorTypes.EQUAL.getOperation()); + rule.setRuleOperator(OperatorTypes.EQUAL); rule.setRuleUnit(DataSizeUnit.MB.getUnit()); sub.setDataSetSize(1024 * 100); @@ -136,7 +139,7 @@ public class RuleXMLTest { LatencyRuleXML rule = new LatencyRuleXML(); rule.setRuleValue(String.valueOf(100)); rule.setRuleField(OpsNetFieldNames.SIZE.getFieldName()); - rule.setRuleOperator(OperatorTypes.EQUAL.getOperation()); + rule.setRuleOperator(OperatorTypes.EQUAL); rule.setRuleUnit(DataSizeUnit.GB.getUnit()); sub.setDataSetSize(100 * 1024 * 1024); @@ -151,7 +154,7 @@ public class RuleXMLTest { LatencyRuleXML rule = new LatencyRuleXML(); rule.setRuleValue(String.valueOf(60)); rule.setRuleField(OpsNetFieldNames.FREQUENCY.getFieldName()); - rule.setRuleOperator(OperatorTypes.EQUAL.getOperation()); + rule.setRuleOperator(OperatorTypes.EQUAL); rule.setRuleUnit(FreqUnitOptions.MIN.getOperation()); Set cycles = new TreeSet(); @@ -167,7 +170,7 @@ public class RuleXMLTest { LatencyRuleXML rule = new LatencyRuleXML(); rule.setRuleValue(String.valueOf(1)); rule.setRuleField("Dataset Frequency"); - rule.setRuleOperator(OperatorTypes.EQUAL.getOperation()); + rule.setRuleOperator(OperatorTypes.EQUAL); rule.setRuleUnit(FreqUnitOptions.HOURS.getOperation()); Set cycles = new TreeSet(); diff --git a/tests/unit/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryUtilsTest.java b/tests/unit/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryUtilsTest.java new file mode 100644 index 0000000000..afb47cae91 --- /dev/null +++ b/tests/unit/com/raytheon/uf/viz/datadelivery/utils/DataDeliveryUtilsTest.java @@ -0,0 +1,119 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.datadelivery.utils; + +import static com.google.common.collect.Lists.newArrayList; +import static com.google.common.collect.Sets.newHashSet; +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import com.raytheon.uf.common.datadelivery.registry.OpenDapGriddedDataSet; +import com.raytheon.uf.common.datadelivery.registry.OpenDapGriddedDataSetFixture; +import com.raytheon.uf.common.datadelivery.registry.Subscription; +import com.raytheon.uf.common.datadelivery.registry.SubscriptionFixture; +import com.raytheon.uf.common.datadelivery.registry.Time; + +/** + * Test {@link DataDeliveryUtils}. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 14, 2013 1286       djohnson     Initial creation
+ * Jan 22, 2013 1519       djohnson     Add tests for getMaxLatency calculations.
+ * 
+ * 
+ * + * @author djohnson + * @version 1.0 + */ +public class DataDeliveryUtilsTest { + + // These constants are not using TimeUtil to make sure we get a + // "second opinion" when using TimeUtil in the code under test + private static final long THREE_HOURS_AS_MINUTES = TimeUnit.HOURS + .toMinutes(3); + + private static final long MINUTES_PER_DAY = TimeUnit.DAYS.toMinutes(1); + + @Test + public void maxLatencyReturnsMaxCyclicDifferenceForSubscribedToCycles() { + List cycleTimes = newArrayList(); + cycleTimes.add(0); + cycleTimes.add(1); + cycleTimes.add(4); + + Subscription subscription = SubscriptionFixture.INSTANCE.get(); + Time subTime = subscription.getTime(); + subTime.setCycleTimes(cycleTimes); + + assertEquals(THREE_HOURS_AS_MINUTES, + DataDeliveryUtils.getMaxLatency(subscription)); + } + + @Test + public void maxLatencyDefaultsToOneDayForSubscriptionWithOneCycle() { + List cycleTimes = newArrayList(); + cycleTimes.add(0); + + Subscription subscription = SubscriptionFixture.INSTANCE.get(); + Time subTime = subscription.getTime(); + subTime.setCycleTimes(cycleTimes); + + assertEquals(MINUTES_PER_DAY, + DataDeliveryUtils.getMaxLatency(subscription)); + } + + @Test + public void maxLatencyForDataSetWithOneCycleDefaultsToOneDay() { + Set cycleTimes = newHashSet(); + cycleTimes.add(0); + + OpenDapGriddedDataSet dataset = OpenDapGriddedDataSetFixture.INSTANCE + .get(); + dataset.setCycles(cycleTimes); + + assertEquals(MINUTES_PER_DAY, DataDeliveryUtils.getMaxLatency(dataset)); + } + + @Test + public void maxLatencyForDataSetWithMultipleCyclesReturnsMaxCyclicDifference() { + Set cycleTimes = newHashSet(); + cycleTimes.add(0); + cycleTimes.add(1); + cycleTimes.add(4); + + OpenDapGriddedDataSet dataset = OpenDapGriddedDataSetFixture.INSTANCE + .get(); + dataset.setCycles(cycleTimes); + + assertEquals(THREE_HOURS_AS_MINUTES, + DataDeliveryUtils.getMaxLatency(dataset)); + } + +} diff --git a/tests/unit/com/raytheon/uf/viz/datadelivery/utils/DataSizeUtilTest.java b/tests/unit/com/raytheon/uf/viz/datadelivery/utils/DataSizeUtilTest.java index f246a52532..134298cb9d 100644 --- a/tests/unit/com/raytheon/uf/viz/datadelivery/utils/DataSizeUtilTest.java +++ b/tests/unit/com/raytheon/uf/viz/datadelivery/utils/DataSizeUtilTest.java @@ -25,6 +25,8 @@ import static org.junit.Assert.assertThat; import org.junit.Test; +import com.raytheon.uf.common.units.DataSizeUnit; + /** * Test {@link DataSizeUnit} * @@ -34,7 +36,8 @@ import org.junit.Test; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Jan 8, 2013 1420 mpduff Initial creation + * Jan 08, 2013 1420 mpduff Initial creation + * Jan 17, 2013 1357 mpduff DataSizeUnits was moved. * * * diff --git a/tests/unit/com/raytheon/uf/viz/stats/ui/SelectionEntryTest.java b/tests/unit/com/raytheon/uf/viz/stats/ui/SelectionEntryTest.java new file mode 100644 index 0000000000..d728231f3e --- /dev/null +++ b/tests/unit/com/raytheon/uf/viz/stats/ui/SelectionEntryTest.java @@ -0,0 +1,54 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.stats.ui; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * SelectionEntry test class. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 24, 2013            mpduff     Initial creation
+ * 
+ * 
+ * + * @author mpduff + * @version 1.0 + */ + +public class SelectionEntryTest { + + @Test + public void testCreateSelectionEntryClassAndAddKeys() { + SelectionEntry se = new SelectionEntry(); + se.addPair("Key", "Value"); + se.addPair("Key2", "Value2"); + se.addPair("Key3", "Value3"); + assertTrue("Keys are wrong", se.toString() + .equals("Value:Value2:Value3")); + } +} diff --git a/tests/utility/common_static/site/OAX/roles/testUserAdminRoles.xml b/tests/utility/common_static/site/OAX/roles/testUserAdminRoles.xml new file mode 100644 index 0000000000..5e02c0ca3d --- /dev/null +++ b/tests/utility/common_static/site/OAX/roles/testUserAdminRoles.xml @@ -0,0 +1,14 @@ + + + + TestUserRoles + + + This permission allows the user to access and edit AWIPS 2 User Administration + + + + + awips.user.admin + + \ No newline at end of file diff --git a/tests/utility/edex_static/base/stats/mockStats.xml b/tests/utility/edex_static/base/stats/mockStats.xml new file mode 100644 index 0000000000..3c9c5aef7a --- /dev/null +++ b/tests/utility/edex_static/base/stats/mockStats.xml @@ -0,0 +1,12 @@ + + + + + + + + +

YsZq(Mlan0|cQ4s6cpaq4`FPUc@gsSxE=qGmBP` z(|}`b{7mIZofHTX?&F(x{Pkomg9ujJ$k&=66|PAR1## zp3~)r>APvYVyR}c`xX@F2`fFY8TCR#%oHhefCaOJjDKjPLS|^p^a+n3JC4MfTTk@| zxHcr#y?;!R0{V~}1*G@DRV#M}t6-N*RE`55zF-4Y!&7p^OE30qC*i&oTS&{PEs^#I z5_QWndN+K#GYcGYlM1{-7KfO55@{ub0%2Y!^gyHeAH2*Vz4TEbO*qbYJd%`<0nU?F z>Nk$pw{Y2?FwVvL32G(actRXfGF)7+S0Lx#crHMSb$R%HFMNAUKhaINOXGnR-0Pa9 zr*2z}*>!`*fs?*DdH7r^OfXE|+pB5S{b@Os{iYLtTv1&U(?a-~v9dYZf8W`S%FP#r zYmlR2ukdYO94%-Xs+zBV!n?=?pR83UgqJy+)!@N=O&D;Vn6=OsyAc z-7&7V-_CGTF7YxzN3K~Q1iP(w{gN@vH3@8@UfT8+@8DvN5}{UP9Q?V(k!!q$0~e4& znB_D!-1RrgEj^FHTJr@2?JpqwH_H8QApG0l<-ZIb{)4r}#cePZvqEK+*$fX61uct6 zxSEE>AJq)v&enc~7>m{!@JM^wWtIg3>iwHnBE2KOxPgMbIU{4mx-;e3$@;R=>KnG+ zkRWW8wuRg9c12ihm^1Atw7n>$(lvOXMZv0pjZAK%fm&smoR=gRO$k;mikv|K?lYkY zR7E*2B!{gmM&N{7ep`DMJi?MVK8&?Q1&72brl1UTP!FhJ(G3VnpaK?8w%K>y2w`e) z#&Gi~{I@*jPL)12VL$~3FfhvkVxZev3S|4T*S0bFdlyd$ORe7w^JbB~PNDpsUfA0l z`Ap|qc{#PD_aN_aSj=$W09OdJblzhSwC=EX!@Ud;Ae@=iI1Qk$0V~*}aLebf{n4?I zeymla0lVlMzvM+06L9Ya~~-+K-CurkekQyOvr#HGUEF=BIkaF^b?mS0Yn9d%;if4x3XNcuMbk$tq9|HC2wVN!Ayv~obG4JyR%_D&<_+b8Zqpr?{8ncEaS!yvjF^ZanMgwpf5@*>D7nfT4bH!>l`{7 zMUZk)bukNx$0XmK~V?-~A6E(R_@3iH34~<%b>tOUBx!*bKNVMKK(qQYCn!rI^ zW!%;#?8b?7`>u!M;t9~Y)4wDNBlSVQlgXYNvD^#JcEtXa?H~@w**MP7L`&RJtF-Lz z%ri32iHhdVaN%)1jTO`GE>IvLgmaTkwY^3}`VXGPODRZc3mh z`rVuT%W!qubRT2+dncdwnfqnzFN^iziE4}6>2M*jYA?6?4_;nt>wEu|!1N}d1#vCt z!`uKXdGM&?uJJkV)Dk5F>+h>2GqZv^2$(R|A>~I7le51THC1)pUZF7Ff7E8_Z9`SK z0s*Cw&y@~1VW5=r%Y1TNDAeXNm?rg;yvM51#+Z7FToAF>dPmRe#hL-7$B31Mx+8ae zmi@l7h;9&fihQ8q3O<+*J_lG>&b=F0fJfCxBuW$)B*XCjjj&xLjK8~lVanl4Z1ML| zi2uOUzdT5R(wf!kS5XVA8!Sl+zloIDa`jN)_h7*zD>4tRY@k|yOic`3 zho|zZLO$U=@Qb{%u_d^ePdssA`=5*qCga1ia_`UQ=O28yRmA<#s5L}@&?yWAbx4FW z2?)W&D|lCgD0F{cBa=y{6qs4ZhhZjQyhsXst1 zC>*uvDW zAu^NnAs~TF=ZtcK)HrQ_b8R8B6bo>HO5m710pMokDCdnwSeNG|!o>D>;zZlHW>vQp z+c8RY1%98V>ca)QG!^G|F)lw!br&guv{#?wu5wM_a)Bu2;~FU9-46Tmbvy6hjzqc} z`OagntAoI)B&%UAGgp7B#!jiqmj{2PJ@sGT-4z1PmTp&DBVwJ*P z@+JO-Z^`e^PgnX&BaDIl(qs0UgRk_?9`Sbe{ynZ%Ax?4`9pg(3jL!EvCLqQq#Rs%s zPZu;+3fkgtjB)<>^IOr^N;ovM|LgDg-;Pr>sJ=QQtKxi0IkB~^WcWve2nbMohujd= z{n0pK8Y?mfZ$Xb$+y*+AdtQy<1nz7+o1zX#M=R?4dhP)gc-!LKu@x;PI~}V3%8hs-^~`goR|u4bCO(Wyz35CsyBG=TRQ6I z5oeL_XgEsD{SK6>Kr}Kx5fZcWCvZ?S4)QxpTTq>Zl|qv8cgevAG4}$O9wobL0_~)S zD2hOF0T^+TJP9NIBv7prC!_6q0JwNivwNJL)It9Hock9GxFh1eV{b*Rs{;F3A7CKV zDZe}$6}KAi(qnPW`yC&0Npq*n35$1W26q>Nosts6TOgRq5|cg;d$UpI>$-*d!``B@DO>T(6vdJ&p1VZ`F%+VvsSP`o_#F;q-u zN3P&~;@70z5dgpXP8_$?`O>bbz^p-mxORpkkZA{W9aW$^ROF;PSw=^@?eb*Q6?55! zuviSW8Cf!fHIpI)B85N@Aq+@}%oDsjJk0q=Yc!mU0DmgE?N-l>n{h3dGDm5Rtz#*B zp_5Zl1mJEK;d`7Lz(s4j?fxN1y&FEAh7RlDBz=h(HykvI;gt;lfz7V~46SH2xHB z1T$OfwjvbxVrdNxxu~HX3i#fts#Q_uhemoU`@@~}TH~{`&$}v*2K0%@bnIW3_U6>p z(WZB*wUd}`I$e5KYwa_mC(2n(#RCe7H=-+07+I#sP}>lNJ;$hWN-{ zCEO2al@*t8q8%&3$m1F62%WY~zbCch&aI?4D=s)8bV8L<_ZlllBi6M6adl=SnL%ds{e0vc>vR#^L7nP~)%AS#+ zG%y@?EQ;5_6Io$$P5gPN1gnPTW$$=f^rVSVcIr0pBhIC+coZg=Ic6c(^xaCD%)?R$S*}&nRH}^u0bT%ZYyPnPfYp8^RJqj^&8_N)iP_!W4NshB*R|+@w%Y0bW_^EU zVuO|Q@3rSc%0zjOQxZR0X+GztU50JMhlS%JdX4YrPLjToX=YtwJ4r7vDLZ4w8h}s| zr+Jo(TL+6cDJV4MCf7yo;91uM z=z)CX>T}P(7>tb=!OjU^jr(Dsl`CH}(VPJ+2avi~^`l&^*?c0#4_5N6OF^ty* zm57yNB{0kjmuFr{F~a4ti~PXS_E_t!q4u0;_R+VjP@^ES7{WQjt-ehl;ie|cm{DgI zp3 zDYk(;_QsYbbf0N}hkm&`x?+^XRsU`)?!71^-}Hkw)ee*0v%}s!mKRWyY*QC_%uWau z>cPc5h-efhC_R2881fuRvao+~8i7_(dUeVwvv#;#yNPp1Riu9S=^?s(iyajM2U%DV zWZqt1UK1edQ~UdMBnZ5CipvEdR%S6TtA$-wE}5hWU7YM)I^Lbuf%dMp zEppO5^|jU6t>cr7e!@4(yoI0{^gmY<+caqKsXWIhksS}Ya#qYL*I6Q*li66t6dXk* z1w5lW;E=f)w7%~@`HDRH6X335;dF6$#H6m^$#VPSu%{%gDLy)s5cW_eqANU#9acP& zjhgm|8mSDyVyNuZ6mdeyv;@pfTKpDyBo-9gxj`oVR7TAo)y~A9{7;s#7iGwXwOC8lOC?CW2-v{mWi$s3XYl5d|TH%Ae&8ZIjjM8E%zFJ|I$ftjx@CNYGn4FnNWF9@3&6PUaSINL4k{ zH${4WTkEA*Yh(?wgkhjtVWo+8R3~|moxP%)y|;GzjOuG|jCBpOxIJA?axPKTXqZ{9 zwSxVV(#905n)a-d^a~@K$6;8-4uwt5DjJy;jh*R+7M@KUWury`@Xu$x`=whZ!TMdD+X8Jh+0M) zQUYOl&ToF%*3j_ixw_Z2dYP88aYh;k@_K@|;(EJz>Dkrw$hoz@?w!d6qs#J9u}z5` zYa0ZF2dhl@yN_|RG#fhzxwBn*aBX1D%QeWC<)=b`^RD*pz0CEk)%6Q5#-%d-k02nI zESFB59&no^bR1z5_0D z-*}1l^abt!7)v3KQDI54N;?Q13UBGitz4zsiY`*+JhURR!SXVL6rg4FUpuyju@QM? zL+2tWo|rQc^XByK>d`Y0G$%u61b2_h!>7oX@u6?jArm@qOvjE{925og-B-`TF2)L> zsmzQNDK^3j&jy-}Fiw=}nbJmoG>H|fS<78XKpO4@;zE8bItV1mty$&YMV@v4+BjQ$ zAZ1rv%8WE0!JT04Z{s{^dWi`42aUsM(jH4%tS^b{<;}*RfVA&hYPy^YtT$1Ryccex zo)f!oSWZt}5shEL9YZvOX!d($D@0Vqqo;4$i`dX5?*14Wp$`32J?Ui^u z3rxuud#Y|p+90hO0y|+=v_>;P3`{SwPTKWl@YNe(Jw|p%0_nIbs~AUk$xg3 z>9tvPgeO~WxQnF*mo72UC@lbC%Gi_GDFsh{1)>KSxIOktxgl|$rYX#XMA&hPGV_L& zK|jAaSh!T6T0k)@am&{MfV%Sfwq79(p6?zVNu0vt+6>}XZ&IWWl%A~%d1)AHH1@qP zzgQ`Vg8dtCXVy!$Vi#P`PW(m@Vr_Qjzagpwtz{(qQpB2mESgBm+hF2}FZL4tS=I#qe6n>yQ&8@rhN!sjN2Ct56h+=2P5`6J*@Zgo(s zaDn8Bgz-f4rctn)lHxHcRRFlMg+Q5q;H{ND<*&$y{k!288Er`p@hUxVj^m*c&4f_Z zJyMjcJ|;$t=epeg7Vi0CPei4EzGd& z{k)iUWc5Q@6$s*;mQ>6S3gz9ErThp7V0g=4tG-DOY+d_izXXMP@9I!mA)SI3g=?uy zT<2-mIcMP-L#bXaF>0^4XiXWo)rr57HUwGfz2Fj4ws>Y;2Q`JJQ%V{?Gt%kwhdVfs z?TzWhpQL&c&47X5D+$yqR2{MiYuW9k$NC|U7EIx*bW3pVK4()G7`|g6TZ@k_xz9WV z8zr%Fs!-`sl!M@(OX|9?!0XGYGE221~o%0WvDEdKp=NwspK~CaqS)QcAOk-N35l5bl=gw_z zJKUslhCqu>M{<4G`I$DmQ`@r(TQ{`anFW7Y6aZ9~%#&NE zlkl|@jWjqE4X&YU$ReG1Cfcu_$ymo}_00B~bPILlXs+7nSDeEGalM|vo@ijJ!-E&c z+yP%-a|QY&qMyjZnG>>O;U6G0rCY z)e_Yb29@STkI8gj;su=c32`swVotoBb*&G=v7>$=Vl6k(L8cwT*yf{(;!lxLfXCun1YQ^>p5m(=&n-U0Q?c93^e-Az8h^ z>{ukhx3Snjm)C|I=r?wt~{pa~`PLuLT#{^rr!k=NBaANHAe{lAW z@s)2`*JxF2n-$x(Z5unb&5CW?wpFnzc2cpOid{+N?$f9H?dP2P{O;R*KdkS2{r8x2 zjx{mnnNvDnAlKVe0e@JBar)>BEcb@_WG}Hg0j>UDm)5CR4a5H^>yjL#kjSH6j1{@&0zbRQYcn zA6OVycDx~E4Y!i@ykR8?ljqP=J@SwPLM=-URfJO~na*lg_pI1PNv82oJc}YP)q6uZUld2fqv=}# z@x2kDCEefQ=Ec-E% z{=Tqn@$Q9i|9Gc#@T(PKJC6*tG(jy+-SD|?yN+HvOET55^BvYQ;}!j;kg@JEvM1i} zQoQ9z3O2jx-CJ>{X+VyL;!z~jiZO*E{@r>}{>LdgMTA!~TQWDVsXF0$W4>Rgm#j`g3~>Y>2Qe z*iBTN*Z!w;O{x3h8(~(a3W8Y&14B?5Y207^SM#FAd;Ndtu1_y#Vi~VaT~7Aoc>Z!b z+Q0jWFGvV!deC4lIM@^084D5AuxH2fN9z(C{3xQ?Bk`k&iNEn9Ba=DYu(Q-Pc+k>V z^jR!cbASLk9J++p9=m?5n8VB{JrUbzo`d@kXvH*DxtKFHa2EEPIvQwNSizT}*JI=x zq$ozKCn-5k@q9_j6TR=Xc%_i9Y|(eFi3R60~} zG`W*{tjtwnEMNnxYIR;@ZY`Di5u%i9&jS8#dS{8!zGh1$YeHI4Ns;Iwb&|WVc?eeb zAZGm*jgx{@w2*g#(We0TwW%SF@9Jo{l|Q7hZ5q#NXT2f3-;#JgQgkJg?#juO)_)LH z&20>u3Cm{|h@Zm#wLT^rZ;?m~tYbs~w{HHu82Uf|jXz5nIU1)Li|S|}Vi3%zVS#9h z8{DnxVE}B$D)gc8LL{QckI^AUTgIKQ@`e+zO)zX%&A)WXgT^g4JB8cSC}8vYgt ze)8s}G=h&Uj^+s-!-%e_xp&{iYy(c`VA2kw?PxFp3jWih+z|W9G4{#SC*P2PKlvsh zI*yDL?xge*LAqSVZCWxMPKS%UfT}3VW?;fRgRjO6zOdPZR*ua~RpQXsE0W_5P(-PmNImx3H_C08B+yXxpE1F>vJtKIaI zyLwRN3Y@E_)<7-H7wE`3GvO&%W16pIc-6rKfLOD0;Nr=Qp;`U2y}=S!4xNby_+p3% z0rrxatjhD%A!gNGyyMkUfB4Gy*?5)0!|*d6dMD#3|M#Q`PXI7B8!)ah`H|UA`GJmr9BtJw~|+^a^*68O$A+PEUqc zMiluF6GqDBN^Rr2$s9PwN3uc9l`6H21$b)6ttjFR^lZDF*4gh~Sm zH33qbxP`4A-0Es8iN>*ZO}Yu69+E^3_kX$YN){iVg_ip*sq0mRB1X3Mw(o35WG6{+T#qzH1Rj$0;Qv6$vf) z3Cry_2g!)Hi|p?szv}e}J&xQHe`AVguzv?Rp0ha|ju`7{DNH_) zV%v~@|HzMSKZ~QX&a{Ip4XCqGU9yOSm1ON0k6h|x9Bo;rImNI z1PakgR7M!4uVA>6$s%MvZg^tKKjwqwi=ldi`rMG+pF)MFmqg6#7^&s(Sg%2ci-HF| zjjYS_$R==MsC_5AqiEy6&pKr&!B6(@{ft0giHQRxkY`V>E>|w9jiVO-_*SuL|vjT&#Du~J25yk+)g%>XW%m=bgv;(S$3I0&u|@d z6i{R$Zg$MGu*#zJ{*pRw*hPu95Tt_>Ln+`JK@?G=Q#uj}h-aj{oz^~%wwa0^jYsZi zKHTrtul7&aW3IhcI8>j~q;+@Pc~8=YyX)-WG(fUf#KtXUAldv275Qqud9CFpFY(b- zL|py@LKSYM!k%*x&JIkfOP$fWj?vn{Q}^S?P&EgW4vL0+M~4zl+sTK{-iqx8 zYFl%Eu*tpuU*k;fJ7s4!u=F?qJpXIW9H`v_TrvNzpzkUx12e#gmR+`Fp;OP}cs$Tj zV2%WiNqhor1lK}F8Xp(ty!)9qIeosx-s6gCaMGuzj^is18L07h=$9pNilu_3NJZV` zIBpxB8?@lzElFEn>&zq=L~nCSD4KJeEwKfN%R;8{8=|HP=r75m`si2?O*DvC8KKEZ$yXi3^Z(s#H8mt)JjgMwVOroVL)Vd_E3L;yR9lz}6me-{J( zX8`@j#bhm=T}*)uC;#j!Qnz(p5J&QxhE|UkyAXsv+?;JDeMDO&N=|Jv!pr97RLo{A zh-ZlO!7??eD8dZ=T|M0#{|G9OFHpI#*;K!Q)b)F(t9zkohTpr(eZTkPa5HUrEGZ)t#>`1g_Zr6J`@^$xLs&vR$#omj!E$`>tORt?MiPfZ zsF*6|X3*ob?>Bs8tSeF+VDvHWNVA09EhXB)I0Q<8Qj-w)GS8VoW}sxUf=T-36Q@dE zMmZ=(hLPhHC5P>ff?wy6h4}=W^toDx8z#Xj(5&nDJN2?=X`ojwy!`t5749lALLC)M z6Z=?M!M-?HyO>I-7gQ#jZmD~e!(G}2Jg7)dh9X1gtO%T)9IimO#iMP(t% zL}PQjB%;$(d!)v#f*pTyCp1xU_E-ox3YHV7w872Z2vn}NY)a9z?K854yC zpA0`S<(1>DVWu@QhP@gl{{})*8pM2fu?#Z!KI4H_%JI-hRaNi1Aj!LS;g7qygQX8y7ao=1a^uY12fNm zZw3Az#{8!Zr>OmOS{Fs*v*t;y`R=&qmmnyqqg#(}HEj03Gm-$H#ch@Vvm>kr{h_$0B98V{Q_AdZhThm(*St{<3+k= z1H~#1wX|~ERK$~T#!{BsbYyE}oaD}|p%K?_>w+)ruWX9KE+H5uQSVIdG z7>U1Fq?>WUPR$A%M~uAa=p?F2t?+8C$*8SvUrwkU&-%T{s8>_9%7!v)=^{6=EbP$P zRB{q(?#$E#DyoYqR;J^%qN;n#qD$yh$3fRcL+Dj{Io>+jMwXRY9XbI^gsk{Cq zSJix!#r=V#5SfQgqhWK0q@xzqCx}R&vK1S}^&DBNNp5rT(o5o3W_Q&EuE`i1U5Zta zV#o;(EBOX!j>$~i*^fEAnVr|Nu1uMX!71fLh=wG(MU1uKFVyj(LhGOF4Kj2KIJL9Z z!f({5nMI)WPehL-hAllSE4k!HS$yyjDP>#OhL>JP52#IjJu%j#7_x7}BNZ|Xv?`cs zG02y#vaYxv7hnjfeKkuOxxWita*#VaMC#k5jM{aRKBmaq#y#Me>+$1T|0pGJNf8-N zJzTA9ExEg6!T&mrM+|_rmu?T2LBV*Tj`M`pc)n)e0#N2^(+y_$U6k6=#C0Hj-j?(T zwH(A>FBxaG{q7X8I9!Z22{dS4XmJe> z1K2uYQgGd-Xg9>j-1i-wQ1JzkVqD`KS#}HB8^P5r#AP1WrM+>D@<{)l==n+as$}r~ zfbO45MEH<40^*Auz5qj+CLd4B7gX;axX85kPF7@^nYw3?&M#h_%rCx&m{%vc4?+b} zArs$9J3arzwZ|7%RbC`YKxH_}yme^LxjF$jqMq7FqkfNgR*~!#&z9Qm;ryx~=D{^k z7wVC4-O!r=z%u)e$QX`12=m?ri)9jd)I((?`Nj^WPw+`WY=^p5N%fN%GUwwjq;_ry zy!)UkKYJVaAL%%{ggQY_4H$bX!ak+FJHfVhsc7Fd4*o+ zN8}i~dGJ6Mg=EX^iYy9;;@C3FHz{g+c|=$2Do?*$-Jp+Yde8Y%xl;Jxppey$9`Nfu1`*SQw>@^$6|NhQ)wbQV4vG~)q zgd`}*fCwRteps)SXlY?AieT|cA~)aLfFVN!rktpWDpbKA6CCSb{Dk&vA$a}dTW&EO z2G@B4NXP!&`*Owj>*nPVVF!+fpp|!#&jvQRlv-LU-_Kbj9N+?nd;O3bTfOv0k^A$km zoB%}AMuz0M@UujBc1C&5bmD!TOd2C=vOd0abIuoG2kC$OUcTCB27kPh@G%8-k|j7g z{~1nxaXOypYl3spf;TKiK3JwN?C-W9m z_&q9rXp`9;+yjs1t}+_t7(%708UtFb8o)=BM+Aji4nTeWTZ4b@T9vds@DuX_Kk@(W zy#KMJ_|Grws?;z4$4+8kR;l7EC2^!U0|e*niP}E6v5_#N(qMND4Sj!&R;ynMCPTW% zACvC;HWLAo?UU;nzISF@morx@9A8!NxW5BN142TB^jK{#R)4h38GSc^qPiy&Y2CzT z(tJNjU{Qq-z6HFYI6Uk?s#GpQD4i%s^q`O%pwYe4n!!y86_0F@k`pNmD?1%-k~vH( z5;*$~n-`$eX^STAmTzj6Fff%<$f$+td#6y4(B+Dr;1*^u$vWYfxG`AqFT7KxayvQ? z?rcajz`V3DPNdG~c%gnwxdV!J3Zo-qKrz{Dm{^z74a+kz?9V0|+;L?+BwuUTFaqxZ z%X$UgI16TqMTFZcf0hjeaL4C5(;}_@~*D<~W{t=wO zNJ*LhX>2c6`Y4??|<%CaLn5jKQ9M*DF0=YI8o1wk)x3&jqh;y4o0B&;pU~zV;m(+YGs$ z=6xe?#WJm6VBw`d+SCk}zdISq%<|bXT0Q*5e#L`lQjtnAVR`Xhmg?O;;|9sIdj8ps zrPnT%8Oz+(P3`X!fn+cEyDvZsZUs&R{>R{9{^zUeU+UYb^fnshihW;*CHv<=4r_JM zJ1DiKiGxLban=$LRxkJT!{3lm{Q?+xEeanJEqosBp9L0KY}H`E#!P_v0WXi)SGs0B zA8&8yeNfBibK&i=P_M3wBn6_%5ufpcuwY0+0A%8<(Pv=zRfFxJ&>`uIj<9WPvX<#) z7MsUrv=q9h;Twq#O|cty#kNc?rMBi2E$2G(GF&~T&=js0KA}XcG^aMX1w4NI&HhnD z?H0#iBF5U<#QT`7Ax&d#a%+~->soepjuMrwrYt9iB@>?@jMXx9SUb*P*0=^$0(6{a zI69nCv=d4xvVTy{Rk`1_+8+`8S_a4BC(8>ozk_3A9zl}3y7kSy<+B7T;(vLv36l+V z9z|8v(6>e1w)ocj7B*Isvlx0TX&rX`8v2t*OQ;wMmEIXwnNxbGF@?=G&B1zLVx0?= zC7sOyTMikn$Y8F#YB#kNb#LH5L z?)gM&Y!n6`JLPY5H}_-VG9?ICQ1(m=Q`scpvg>(!DdXKcoNr&~^x~>H@*3n^(^6vd zKUMkhEmO&rxnno;y0h$&Wk6|{RCL->gJI)@ZzZ}s$@<0bf-9-DIoT^k&)9}FPB5Yi zYgWR)`NI%tvG&?TNe!3UE<=ur+*kt&hS2F3f_WBz70~j3uI< z_+DfYB2NF~6`Aw(ydlS@GA)jP)rc>El$@zlpBX1oERdHhLX1KT%PZ?Dt%$!!>L)#b>d`a2Z^}x$7g*Z_cB8G3wP2NHhgra}v(+?VF^v z)Pyb*GWzF!e_IGY`WdlL7-&L+|Be4;`O}1IRM!8{CE&yDl1gf4g)cx?l!hrKJslS8 z;6-}~08uVMB8sH$&q8IGQorQBE%_M0ydD6RBn3(nfId?W$=X0C6DLCw@UrmmJDah3 zKaS4SZGYYvE+VGgFlrh(a)WlZsJFzJr6$TFSms(wA141*1CkAL35BMhx9wLpK#8Gg z4Y`}(oNa;511M~P%R$ws658u(fN8$deQAJm2b0!C8`IC{3-H;{NRU%~8I7cN2TvSv z5&b}2;zeV80#SgOY)eVaIVh$XT(MgzlWoDj*Zr7{~NmMbt|3j zaAV&*>3fpsOD-IpuEgemFE3JhMb}!Gk}Bm3uvtas=Bm`+#J~EG-N9Y}W;KSzP}E}z^$rXZ z>spq>kZNLxoNA_sqL;BJXOd@jQC4{iK1YZ(E_2obpf&n#i`U26^-;Jb{5l@MJ06hD zwu+<+5<Ckb=%uLpy|UZ_}H>l?L{P^UDRd^ii~AMF`nqK+^QQY zjs{`mLWruoCgB2A>e!`~v0Zvw&^Ehin|-YvI(E3NCt#_&u%q-0uoK62Aw(UNP8U;IDu4kU?6$C8C2LX7iSg}2#tr{g`CCS zEK}-)cI)Xs=>hCfjR#I#s-NIUUV2tEV({%=(Y1PlS5eee)X#@lf_l)$Pg85Lq&kPB zXE3jT#QU_uLv$cmE{cHMeRS;>pK8rVSoI=*B(}KL3@h%?kjlv@S0%Bzo~7if%Q|`7USrMW<#= zd`_x_WeU0m^F+Nghx~KI9{&#le53F4nQ$?nScPm0;D($oD~y42xp%yKyIF2uHFKc$ zx<;YQUZGfZhsXp0?a?&5xr0lLP1aZ>3{n>J1ZBR(_o(BLl-?zTit43N1_|N2lwC^W z5akKUE0VkL&{ZmKS%7+6y+HleTbCT0Xhy2&eR3w*cr~I4(sw&RWmyPn+5KcnBw;}s zKgml(WTTEQ*H>)@`LxFbZsjyGkiIXb@GuL-R<}Jn9fLbu8>OgI6s|-HWmsfNoYn7O zn}=!qU)8t6euIy7*ME@!$0L?xg3~Ef4}ihE;wq8!eOl;z`rB)8rr##D4rmR?K$cAZ zA6mt~2XkU#g@DO%B(V=w+ZGtFXg6b|jgI9M%JO!F2}&xq6jt<^qXAG4N+u--Dg?N@ zkL%xzamPOq3*XbGKwg1YN{DymTiWlfUEVSE!9ef_u!}J`G|52 zocVv*;ul=KwOYwe#~Kb?gN|1pI1(`=#=klLxC>5D2vJ!iP&K-XJ`IiGswtdYNF60`>w?U3s zYn=$KAa=M};}{KaoBVAMNL%YW+`qoTNQIo5B7vW`6L|jbG+M>p$>rbp3W@#$UudGo zD?ci~c)&E^23bGVf?FOX6H?yq7q zQ2M;)jP+3BZYIeVpjZ%$27pk*I8xCl|62`dOFO&Zj|u(?V7cW#yVJkNdSjI3>`|GJ ze79^Gf3g=yQEiu?L6Omg+qRcd=YJ|B4iQnjnqHR1x4rm&F7`%AuPeCsmGiC$$(Ta8 zoJtAtG5UDQ`~3JHq9LDVN8F;BFGYVuBJbG+dm~>;STL(TmLxuYEm&ORGK1=R6=ke` zEJnGCyb(-C^odt8ttnH<#djvz^i+rYSuu&-r^u%&oo+XBr>j`9v|yGV4U;G@yPIz^ znUal$-KJbsTo;30x_ZedT0x-DPSj$4T(2L=%jUEvnKOJcO(c@P4wn`6OLs*jG^}PT z-2XsoWQoyJ04rkA?TAMIej&F>AdD-RzilH;WY~5W@7qhB8Nf8vrCZ6aW!1oE7<4}N zS0`hI2i+!5o$U5`#6n@-opedYbO{atw0ETfF>g8X0LtJ9@hbJ11*46@#SG)(j2A#t zUP)}*urAi*&Ij|j#e zK>t?_E+tt<1-Knz^n-$~SWd+b0}NdBaK1D|Q8l?BFnm8;-A54H(~*2J93VU|g(|@x zx!sRB0vj~R`Fa-Sv>|7FsNBGRpUvmp+WT>tn{>B-oL2WKvc2j{j1da-M7vIm{9ZjjTY`ghF{ioDca=0X}cJtikob>j;!jNEWH$Buc*rjR^ZX>Y3|rPxL@l!ulk!!Tee^?Rd&2Lh@(W11x(N~rJL}zDL>E~RQUQ&peMBORUA)F@xjmR4J?8}FgnN}KK(;A$uI6}xJl^`SG~-Qc zm$@6+66NZv=oQ4+oXo;t4#_rGBbmvpIJ>FHqvtJenO33J+#^x*8-=8Ib7Vo@2tsCn z&=8YoGXQS3vW_4ImME(xipV$KCgrG;Vqq4S*cvO%!lVWB0ANP`f#2YMGU+dJ;V8r- zs5_vKwM}S-SLO)EJQBerRIFRhC;Xu{#v|14gH?3({PEENMb|LpmAeIc%O)51lTpqa$QO45ngXs*NC9oqRG+art|cZ?{T)b)7{6p{|Bf8 zc<(t@zc6B`qX^yh=`#Tb8||4SKxi-#0Unl{Z^EiAailUrP}gYNTL@c z*~O%x_7g7kbuIJuf`h>zD0~*kd#(#zQ!Aa`jMGJ!^#sUXtl(9mv3HN9rE-?fSkB(43q7bX4SC)%(qe~9^9jR7J4(CMrYp2f_@S8X zZn_g1`2|QOT*#!&RmNU8VsNd*mrQ;3;3o&VX}RX=W0m&Y@NKjjbW4sTXNRWXtc($K zpvMkdedg)2*Ry@>X61N!bXAuwnrv=seXM417dr`pMzOM85J$^6z!I{NW4S-R_rYGV*-L zeDN9d5ms%}s*~|HFeG2$(#hG!aJBetTQPbpX81~?Rp^NQy=9u0+fGfSw6?SDH0w~H zPzz^lcsdm35+G)e=)!sgiDKzUAL@w;;}b|K{(`^%oAxRnjQ=oZBw&}nsx(X?rbo(W z`T=Cy4Lj+8B}pLoyF#xpv4Ka(!S?58qfh61+~clre55}~4#~91g|VE{VQRbJZkrYXGPh}&3lHNHwRneLDg);xIZl00`Q%PkRdmrDQ6b#r?%C(sR4j<^}bZ+%w(ZYn6C7Gs(dxkWG3Juzt4N%HD1w4cOq;u)Q5C8i1M<3EV7`js|7zsQu6BRxrBPXz$7Mp|Lm-k78GqM?VZAR1 zmezY!tU!SZUK1CN)OJKh^mS$@=hXg|^0Vf-hM(x6fN(ahlAE1qH}#^nIrqk6nu{fO zv-iXAb`jUg!tqCV?Kcpfk7b}#7!>Ai>b;UQvMMFj_tR#)W@h=!VB{Ph3-O59&PYj5)UJJ_r2{? zurGF)ZHk44>I|j`v7kHe3zaT8Ihu>RgR=y}yCa>_(M)d1LY@8}Co6v_}N-Q|20vOzx(zt0uoX#xNR^#ncG}Tca@% zzpIBw!&C6!NQ?U$xH)e-bF`f$SpR(j5Eg-P{S}CcDj+JD{u5Nl|05LqoAUp$aD5Rd zW!;p#Oy{bFF>DW}mtqT`VHh!qh!B#MRVUCKh*A)7cXOA_$#j#xH_r$s=YIx$QySsX zGZceQ{ZY#Dw8iywu+h=B?eFsrVTk{ey3}!nR)*e&wyQnt7eXci0pldWZTl*wR`R&J zHhCnVA**=s`iq8gm}PCUf zxXl#UgB*s^mQh1na$lhkmlBlqmv!HS%iH&K;ut%W8;`iM`R7rgiE#5zK~Lkewj;a~ zU}DSTQC77oTrGR|A{u7eNa+Q7h1IC{n(aGt<%@K=rA+NQS0qYkd0ZZ%ehgy^lHZa` z+g}-o*CF5H7g}s8DCL^`b_>=#3sGzPDm1w+*>-Oe5bON}&4G7I^pROnveCj3vwuI}!RK1Ob`iI^@v z=mE?^Y`)_BsV8YIri=cP)YelD`17T7}&$laJWa;Fz!rr!mTF#110p$ixqFg`SV zUAAa}hT$Eit&e+{I6mX%6W z|5SogNv+jW*A`SlMlYe<455GM$Bd2;5=bpYmFYgpG$y&m+ZLR4@$dMzOHHHAn&27Aet$G zJy_$GeIK~5J4P$%R3eIUkul3H!gW5;+%vNC0j=yv-o<>75v^9AR;6bgC2H?Y4gDMq z@b(P$O*^x|W7foVlwed{SB}_xn@W&Gcvce4J$1voJ&C7KUN@JQIXC+h^h=t>R+Lu` z+*3X3yh5N>!~lA1mQ$ zrR&UWzuh4);Z>*nGz5g{v^Dc_^-6K|E07Kn*HEWMzb@wG7=LLGw zlu>%}|B7xvgy5Dk&dBeBRkd`P@`7QToVD4-sYR7W*+s22gbo+gfRP-6iK&9O9hddS@?`oFp`zv#axTx5 zIP>`rAxZ43Nf6kZD%^D!v&$S7isQ-d_uu>H9G`4$)R|&*tTY<{MoS~M8x6Dd4rzeL zc!`+Y?*pnm6Q(FEw2)HV*NBmtM}FEv4U+F=`|orREQI6L4P!g+k<0x4ONr~bfJ*d@uvRRWo zAQ(Ak&^O(Nnq(EtioTVPfHtxexeI_XPk;wtYm?dJH!$t@)Vk z@(k8{z#>>_w$<5srP89KcV~_{we81ZbR6dvBC3r4_z|JgL9kVbfEu?AumUPF8$rrk`jdtL3r+JON z^=82Hd(K`5^JN=j1YdPxW;`z+$+miS+jf3izhXsA4v48fY7ql?1hzLZZCgO3zTxyk zY~RKMiK=d#Z~vkMd``g}Ddp@iZA`2_&_{u1!s`y03R4wQu+p4W9{T}(R5VjS4TpY0 zpIyTWwTlp^L@}W=SS@J#f5bv;}w@AB?}<6y>^>j*~iq) zV&0VcXM_vCIPO4R7a=vdEd;CJK}&4q0J~dQ?ai~d{r!G}%#P@z-+5H0x#E)N{_u!| zhlPjDf@^^#V1LyO)uP2}?Ns8uo?#(V5tvR!X{akyeKhS;!KUg}`SgT6=|Y(_LJ-73 zcBoex>try*{j-F0hbHuCo#h~;49Kx6(umo^2ddIFfLB7vi zNO|`{Mu4cdeaa}%xdd%p-@@<9T)jIkbYav`MWU7cItd6xxgoZYa_tC}_4u0YyZNE` zuw4k+4i(whwE??gp7%^wQ3)b#A9Y=YRSzPy5WialL(MGRP}b5KIFY5+uwzRWB17)Z(xKj}bK1GSgow94M0f|7wX9v3)@$m&e%XU}MF;w)U-=AJsKQ^Ev^+l@ z43`z~bnz57m!`%1rbV3_f&}Vbj(eEF(2j)tByT;PEEjyCXYw)QJ zd(!61!U#qX$H*aL96~ca%Hg9n$~FApuLtNiY4Igq0HfPJJsI>@O844O zu`+wb4(@TQOwdOavLb|SK5mZ}dZ5%mH*zpgPjd z+fc~eIm_jjin?HLIObr-B!TDc4*F*=W}#c0x5g=0v8qI^3P7Lg@CYTXX_kC^mHG&g z?yh}>pOv4|z<9NCIAPu(x5QPs2XU@-|9oVpo4@CE!Bg5}aROIEE))RP)Xc4&D}oQ( zjN2Y02J}++Yv`^^&b@`V@FU@U%aB}ROpBy4;Ma+wQZnr_LlZzJMIhE(*nPDh(8@PN zGMUsYOtC;okW|eO4f9R-{co)WaXl0_5dXj89{ZoT`XlcBp{lDQy<(?9nO|NGrJQV6 zAYraSvv2LV-4NB@>#kqkqymo`zRG(Z>RWzgPEnkCJ&8Y9P7s)US z?1P)aYn`42-3^rJ)@}3fi|*g_Lxr~HcfF3^>n^S%xskAT1a7yC=8`Z~AKY;lydY2*ISWxwG*_ zgpY#<`==z`qgduo7qvpMEWiy1c*h1W0!V1u$4adK{d%L=@3s&Cq*`OttpuegEbP5| z+KD}bYE^0Jrzus#q=Gt-IGo?qHSA2{42*{y@_lbhsAz8xzXBWLFt~+`Bl7!rWam#- zAJ8h(3p&EB+vO=m?t{%l^z5GV6rZE_;`>@~ucU?{Wte$Bn*!CJr#ydUoSm$3`JE{ zFuizNz(mgp=*Z9)Qt}kYFW;V7UCiCX7MJgXPVyM%{EhwxojM<>v$I*q=y0FT&SrUf zTz_IP_}pBtG|YKf4wws#Aj5TcoDtp}U>;nAjytnW2&wQ%nIJXOgi35aC&X-+d~Xgn zPIy&-{FMb~ww0vi8`S>`9h;)#;(I(zd9TJ_=oI%KsItUk#?q0}`6r$7B%KHKLsK#% zmlP(zzg4Y#rnRI5qRJtcsBv1qMS>^I&U34@H9R8J<1f{B=SE^Av4?J;#+^#_zL~Q}SCp%;=EB6Yk|x zjky*qwC|g>CN9ict7i-T;ik_^WoIroj<7q!jhk{yFlq{?#*TjGO> zs>?`q=V6fWuc#_ZE`Lc&@@fouDE>~%y=x_d;WYp;%1A7?xB zXnQdvPfMMMXX+8GzU%x~yyVvd$CKp4Ol3)SK~lHUC7OSM8ko=yoQ=f~jHm*!2$ z=%3Nhe;vaO((_dNTBS_aj`JpO8yy*sP7qR<9@v}yjFOzcj+oLSRyjLo()ZIc1SPwIxn8-;Lkep}9Y5tnH>vyA56 zyfg1#s*xb}4Guz64{Dni(0jrzeK6vp3Mr(7MDIVjI>1^UOGeFVu%Of-GpQr%5zz&z z;~1NOx)>71bSAT1j1q__pNIGJM5Q9u%FF7X6?BlarMK79^MDe2Z)s_-o66<6z zGy$T@mgc#jsFG;V!X%XxQHnR7Xc2NEqx6=NP)33#c$F;RSLiTC2$S#%>56f1gARdc z+&!yfd`}GN@M#WTzUV9!-`|_Yuu86Yvw^|j4DLTn2>;buOVYMAaK+F@dy|5}*b9OQ z!KFpeMPY@YZK-O6mHd*WW17hX!EZ(rWe4^eqq=Yrp7)aK_+R!!eCOTyMj=w1?>7a; z_j3SE&_wYE$#2vV0oD5* z7W~iv5g}N9^eJ_yJgV>==egMfSa92cR~hi1!bN&eYT$Z5FyQ6pVZ4TlC1jalUW2vs z(jCCxjppO%b}4X$>4S5SSVJYHr*2Ib<{EL@EILiFHZoV#){oeO66LH~2c<-lESxm> z6j41T7EpzGhi4P#okGtJ=%%mp_wHQgo1G#yzZGyn(=gOSi@Zuz0i~8BQobn#D@-BL zWcyY+FC9^hZkQWp!S!3lM4My14U(M01$eTE_^l;o_NU!>uWx9pwYes`kWMvM)>WmF zAJsDMTv(vpTl}Pqtiog}&yZ!J3~ktjNc}==v&^^7{pM8)r$O6ePH>%g9$Rg8qh`lb zoaUrDv5OrVKz&2&z+-FqE09VA%3K;G6gLf*(Ixdot9Y~3J-A2{U4mv~`aJd?x%nV{ zcP+%qMOLg4v*-4jajL|)>*B7k@|4+suf=VBDVZp^QLHJ;Rh#J^LvMP`%})V>m_Ks% zn?gDb#~B?(Y*{+`iL3{w@*-=f{|{sD99>D%w~fvu z6DJef=ESyb+uE^h+qP|cV%xUuWWtk&=REiOeBXK3>fUSZz5nU1`gL{HRTl`Ti}B;z zVE{7B1)ee)l398MR*0jZuG?*9`v@{k&aP?73~IlJ>XSbfSEJMJ&|9;Ca;eda*UQX zSIc9mJI30Algli|*|}gqk9)p7PvcWyL-*M+^YfIMVl>A^jApOWrTv<#_cKH8yfJv* zCB3%BBD@Am)Ak#9r-6TyQYS6B;PqLRHfuLsm!b*6j}S;`Z72pCvphw=)a^B*i7AvZ z?e_-5d`HB`%}RC&dvn6p>nAFHRa`m_4RF|4#685pQ#-o%#m9QpB_| zE60eC+YP$V$Asg^UH+Z z#~XcHL3}xgg9^1kq0v6I>L3t)KRrr0zB^G}vyXYAXn0I8Q%rPOrcSn?HVvL~=vz|E z)&lEq*mC?=;#=YG)k*}vN%vuyVkEQ^rDCE=;&eG}ii)JwXr=?QN6pBO7iRbB#-Ebu zw`58`+i(*zvdQnfTdD5yC!WE@l2c;nfTaAM%Yz}s^-R=QrJhywJsi|R9w9ahynar& z_=j1NZRdM)Znv?$n>)W!H(%MlayMV`Tzr82=Nx4sgUK1?Z;Ym|^S_ee{$qPv!NJkN0RmtAS?thTs=w!YWV}V=U-@o(0HTH~3|5{H$!-xzl2|d)uw|lp%XxU%xJikDH zS5qcI`CC$n?Io?Uvek{#(Zv``{GT_s&u=yX7bs=NEHx|LD7nex#YPC^$pCYbCDb2n z_zuF0hT0goBSb1p6+humi&ss(g-b3kL;`dTO~R&O8s(b**p;n!W{{lU3t%!R(`TIF zGF(Tq6G97ovEgFB*l_D;2LZL(JjbeTIQ$WvQVL8Q-l^9%$y2rBP_F^g7;EbTr{btJ znZFH!q5cr9ndS+xe#qeV=J19HrnR<=MJ`D^yoPEix_EX#Lc`?@I%k$cV!Y+$eQEhQ z@+y2+doYh1BO27s3ReV!8#^I&u{RKwDHSlc{iA#8~yUx`RVmHL3-a!qCMbLT}tVt%2o-?9%BHB+g z18$O5D7|cn{dq~sWMdRajVkuC9XE1j;N7TDAQ)o42pnJf5K_4BF$@zkl9;uedSZ z(ctkU#3>A*NP3LM#al9RbY?1pVdO?n{IS4D}a?+=cR# zSn#W^VZT;(c>m>6?P>TdEdI{!{Kp*IQEp5c=u7z(=oVb;GH(*j^i>|Q|euNc(28i(a^?iMvyiExU^r%jswB1TLhnO0T1KOX1KB859&!u zY6SYDpQy~cEB|DdbOHkV<5aH=o<3qTx*f}6R&L#FZ0^n4qwS5Q)+gmKb%lR|bU@f|N=cCE*H(6Gb&Hu^Scj*WR}$&qaS(xJ`_~^1C-skiU@}1!2SP zPIOteC?R!Vst{t(YTc)9QNB9|TW0Nob57pOZyLZC!(avjVp zQ|%XlB@jp{CeIORq*QQuP{!C_Hnm2;77>{rT@hkQUh%IwJmO?!=c%tAu>4vD{Wt!P zJq^EwwSoEHom3eGEcEQ{zxLL@EGqtG!VxLI_NB#xIdupZ=)h(j$x@x#KRRZSQN%qXLHBKH7YtF;JNb9%j z!QeAL@Sln%S5@=vP($kpwJBrST#48<$%F1Dl%4ydUCLT;3aVcS=@FPVJ<>y2q%pJv zTlik8(AOj_#B`=cSJ-f#S?A}ACKJdDa5|8zOn(wokhFwqKv0ArDB5!H0Xt$m+z&8t zauZ8j1T1L2KaK)YDBj!aNA{DXHO^ov*|Ksb0Ei6ZN4dee#>?DisiZ5-R8s@BwZZX4 zEb5;|m+Y5<)D5`yr6#Z%t5a&~O3LMbTw@spypiqiU+Bcn3fzgTw%)-P zKO$0}d>Ld+0$IDAi5y7yqHKRMwT-C?W~y@c64tqBG`@d7M-;#MxcR&Z_I~L1ChyO& zHCUq#V{VGLKu!RShB2NuAN(! zCTN!0wJZ!Mj0zW`@;iF=a~dJ|3HO5BmMzmvbG-hXHoy#-2p zi+K}QdsohE4LAQrruQZ#^ro5M5xt9^eT(;aH;McZDptC$KDcLc{YZ!Q>dg4i(*6+0 z|NO%4J@ezb#J1v?K8Yuq3;#&7d8!BrS#P zztx2h^vruolVVe_?Dh%q{U5KHP{&_KK%b*t@nd&2d zWNzPtpIX!F`<*hYJ3-?P^a*uBr>T<~DKkTyWE`I%%O*%q#+-k~W*M6Jg|`nfs8XUS z%gvzH6k6xZvz7K-ihki})gy-GfKM`gZd#DaO^#|VXm6^pb6HWZ^%AHi5(M#3*MSy; zE%n=|Y&Q7%UQ3`eR$0UQFR4940%M`Uo>K0{7BH0T5MqH)GRZ=6CO0aCEH)Ii{XGB! z%0*bDiKiwVe8dqo*+XMy&{ILu!;S(i0=*X38Q4T=3Irvi9&03RUjP%}r-m&Qy_1k` ze$(dO?l=Hq)*MgBG3*h43>r#IrJ@36L4ZynQmn;n4A0r(9?MA`i^R9uzXp!3?5t)7 zsIAfgYcWbg(!Y9$P@ciac|weVKolKL1*HKBBEKoZF_5Stq&S4uk|InYkx*1;pZ~r? zFz&UAaPZ(enRE-2!b}TVx8&75k}_ZJN%#2u@Y#3SAD_FlZUl#n4kch(n8?jC)kqwD z4ME|``nxWSzCs}c0yP(=2xAR`Wkc^Z$f@&|S&@U1!zxMOgK+n>07j;UE5`vAtzqX( zsT72?QNJ<;{Cv_ly>#LhqCQR0eZlaKH zcqF8UB_)<>@^JVZ1te?3<+;IBjK8}0nG;bh+QUb@XuiEKoAYx-lQ7lgUV-9mO0xgF6(1BN|)r?oH**nx5f%5eB; zAfame+Y&ySu)`{`yR!z}X$e!-5md%5(`!a9t7#FVt2C4;I?$t}>5>*=wEn1i#) zC$Q%UNtS*2Z=f7^;J08<9x_HK{#(7y-EMV+qEKZ&N*fOJricFEE0PEe3i|Kxd6e2;yjj)yxjH&Sn@0$D8Ts4h;yTIiwmmhf_;l^_&#(l~0vb~b0w(TI^y|t9Wac$=n030bFvTqG6 zeM9!6G+}c0f;Dj)S1$FpXVkOny*L1?(kl9rgl2;u@wn2?I9BM$g2Kolt2c)+w9B`c z0pY7UyTGQ%-4NY~k@_&B4AJ1dV7DjyO~QYBCW(Wtos~KyaaPM8Bt@y+YUi5$_8>c3 zrk7Z~dwj7?Z%4hj*q#w;oR?ym=35mEwlMSx&I+#xjC1G_p65peU?7c}a!pJViyp?F zs^GIlILDUu@JJlgE8=@NzESW<4Jswur%ILb2!O#*7lRIr2v`?^-AI*yUQ<(cf-X#`Av%W%vl>V+b@c}n1l zVO{8QX?x#!OK+)@qeN)m&~_Q5X67KAK3%TiZ=AG<^YybMp~j)@DLn3wiD5q1R>p70&ik55|;C5n7_)ZSX*vR2;pl4`?Y;*M{YQ)O7;B@|1WotY`5r&yQ%^mz*A3A#!f7@U8u-KkLbMFHZC z`qf?hJX^u8W6jHZcB4oSxg!GAwA}Q&C~#}fYqFlhl#vaK=A|%>GvO3bmYpjMIn0Ty zWMgHDrZf%jB`O2!2{kEKbbQv(3BWCSw?V|xBC@V=HW{!+WjPh;35Bkqp8sW!HOby^ zRro|MvEpC+?H1@EN|Qc&iuc?R-hCs-3ti(f=1-Wo`a4vE{g2COHi`Bq?cA~+kX0@q z`<8>U-`Ege$)q@<2JQ>?*>0CAQyLdXSlDRiEoBYb0xXo08nqgNI(^H{v@b9Pt=3=r zr7*>Re*QUbZ;0#)W_|J`>cPcxe4ifNglK4-exI77S(aYA5}&CqpgsQfPSAqy^S6JS*z|7T|L{DIN!@PxJxr|~CN3`&W0LH>+?=jrdXi(o9D z%_f@g3q6> zZIF8+x31&7XUh(Am&X@)x+q^BMSG8|&F+S!wd2fU#Jo1VM%y04)+`QS7@~sT?*5Qu`yS0d2PetaTYHbWGF&SzFQE*nJ4%g_i9_aTO z^XvHt(V0KD%bgeIrl}(L5t``1ms$eMk#@#CUQ)5vS`IHqIp`=L0ZQ$0M*WUZ4(buh z)M|&vl2!OR0gJ^9d@R&+wGb7aN_?Wf8u{+1YO+I=BhL&=q)3sFX z3#XS(4h_YF6Q%NkyzPC5`g6&kjNx>p(}^-=8}Y3-O_+9ep31@p@vX84g3XnYV1-4C zOk8kw9=#X4zeS=%(>KRC(21UUAR~G&48+KI{zuA%5)BFP!`WG}eBmE@^<_hdF%mI(`_4>}gtG|mG00u#lHh?C# zIi^`d%RFl-{7#uI>G5~3tcxPpwq=seqbzqfw>2-1u1;Xq!7g6{b#^Lj%b;7?9|Smb zDOx5YxGfiVx_Z%`I70q?=>E(-qPoH-Qnr5 zSaUU(#{x1eQ-Ao9629&x)y01o02Gd+W3=9(RcsZ>q~jXgRl6)>#%`u?wr!H2=)s*F z(<&C}!(X$;HWX&I$E@aG8cOyFwr!@$PA*i`5*AkS354d}={!Mic%00`ZYU|s$h1nk z26<_>6*b>q*ysIt8emX~lqrBF_LT7T5`qzqZ_BBWTtU782|LjKL_QCcg=eo69!)DS z*9(tHES1fLlvfmr%xHorPod)oI1OM5Yd3|X$Psg)5jy-!Am>>NqaxZ@7o2>Z{~eu^ z)w9#HH2Tu30^E!YiT?e~{vVwZ7}FyTOa~YA+0bOZRMvRPCx{fw@>O-e6+DkoNR~Vf zOVOMS73sqLkrP+FuTlV_a?h%0z(fo7OvQ|7W3%#*p z@f>EQBHb%fkkzROoQW1ZG)^9pOe-pzh7KY*E6J>pxdS%~GNUQOM``GVc3Zoxc9Ci2-#G`(I`AiE-#`G{07LDiFZgYz23>N}i z$#qqprc%X?8Xt^f7c3j3ssDhT3MNXq0#G$1gQk` z?Hm7pMWO%Qu77XkzX8(!A1GAV+V0=~|Fhi-zv4s@g^)gqq`uOnJPUqN9K@PQ%pqaO zD&iGF#){K27LqTF3N){YwOtrDUs|b$k%d`*U~qy#p7On~{B2`-B<@g2K8nZi>2jQ9 z>-{p5!ocxshCOO8Tnf2a}j{) z7w7?J@z98}e6Y4)GLkmS(y*(HfFShiq8UpdI`pe~;+(pUrw&(-pyoO6^R8uPwQG=N zE94^D=qreu0bV`;g8Pa^6$t6vNqE8n5dP@U9hc7(0WlRe(r^Y`Lh=EeoyQu z&I@ovF18i!2?|?VRhq-Ma57D z)Zm8NavwtFl}q(0!j2;m*IM~0X;(XXlJLs#@+Q>}jVFAuD^93?PKA3)DDs88O+$T$ zcK_8CTVygZTPiD}FEv^Y=sU0A+JU|(kiDO9P3*TrA+1sT zXr#V7Or6UFmb)HU+H%*VFi-ZzP&{m6cutTXecD80hEuP1LME3 zk*61nowo%S1mT)c0mit*_w;^KJEVJKATy1^^MQ78^U-ba!z(d@P+vQ*=p;=Djp4Xg z>D~Z^4kMBf4?dq2RP>B>FjPeqVs@Ik60v}ScPqEo>Q2sDS=K+mE&Ti&Iro9NSNgg0 zHMJW533?ktoAW^PbZwyS8$`md037j>7_@}BJNY>EpqIET#PR^nU!gyCJjDZTc+kBC zZ@BrlS#FzA*-=-=F5B#&zW37J+#_vh9FK4b?L)YI#$~mA%_zH~ zq|vWoFj~dZZ6r?N@kK<()QE_^>iE=n9SrKCMpu4@o`&CpjADpxDBMFOKir^{?Oxoe z0ry{LO(haj!yoV(db4HG>RW*q{z_#|ZaqPIaQ(n?oUTc}8= zMzQa&R_;P7xA;BtE*_4AIndeF%2z7v9|&mPeud~<94xpsVsf~M?$s&2!qaoh_+9D? ziM%p&D9hM4Q$%BPOJPwx3hTHUnF*MK_+d4>pCA5G_xS2 zxzn)WB3Gg!K-f$^CU70T40)1%3bZ_p%BoYK_JBjW?lPsRB6>zl@d59+JfW|2UyO-= z8K9943AW52&0+vLFqdg7<1xo70)#|A%?t#~`a77g2H3BshH}GW-I8mzaKbufl$xFf zrk@Ng?f0~<+SrOrg*?nmWoQDorU8sbd|X5#K}G@xR}jPsCrc9L6}E}AOGg3Bz@_K& z3gRi>kfd)_p*J(Gq0941<*y~t#ODws_jM9O4VcsV!1jorUDX53QyC>x0QmJ*dBI1TtdYMk;=_ABLiTB^4p#(0;z7UP&xeaRPf~>qnmH1$`t2s+vi|J~_*?kYIazoW=8T z<*p9(RSxIc26@+a@LGyqAaE3F^HXZH^=N5`2|9olpCdDxX*7jO2-Q0$U_p`>txT`3 zj^-Ru3LmaKXO}C{&W+-7fDh;3Fz|~_Ck}Jj?eIXTV=428^{3>`+t@K^X%} z(?Qe@=Q&N&D_UB3M}!E_p{2b(w3%8k<^`QfN;HX5#pz_$1D`omQumuHlYZ&qB%U!? zh&=jmC!Uk^_UKC$p4ZX+=@#Vaw|_=rzK8`2P@ z->q-8CiBInZL_wqGF%ogUQ&)NAV5To8ULm?Sdq#pSWkPG-x-6dO~E4p{3bC7%gxwc zBa6u^Y?N5ZAbI>H|MtSkfT*06!e)w#>34W`04~O$n@##M9GfpE1a;@mn&SD5!7Rg; z1R{eM{N+n?K$@m1&PTO@Zqmqe;*R!kf3d>5RjQ~mnLzY@uk1sDG~0sy%SMj_;N{Po zo!`ypJ!gqD-gltm<8Fu($kV&`G=x8%Uoy2Ix8?yh5F!0R@(FuQ#fw!NX`8^fG$|0a z=bK-wb$-~%^P5zM`p0prFDI~xte}H-RQev z?2cYH&P6{pzq)`bZcl!I2MeHFl)Z_ITm$oDRqTvpVpA{)`~DH_aVF#l4G)S?ZMb%; zj?~5nN5i!TlzjrZJiK1$Bj!=%C2XWsmGEzb<)>RB{Ykk#<~<1BL?qGS4j9J(DAf$+luc zNmb1S^X#xDZ0y1Qy25^|&Gjl8L@}BwC&*1rqX|DMQp$EdHYDE*C*5npY>wD$&S;fh z#neEP*k-B3Wr_R=(}^DYM_FK+%NM~{wBBqcT;PWz6YKM)+Uf7iPOpIFn!Nt=un0#D5Fxu&4Q&?HgG+{3j10Fz)Y~m7pzvN-{MiN`U@5 zZvX`{0*V!~By?F?)xYQBNUV9nQtDCI6@1`~sAkwM)T6}SbF*uD$O8TTE0I3TIX`*Hpecz}%Wrew9f=wgH zO(w6v^qMnABw07MmC8JB*yFre(98LAXAo@u&HC7KKiC#Su=9!H zY)A`pN^?2IR*r9D&>j`D;5Cop?mGu{p+CP|u*(8I7Mkp5&>$#2-t36nU zY%~$Bmwe4b1WAyGq?2g?>vuji-5(AS?$O(xz?E7-$g-VfdZ{CX9iD-|quqSBSlpw$ z6T4cA6eY=!LCPY)8i+aj2`5o-=9D8@ncHK1|Kd*xRv{xh{Z$cN|GSF#ry@L2VM7{` z4~=WC@)uQpWzIGY3RT!Z%YsHEiy)%DB{g+OsMNTqG*DPql8IwLWM4 zqG@HWZG5Kn(Rgb7-TV2`6)w+rmx$N;7N0dMwMV%gY+RO^68*w3rSEKta&v>Jt_BVS zH8Y{{ecNQsBv5hd>X|=yUQ%9lJ=||4oK`PHE*~R|8|@QguPQmtKCCiGbG-l={Rea(u^1F254}Nh z85r)*>L%|kDg#=fB#T7GI}(a?gml5gq3$sjeGSk*lu5{elV~8F7+x@9C~G{rptS-$ z5g$SDAu{aX) z>fGHlsAy!K#8Zczk~QlLeu|0-me8am0@9J)qX@skI91i{pbydvOpg(wiVWaDax$rN z6yH!t;Ldr|SfH`+D2%oCCL4n=Vv~QgsjTtBWLmR;@^tye>mrAq_aAr?k1IKLJ}u@E1es}!zraG04FMtEkk)ojjSiaOl7() zM92W#HJ7>GA@;Mw@U=uvrRmB)n|3k+ru4 zd&1_lxt`|B%=IA3OGDDj)+^49$su z`hmKfJ#3{HY8aa5i`ya|hx$2ouTALb*=q-U$i2~jYVA;d?fMbZ9UQ)Etm-3IF6VLOTzpsdG*!Tz7Djl3$M@8Uf}vu&9Db+08Sx%QMXVeI z`~3Dvws+pBOs*<P+aoqFa`aq^0AFyBJNu%ojwiEY3Yi%hfXsYZ zKLzTQo=g$#R%+@>&3`yC_dukI@~zu#!gD9cdUpXw?}_*Vht?vczI%W$NO9u~GH9U4 zVPMR38Qv@18LN(pi7TB$WIfr;(@e5d5UpF65lLuchYxSKj+;+-QeCDXU2uTxB-wkPJgtSl~+t5Lx~v}vuNNTcrPmR5cq z5HER8c68w_6v}_1`oM~bJ4o#-8-sENNk_LNvrbMU0+KmY8yd~=L-BomqQzLBRMH| z;5p!&NnTS>{`pIfCPOlZL)hlhyv&{bKg{eKGrp{!feIe@}A$u_i85|0kah6o)hG2M{#B zJP}a?G_Yw5Zx}Edlo*~KObB>DAeIKk1gCC+UeF|T-F{QmMv+uo!AVz(SVj{7u-DLd z4qh=m2-q9^vcZv9br8#J(#ar+Y%hF`6aF*hX}#H@=7WFmdbsg=X*cPeb{ZU1@%S6^(|favq}N@U4;0Z^gTIh$a`$|Gj`~6bnoo; znP=r5Ci3#MAzaL05x|0I+#Fv1{z#kYqaFQlBtMSU2B44!5C1 zK2hu#8fH(v{_z>q1|O+p&&*pgTqccX&RlC1*z;$PRPFPMsv3JLw)vv zJ6U`Vk&eG_8x&#ksvmqZdqV-|;nE{fAkFJBj4LIElNo=mrtT*o_twWpVL%l7)a0}f zexJ9U_2+dqyfF(jN$G{=4xtQOYz ziiV@kFKQ|I%B7Fh0%_hh5ABu?I}jPV5->8CZR#P!zQkOwZ)aWPx-dd&_btOg2opw^ z8u^C`a(;(da-f8nhH)gq7_C)te-n@E)QYzptyI|28*$wHH!MB87j;l zeWG80$W%m(w zPCMyFi;ViTB_PjTs}(b#&iUSwO`SH{vc_Ii5I1s zD5;=EiQb}S>B<;P=e>T&q)4X0oD#Tb69(vo z&j~yC!*p9>I>Qan>eiX1r|Cuw5Y6Cayw&ssNJSEGJC$K!zx+5owwB1jUg`5&2RgUc zoyV+XOQLCkrr)-%RJj?9SdPz`v673jTJgDxkL%*>Op7U{>tqI$u)ft{mZ;o7!9-YT zDQ}(_Dp3}Z_#}bNT4JgAj97bGrD(8O$s8qvBdw^{hC2D#h4_9J|3lQYBJo54RaPX8 zVBb+cd#4aZ{Wr1w(MJMjsJ(E6?|b%le1(`rm1_7G0Sv%_7n(+8)qRU4v5X2;VeQ`{ z7R0S2KE{=~&>&Ms_BSUdrHf|x9qK5KV1lCKFf(si6L#!HpOMCe)I1 zwCRtNkCSafS8bw@SuIo-N;K8x-&!FyFv+=%4Aitf%eo zI|ljut8IpJL{5Tw^q65@;9b7SK&@R`6YF5yLw1(kMD*0(+u>sf6>#|z<_*eBkAZrI zechOnKlk9$EJ3L*XN>3%Yw>r$wDas9*@24v3lOS29c`3c7>eM59PeT4gVaW(N6jNb z(V$WdEl;4uBu*@5 zrIs%(lVPF!5^@W(H&WrF1udJ|rf8`?FvJ?70?o=phr%OEmEBY_49L};mU+g6LrW+@ zbjr+ifsi`yLN+*bM6?dOGdHaZzz&br!%lbioUJv}8*1L?<@j`f|8P+byc0$2=kDG}4Bj}`d09VWB*n{lv6NW@@M zzJ(_y0Fc1X{x)4!P9#AsjFQSWMwwa*J1T%Z9>zu4qtx7`SrG0&HM8rC`KV-hgci}*adMpi2!G$ z}2aQO;%5r4pmZw<{56AeU43!G=z1xOtstYOu!3D?lJF)q+a7#kFh8xZso0fo5Q>3%EVNy=(`um4Yy+)>T&R5l%xg{9<3gfAi_3YtRni&*;Jw&0o#Swab9~yF z^N0KR0ib&I4k=SFG|*EY=@sFH#W`A<Vm%xMRxx8;Ob<(kt^@ z>schca5gPQQ#IEpkfLlbFRRQl0hpM_LHc>3VFGE?d!Nx8jyh3O+ zR!uHH;gPra<*%}4v8P7Z+iN%S)d;YPYI^!gDTcrypCU!-y7NV96LBSiycY+hIP5 zH4rESmUxE#JUHDqr}k9YKWXnRY7y${TSfx22s7fROI}~n+8@0gPF&ePwSDF`jonl3 zPE_UU;14clhvR4?Ql*h&0UCop!O|k)>1`@5wFtdz1am3^b36By0^gZ6r|`Z($(i>V z_~}+}#*w1~c^#d%eEw za|b)yKcZj{d(!TB%IBI`khY6)c!%}`-+fWKT2lOmNv8N)jaZxmJbgMVJrW}KAR=%qwNLXvz*t3_p zh-DjKG_^#m&_w;(tNoU69hn%d;Z3$+mPh^#Q14vl#VD5nELeU4!KIPy*keoIqnDeI z@Tc=Va**)besrQvufg)bS;M)mVq2Rw%iNQ!2L7<2q&#TkkoOKyuHc3Iq*D4|)LS_$ z7-Rl$ATm2sE#g})gCT(BgWqnHVpw!agfCM*o}Z_O**mAbb}NmPURh;@ z)a>t^7Q}6^!6o{g-Qj^HkK4zFmP36XeJggl$Jdq}d<>nPXN#kZaRNH|^LdZqKAocO z!j@nS{^i%&3t|)w3ErNF<(b54?V@+L+Gk$9He(#MmQ1Xo&2LNh{ycGZL9H(4(we)B zX68z~<0IdJcI#otx5*A(Ur86`2S~7z2oc?DIreUook4>r%&XoGVo|0#tJTPMEWWm5 zXB(#BmfFTmyFF^sMvn~bI)*(&Cy=EMe!`kwQ(n$zi}bn)1;dKzly%6>7k%npuu?yo zZmHrDUmBnjfvWqY$z@~^vtx&>DjT!o@h>w8ZjiMW>J@Z%4t~j%F~u`P4_2e2B*0q} zeUCnU9YVQa7d#l-}Uss3|EN5dz1yA;d)AB{Zg2!Jx zQCn-p$oRe>PLVIz>I)|LAJ*{pGzyLY2P2}tfBu~hW%MuFS?t!|qe*}NJ(^VQPyh{I zVf?4()jAuzX=wf_^dWV0 z(ul?)TDw_z#yKWzMBDZQp1SxPdo?vhH>@at;SY?|0aU_$Ts8R>6u9Bq%4_d%&L@AM zawTOpRgbnLH=zU<>l*DN(=6FRP-aBuZ+y%AAZyU)wTUqW>wF8;e~mkQzUN%T|B9}F zfdB8IrT^@Rf1os(Dgfs>VWiGI;xJ_2c(_M?Dg5*c-JF77L`1y3%95fG)1a$obI_Zg@%(v4=_M6i%=vmP z(Xnd`&;2q9!U+w)%HC?pb{H=0gLy8+TZVEZ6&*z|=@i!%EnYZH($WsRnWr?%?0}gx z!tYM=)JxdgGG>J~<_F6T$S2w=q|prlG|J*-wn~i-9~bE8?=SqOPPvkJ!aG>0 z4hz#)rBT{+GHS|!3>Ik%8Hhz{wu&O@kHwoSdy~Vm6Dxi-Kkv0+Q_&^j}g}NLJ-%>C;mBxt>akX>1b_5u(OTWcH43bd&WtDS#_eJaK5bLDbj%2HjlIvkZQ!&TE93q^^> z)Jqjf^OL3a9zy#XW#!OP30sqd-J3JT6-(Y80wc~)J7MP1wEiE~z5^WVum4|0naLg% z*;^>P?7jEM9=E+WQ4z}CvPDLj*&}3+>=3ePkXZ^z`k%Xf>!!ZX?|)y{=gIY4-}8Ep z^FHr!X6btd`B{!LXt%7}E@z$#4{kC}-po^VVsF+d(%?<*npIBKPG+1Grjbn_l+Cnp zEM|YZYWsk8G-yD+zsLIe0x@RC&7~S1&f>TfO#+-p&NoKCoWfk^?R22`o6E)t%VSz# zgv>Z1eTYV~%~Yw7d2X3HYN?H1{~26P_l(nu@~ow6zM8P0g3?8Ux%b9n%19Kv;rh?^ zhHmhkSJmqqbB@bnw{_!BWMC;%DzQyfz*BHb=hCDykM`?-i_&sU`Q(MER5$k=-HOzn zl-m1{VYvZLyi0GdESKG#mG!2X^Yy#6bES!UM??6eXAwlL*&V%a_UgW4(wv2Sf*oHH zBu}D=Uu2~jt%Z2RY&dT&G-PSIC+Rp8ij1(`-X| z4{N!e$6X-EFW}3}@t4qzc#efr-6cM9zqVYtL(g2aA~oZ2Mhla!0^a3O4}5;gOo>-v z_;HPakWR5FQce3M9&O8UiQxvm^Bv( z`xfgr8OEru`fBZw7Vf~c(W7MQ4R{HHkHgQ$X59s!MZXv;oS#_Exxk9@zPE*?=*c1q{@lN}M zXBjAYk&<=nc@UAuX%-$i#@(*1aKp*@%*=>ucc<&=XAvIoEIx4jbTX*q)R3HqFpu2o zH4(=TQ|I{86=k{7yDtkbb37;e^rG|}Nyhg5bG_9?9z^TMGTW9CEzUM6zbhK7LiHld zBtP~3CfR5C-I!MPIOgt>J?O2f57NF+8ik$MAxJmCDUd4jikX+_mVjyAr8_f7U5rBRw%1 zPN+BQ4AEK4Fh6#xSW~^3PD2NI_QCn2`D60I1LaS-<$OLQDWJ*cenx1k`w*qm9&fXc zZBr=iRMm{w)gb?_;7(E0g>s^s$E@BWwSL-?Kwf07=$rGga%4w&GdJC}vOcye#RDEg zZLVHi7jxQJ)Qj9i7J2PgwG=Us97E?UJEno{B>1ocFW zsSd^#e;gWdX_%5lhv)+_g@ZbSZ>>M~o7{R9w$)hdq<2CK`e%ygYCW#Y#YNx^Vnttj z^ho8)fy+9duOepaf_3dL;08Q+?`1ikx3xEg*qoPuZZmhcce0kSgxHvV3pHWtdYa%J z(0Uzu%LT$y$ONYdgg<2*f2_=?6~%aEFjL#d1M>ic-uUf~)M*ktLSmC4Mj zN@B|`6cww+!M0}ewVtfU*RFp#HjA6Kyx7vqgIk?F#F0-GGU1dM(_I(N-zklhI@RVk zIUN%yUh{%;@=oOm(s*Jou6OYdM@hnoDtp{>jFJ_`H(CQ(WEwK$%8;L234hto9!i5P zmaWg`a=v=mFQeFy*EqYjp0-Zixi=@q*H4FIl_GC+!+>c5HQd z3#i4$Hh2-XFD^Ul)VbG>USGIvH*7NUq}hPtbW4x3=hUn<5G}jA6LXwB zalY$h&3?{Cd;q@0lzJ@DkRCfaH+{=ugMV{CWKi*1T}JDP?Kwi5G8Kxebrx}Fhl;)Y ziS5Kqhn$h$P~rxb^=5n5Rf>=HXdSx*hXS~(#m^WX?C&0D7=g(*C^2h`Q8~5 zo~9DN4$?G-(1izq=4ZqUoaE*hBykzSH>-uB-3d>2AosDQEVIc52G!Rxk5|$syY(?? zRs}3@2e&xn5vVZ+$z-F6uqcXpzrV3{?^Q0B)^zd-zag>E^5!qb7OgR|rLCXmaI%YV z?elZwnMGH3H)s@wPUl5TyAHdlIC(u?;=dux$19@fDYht@yHsqr)I%gDFv#jhapmfu zxV2zy*Lekjmh#g@_Z;y%5I(r16kHrG4LtT5QgOm~iL};gaevHkMftU8aL_3GF}#?U z_HVz0N?{E?{350E#W4kQk7!9#BJuvGZBxm|!V|WUi%)nIis+J6WRS(!#THG>tvIo{fS8qtwYFlQ`hpX4stNjB+>tbM$5y^2DX$VuWf5Uqzx zv`v{t32%aNhkm#(Y$=yG{c`2&!zT zkDiqhZ>lpfT98re@zi5DaZI(HC6~{GgpS#BEYEpGp0x z;<Mn`cLYQ8*qy?d3_{R&rl>x!VIOJC$?t7Pseyg_fLCrWHY z8us<3T18LdTR!_rM&F~AR-Vn{E#TjPjIwq&kl#(34dW7(G9!7aiq`Kl=QyK2G;sCU zg&@Vg3j<-N_*rEo1H9m&XS*z;-m(*Wf)>a>T-XL^)?!JRBTMG$S*C25N zg-X}Dx5#@;oYlRSV)D7opjb5rHeY$hO7Uzbe|l}tX6_*Go2CH|sxXV53SB1wRqNxWb)+7Gke(W3@YIPS$M!8g@8fAdyeOiuptj| zv9LG&d25iWEp%VQHNr?H4|EnWYo7<_E#~O!jRi?63{d6e1|)2E+Y~XTng<~fD`(61 zndF0MuYG+kqs-lc$+%h1&CLB(qPe-5`?p;UXZcCAJPcb!smLHD{wl|pJyP26Y_#Zg z?z5S8=*Ei_J)$(#vi$Hd;Zbyc(W9BQ5QQD@U}C4<6URj7S}sZPt#}GsCTBc-=Q_F? z5ld9-l@&YS%fAuf@3Kv=pR&9Aq5}2meiWM59FEPMIa|-U``5YCV-#OTQjFa72-NLX zo$s|6Al$uCmCZ)8dzKZuW~;}`N-lAaq|xv(#{@SuHllF+o6N+xH)?|%!qY(}($XF# zgR?3e_}y_e^0sNNt!(eT3A7w6K2MV`g^z8@@wJh>V-Xczi9!GA=UGPHV+g zG*=sjS;|$^Tp868k3}>=_=YPjQ{r{00|{72&{7N#VPZA++b?3bGn&inyqUJ8XtLby z_eo{_66cnp*rttz%o&W2QFGd!C7WrZv!>&^NXt9iU!K!MhHtum(QO;~@^LY~-E&T$ zK7+H0#|5_ERp@W!gB5yvSnoiF-VW_ji;K@O|39rD6?eR74`QLJ|>QWH_V8# zoNXmMhM$R3m$AQkVk72$KktRaUVYrE&o5UJx9je_u3LAWcHaM(zWog0OtT>6VoOY~ z)NBZaH-jHS19M<5)ed@EkkVd3g5Jrwd&$>$}F_IUi6a3+J& zZ_njYaviG+%r|!9^&55M^yl_p?e`y1XV=A;doA(~s z=q<<-M+qy`6uSGfnSHo&b5mmbT3D16&)s@c8f+NF?(Unuy+)NiUxc7C<}jukYLSlWH!qpk=(L3 zNtfTPDo+LXXC>>aGByDXBc11yUVn%o!r&d^BK$B(gMw{4+4&&Rlk^O)4wKAq@a?8S zW(lI?ys9e$x05EGYj>pkb#{eV*3S}~O`n|OEW^@kiR@^y;$?}U{5UbB> zlO=ZSR_FyLl!LXRwJA?7P*A?q`+yr=5N{VC1KBFQ(q4DhJUoi-vL05{Y`2<=ha@4y^$?tclr%6Puo@0|EZ{{`8;dCvIO5OWOTNsBbGh z7KSgFHe{o7sxrJvd1%QNjq>GnvpE$NCwHef z2k2<22Ty#WJ4wF(Soyfs-I^`5@UT+pa(V5soRDp0-BL}TkghHGSku6nho!V^Y0$EGX(c9I_gyF5?pUg3Ko>XtD!5Z zD(c9-BD}>n_yCtvg<#!;#UER34^3?5N=7OD#KO(wmu|z}TCa1Xiflq->{>3elvJHi z+aoa-*$D~mpVLLX4oSCvsKK~TtCDFHc;_lXle+iq$N5@9`T;?H!3=WTue8}pGV`uo zh<^a#zE<#dYhuhtA^q6yg9h8r%Qd!T?#Rmz2++OKVy26pcR$#Av!x}KZq(r-u0GmW z%fK$qbe`UCm?JbRSTa13-3&`_a(30V(KEjer8ZE!|5Vtne_Eeqb5%hEwN9!+hkJ8E zhs25^$8MkabisyFG09f8%G7AILUvmGjLI^!lRbnI~Y)9#<3>>{A=T5}(GPy0A&<6H;5 z!7HKDeq$|??)+r);5~)Yw;Yip%dUC7ln=W{yy2bmg8L!MN3JBhowZ6?Bi&kMJ(T|5 zp&cFpVHTrHA`ehc>xmmOj!%{O8KO<()l+BRsm@=z8DxB_H>?zlG~oaQCHNIoDjMl#7r=7!K8K4}SJ4+)d?qmUa8anHhxBi?_u%Z%DGs zT+H=O5#f;NGI2Ve%W&GDBma_kUFcnU)}%4{m6d8gytA^X9d3Fpm1DN|bdJsRW@yUU z6+idQAJS+}OSUkOFbIe_IfF*9g}&+I+H3OEt-EJRdDP*H&h5t~6?4Aws%g~DO&7%z zbKK0?6YqAilHwQ5^wx238gZlbTfVVyH1F%c_DUkLiV7g#nrKa?TfuF4g87yNIXM}%`b zMl03l<@bz>7hBJfOTR1jSHR_UsK1KhUQE;GAntuUd@U||^r7P3+N$i65`WeQpKW5C zRv&*kslOc|M|Tw|(umfzJ-tn!$4IcWC!uMYP0`p)dU;bI1ACS=1)`B`x~)CaeM+D^ zkte=R@p7wq-Slt?9-5y*t;LL_UzbzJq+Z}0S3Y9Q7IKV{t(4X+@~oRdmuPQpY!%L6 zcs(JT(s#(PJ1^zja;!L%wNoLn39_=jk5DgbLDi=pkxMgK=C8Ct>gQ{Zt+b3890ceTgL z6t<@~NLKi?rXO~hU61Kyj#Y2crzr8+;$yjKYCnkNIgCw-s??nEMy{O;t+W&U9o8&w z{cYKI+ZY})WNhN4fnN?@m3w*4<)tymN?Soz3hzamA6coiou!MVk&UI-*C%1cot*5Q zzGV(^syZMq#orI?res1@3GrBJ!yqJ_sF>D&ev$olN#G(<+}O^=S*be%Q)X_Og^!=m zl7>ord(lQn##g|F-0YQZ!+Oek&r14Z!D~ob9VU3kWu&Q<6&g8|oAhErN06VXwQ982 zBR?Z4ZHPR%&KdCjY`;(a=UCr*Ln+P6quAg4d|ni$jg3*pmMm2(JZxjrOakW>NsQIk z&%TAc31`v|{KP`xjvq^*x&3^YH+R2_jL)PgO|-Z0+2!$)M-(^{94>m%=IeNh{nNBW zXl??VH;}E_^G>j<#R*D#d2FPQCE2W96wZ4sVrixnFkg$?ve$$8E<*IQughe3J4u58 z)3~Z*lD8zXI@zut^$VGoOZg0nyo!%cmCXf|vZV3KxEr-MKEvk-;GI;YxXC;s^U1HJlEVJm#8t=tqu1U>ftuZ-bwmqF-_btAn zH<+`1k(YS#u3*#M+_O#U2|U<=v6W9d87xf=hTTrG^Tpuu^~b!%TE%%TpO0;(-az3b zrh)Hy<@~_O<~Gzg>K;hxyPG!n4&q;AXh&36Mi)~ueP+AD-sp{v5L&2@q)`>U)n?kl z7@V@metWh=U|y1syLb>sk4AJPd>JD7p;W6Cw}j!@OA6~SJ~eI2WxCKQ8S)^3K6w>Z zm8-HQu}e6Rq(FC7)#>KdIV~GoB*$eYN&^YCKsQ3pULjj=sS8Rv)H7#&u6#UD*T0mO zGI9pSx{Hc{z;#4jFYjvOV(DN5k@)s_@qv4tPIRgpFb}Y$i|ZxsQxP1owAeawD8yxJq(oBi_FXg6!}JiO5k>0=*3PRdd3f4F$Ss@hk0mb#zoW zQAk!hOKnQ<))$cU1!5yHOr#}I=kg1cg#~Ga89Ene{UjH-XqSV^7ycDbvX4*SkHr6_NoZyC~Qmgc*@>8ieiy^6QBnE`2*#(Fn zm-`lT;y=jbC)Ky+AV!5&NOY<htOsrNCC~?DrtFjzpD`0^a#wI_HrM)5a#1g$bG@xW78ORL zy;X)E`!)bs#}^54)@Yenhstw!%;_TEe5*uCwV&;Z)R_7PYB8fnz@77NBE_ohp@O{Fr{56T79QXGuT7hL;10#U?TKq5fIyc6|HGTv28WFH1A{v~4>+Z2Aaw zCGTfA8t31p$CP({a(8Jy{jnF8ffV{wt{DCexl*ejR9nq%NG~&LXobwYK|Altl@4l| zTGiAy=RQINp0eDSNAZeh9mG4;h=RG`iK@G$s4V7TvE)4>7;#SQ>Knu79a5ztuMvE% z;(a<5M1}nB-Y3-k&;eE4<2bn$Aq`nV!8l$OyODQ?4BJreRj)n1R8PElGjvEl!(N=j z371Ry(dqZ`8h+DRc+38Hf)p+{D#?A$hL5aupZH8nAUJ0g8cbf9m6#Lv`HT>yn$R5T z>c`voy99IIkv?RZq638~{6en!1q*Ke0>H(5HiPK}Ei zu##u$2~MmT&F;rM{&Hrj#SqJ+HNrFM{@M16%Jm}r?aAjpUL4#f)u(I6eeZ*0zk7)w zk5`O61Z|S?{n>;pT;$Kpy1Py}C9M>F7b*va{L_UN*=uo|L@yB;ru2ui#pW{VdAO-0 z3U71^DojU52F+YE-r@LITtc+D>{nacx>t*!`o6z#Kvgrt@;dh>HtcNBNe%=a3vk3f z0UWUxIKqu7*h@md-O-jNYMu^|Uw5WxfKY5|z^h*rKIkCT(`GJ@D3%X3x?Ux(s$P||>+C?v^Y*du*Ni*|!2!qT5zj z(|ggjwo(;??6nq27vAN(inX~y<6io_TP}LlCppYApVj?BjxKr@DZ$g1V{ESB))yU> z?tP||T_e$kSX~-*e#v&8TVyhOlArFx0;{luxhDs zo-YuBekNb$^_dB_O+1=-`Ks~OZY-Xh%o_v*w9M_qimj#bOBR7OgiMK*4Q2$-KIqDk zy%?)K@$w43dO>sa;B)k6YCQC4DZGt1O6-1vfi70tF~R*CHH}N|qoQp@)j7s`v{s@g z6<=;(_KzPIc#qW7po@~GtxH>ULy%SWdClmp(BgNs3m*%2Vi9aMFTZUSFt`<|!Tg5y zGUhY8MyDDHyhmdCD3F<=-PQg&i<-%k zAF8CVKXRJfUeM0XBA_03>*h3^yjTe{ncRy66)W?rSmI zEX6iXAZJUpVIpL+za1g={?TpQR>UvGwT`iA&zCN|$qXMf;J!YLD@A#mZ9&oKhDGlS zuG^dCcEUtYQ=~t6(A4q>%ok@gqV%bA%P^44uVi+=!<)9D)1SOPSY=w5w2Rb4L`>!p zHgI!PiOhy-@>zM?nHujTUTam}tV#z943-HCpMVyD$(dGyD`cL&&rILApCK8On4sNd zu-X<|#XmbG#xFidq?AoBqb$jJ?6cg(0qHzF8_dhZbWIF|c4^YrRCNANu$vxc~8PIpN{B-HLrbpSTNBQ+k@_>G^Hw57&tJn=BCwFe$95lSx=!GS5 zlSo3Ot7zaxfo9}~-K*yHyTlfPqdq-ryxirH%A zji45V`Y~hK?Wy**VNTjxXQddfP*F#PeYlh->Q;g8YyFi^|UDmo6&goq)eO;?<1?E+SL~t zL8^W7p7ti{;OXOu_s?FDN9a^aiZm;EahEh3;$1-y{nR=_Ctg2K8ZSMe8&in-M*dZ5 zcx9I2YUVli$ThyKM972}^E@7jt7`|=d%mOu8J@9(xQZukX0^@taTIlQ>s}Hli5O@t z_Oi~$2?>@-R%e8(=@?XyElo7kig=eiFFA3|;#PCUgAC*ku?|Hf^K1IYJoLDYcrqDu zg1ZX@EZIKy9+&fp8Hh0CidDV;&aRm1YUK?Cfr&GncF!n`%DF=nF4jyfgvW`9dh##3 zhZLUwtifsd!D@a&deO5bEXuX8x<|ZhRe%*T^@39G&MEd?tI_tG4K@?cuiUuKD7SC+ z%A~hvroKGLGT(~mgJVmw7FNsatVU%=O!9ZM>xTM6DUfhUf_k1j$}nNHu1MuZqq2oj zHoYmX3MboVdKI?aX-}ErS4qvf+?jL>8QIje?n`y9aZ(hknp!{>9?<3_-J+gTQEp8q zU35RLvK0K1r(ML81(FaFSV%PW?zv%}MPiXzg2EGrv-NecPg7#!lZr@-$mH_3Qt9nj z3kGD`M90w25U}R?O;Hgl0TrI%?plrizfM{h>_kS(-=!Jps&--jg%?hScc$PG+R$K+XievFA!xaEl!)zz`XaQ7XO ze?7}?-0}(UkaGcqYva$o$#PBcmDg@;_0VSZ5K?X?-`+?6Sd%-|k-KAeOhKp}VYf!r z$4BNkf;KLZFDc0r)3jD3LG86$b$D|xDf%;Y`8me1TA$h52q*TRw9SM}A%zSwE1=93 z^{Uo2ZeMyFhMv}q4?z#YT*#8lX>ng$b>a~Z9pW?=ampdIi&x}gSw#tBRQCTY^opo+ zoM?=wNs*^Cpw-(ve-HPKckKHu#V>)C@@G6!^>VE)Kad@Z=%&8-DvEDWbmTtf>?A9r z2<3g7*R(j1eEoFmijm3MMTpW^QWcVH+jXzT`}cXSy!A}gtazmk$s?^t?@~Z~H~E(1 zINDBBH1Vju@~!Y1OxXcmhOMr-4|OZHUN1(~g7Ijj+o)^nD+I8rz}>i;<5z4^wWx+q zX9=$eK(2~kvJzOGK1Z=X-d0;VuFy*pvG(%Dn$-YTmz*2@F0S7BfwN8IJk`FU{1ri0 zZ*0Hmq_#GV=H!s(J7aw=rXUK(TvMdeyPf=&o>K1h>Pm-R`#HAr(*0p8FE;Wwo!)yF z@IPY_YkZ0b_ zI;_?AkA6O8c$1;UpMomO$2F>ADEeXNc40MIQGn&nAPJQWOI3c%oxUgcr?2`elL=|K z^l3QdirA6qT87w1>D?l1E-k~dPgO>$BF}g|S`?r3WyycseoLvcloS_{LZq60EBW@Z zFC9{sC>}OOH5_=}=oGmjtEq$E=Dd8TX2T?+tgk_WQjrxR7C5cEdPP{ zc=G#NH;#pn45KvRHx1-H!Yg>DY)nPRut$i83$9#{q)0>Z!;!tFxxG_w-A$fuzmCA_ zfPXJS+P?)=Rm3AZ%#P51ziTP!ljCI$u%#)q}FG#bxT9XJbmxcOe|lC@x8>xTNhjw=yGAnObLVod@fZ<4B-qG z#1TeX7Mk(^5lh*ONIz8zhV1I{a``I{(R>ju-_73k8Tyn-SFhMC_$WV)nIR~tcr{nC ztn7mQ^wrJB+xv+=uL2}b9^=8g_4&3@aj5%_azOnE50QKDE7rlfp$M-!+4d=cx(RIZ zwYSb2mpQdUuUc>DPtqkZkgVewZ+CkaEm%YY%m{<=RTiK56+JmGRoW z`47T_SEVeH2z%wQ$l8yQMC_CxTy5(X9=yc3z)o_@|5ik|hlpGsYOmt%2K(E+YV!0( zI>;p&{Vj|*MU0yf!J~>nuZB3%qTZ5_3oLhVcq?G~=wCG0SP0pP4n5z!6O6pR@g^&& zOUh#Gq2AO3H|mjLsaw3|A|fAzjH$Cpwe?~K)Go~sEagaTI;5M0=G@}AZ0Q4GjN?+H zic(NEsHaKi#O(?fa81d)(@(ag+_>1OLGcb5#cUewWbfTji#b z5k=vac$Pl5AlJmV(dXn1tLZXmWK(Nat{Xouhv;m%(a?{}r!>i1S4#)-)+ z_lMgKy%%=XiKYrW{nU}OMtTHqev0h9wUzhq^F;r6#DH3^l;L@aTlLm&)Lngo{9{;o z^ORI%m8IUqDa9G)Ub)X*f9Di)*}!vRmODd9$rt0sx`xyc^oui=@}iyv=$Tw>8gG;I zcT(ymt})$QdFaB~f82D`<78|NO=s{!G>7EjjEp81fqBYn!{wB^(z~~{3g~4tE*Kw| zmyPU@L(AjOpcidDj&dBAkdP;bPv7Om+04aES;kZEuC!B^Ypm2Dk0$W3&K2M~WOiJ% zh?jGm#y**}z$!q~8h+0~4n-tjnv*!+g?uZIjl9EN#oxB?w%M4@aG;HyF?#%iCr=%o zy*4Vv(>dQ;BV)+&>~s1CF++v}24RMD_57Dt(&5i!9+oc~T2|k`!srVQxM6tKgiTb& z$P%wFU~gSNagu*xIY``$?Xp0EejHcmdo54085y%a>v)Gg$98|OH)yLuZn{Ig5K^N; zE+19jXr-e!%M@f6Or zw$0-AOloVhN%h8W*~OS6?wskaq|vx@9)G#H$u(}{^JKKlOcre!=6}2SDJv= zk-4a16`WQSV_YE_-6Ne>+Up(>9?KbUu%uy6JF|FZ{@{09@T~yD-2GudWRQ|D$ zm}b_7(-BXwBt`FLIx*RANy!bQbQY{A<{oc-=TSVCwc5aB^X!WdUw%hLntyfFFz@!A zp#TmP>kakktj*xjyhP=vNq(CfDk%A4Wr%v{4S~gYn<||jqE?7Qo*zq1z`)C>euxvC z|3E2e1cy}J-D<@$!>@p-{c(mNB0s)2-c0mcTa=lmRrH3C^(ebwHl+>bhVygf=n*s- zdneE<=W$U4TO+7bu4vQVb`^|&i-%(08isx?cnZDUF~Bclr?e}}Z*<<3 zWB>lF;!c@AN{19J3d6B=gN+ow$LN|O9eJeF8Jm{N2CmCEq%xQRok-7w z$)9pwv(FZ>>MWQT@JDsx;*I6&MSYO7wuyZIy6T2I&gAvkbdLS(*%=RCG0z@rt`e~Q z??MT;_KBx&w5e+?xNgPe4hmJrb_DPlH1A{5^PCJ8#3q%M^pptAOT4x!BP!PE-6Ozw z<{7SJ8+gGngGhJt)gAZokEfEz1>O~G)Mf}-uFZ26*Y%wl>SfA(nuJfv^nh*oiNPJk z8sW`uQEAiT5+fP!{kh7m?(kTLbm?tGg`^80&QGg^`hOH6!6oRnGS_=VJsc^G$r<&e zVASFXXBua)9d|Zz%8&*t59_>CG`)FUO10)A%6!@&SKBoW{Hij}h-sPWXctCxwKC_1 z`er=+Dg~S2^v?Gj=SS31I%^j4W&@-WCz**!&WsG<%?~{l%j1eFp)?{2u3mbdeG8Xa zbjtY4w07HyX#@+EihxNfsmr;^iCO{-M^%HLXFiB!VmF=kLGK;3?7TI(ow;?+TZc5? zeD?Y!T+dU}B*SNJP-YabB3RML8PoB*;-(4tT>o@Y;dafSlSVpg-0HUYLH>$=ytyjJ5!InnlQJCmf~BX`;qbX!o6elS|>>EIJsTs zQkvi@S``(%G;rUN>Z*Q`ZDW83$xAz~m#mqSWRhzqCG9Q*vNy8Tpng_AbDDY&`Rw@) z+Qt=IuA3h0pL$cuUOZy3?{(!rHrXuLFT?L`Bm*wwXEM1^_4u<=?!?Fvng`Z#SHDdgU7YV$)I- zhN~p3bc|&456SXsZehsxOtv=kxAsuEy__wJTkHt(UBqHf&6mrfjICm}2oEs2kQ%Ue zn@Ui|6QdrvqtfJ70GVxV56_M`>7#pM=ILcR#Wl4ZlhS20FFh6{p9aMnKMBI=4H_iA z`rw_$rI!UZmspuB_dVxI3hR8eZrf<%Lf)q82Gm=GR-SD|By?OvAgq0;EytW^oOHf# zqWHonW|GFua;800ZLc$e@d>wO&A?>flP(o&yWzy4Gbyh7o+xELk5UvVrf^el(hTuH z&RdQ1$JI-Bt}#^WVdGPjRv<(XcEk{xhMdBo@)UD>Cpb5IjXT{=K(SJJF=VSsFd&fY zUAJZOxc{fzlY%qx9hm`@O+D`i4Ftv{rLe z$J4jf_}F$bTqJKIs`g0~ZiTJqXVO0Xu&K(?v)*{%RUxw}bMzNR(n;Z3I@@F6S~5j* z#Ouj60nwb5xWWa~xpTHQQ*>TKw_k8x$>@LRfLR;MGB9aj9lzlfo%J&QNpFZ@Ps#hv z(|d!WqnAT1hAYZ>l8avHyT^DIGu)m#qmzxzSsh-J6p_K{RFBtkdTb$JdRi)?K8n_w zN?_E)qO9tveqG#hP2A~o0w><-SUOd{qpcf%)uZvLQ+2iOb`6#75YN=5X5+NG9RjTy zL1~`BD99nvhWy4(SC!J*Nn$KeYkSuc3Dp%cC}_!BOIgCYQL@uM>vo=v7mdcChc^0;u&41P3`nK(XyVbOj+eXIE`k+G1mN$)#X*Xq^DjUR6DYh>rv^da#acrzao?IQ;oTLjViRUw@|% zR)wK|$cw89vq&pQoZo+f0Is$B(G(TI7Bp=;z94J>{v)Wg_|X6Q`!CBEIxG0Isl2d) zw1l{-8mqj-F9ZYxn*+qbsm1Rq)@By`{jCke!v$jJ zY-w)?Zs0tk`KceR5uhZoL6!Kex!I2sEJwBmD_Gxu(AJlKws!jZ>gj)IYVotF3t-&U z5~iuA!!&fc|L5;V4;`p zQxkh9$dT;{e>DHf>?yF{2FmPD(w27MH3~Z;nBT8Ha`VVOTWK@hWuq0qm z9iqOUOgg(dIM`T1oQ@VA4+hr=2KS#BI|Bm{4IjYx+mg!BtiU4mz(=w*asktOe-R26 z={Q*V`K7F%LODSkU4c6}nkQKE7diy#AB>CwMopea1ARO2bW|XKg{wXq&IwG09xWy< z40qc{!#V$$d^{Qx*0T6PwEWcx|I~}H!OjK-;O`>AM%ttUt)b6+AL*{3k3xO>LH%AA zyymt>c9ssVHedHy{s$}+aP;GsCcejBJ9`&PGfUu;K?-mr7HohMhJ$r#G}f zgxmh0`Jo~}W4bdkMKT3&XD@+uVEjZuK*;jV1t@aTqT&jw;;b$nF2C#+^=r;#c1@{Z z8${ygpfNp6!?z$*{)hlS^B-Xo7fUw?bb9vN6&&o}CTI_$8g}Fd!~sMikQUOypt6Ge z;cuw$F;Q|%FO`B2Hx7Ic6%6JHU`~Hvsz4kdAc~qodHoa68l;P3dnI<*01y)ZQo{i5 zg5mK8AQVUp0+N(p8-{)t8;Uq|>*d-@piEOBIwcIEEXZBpBC0}MTpfO#PWv4Xns+&D zxV66lcvyhLb1--gz*G*$`%_*hTG8=c6)S+^1wL2>CXm8G`?Ie2ojs_y^dBBPEJ8y- zzyr+u^6F5d69umM8+*T!Utwowh|?im@#KMfWF!!@9(2dAU5C@vD+pSYs-whl&4md^HeU;i@sxiRb@Y{E0nK32f0 z8t4~*^YfSG>jI9l9~Ar-?Dt)?@Vf_7L=pQcaAhZeYlQ`U&H5+kw-@lBHYsds$(^r!N37K>7Iteu48JKt+u}JU`4j>%{O4oPlx!!Nv_B_Rn9IZwt@AV#DWp zPxJn=5a8Me=oi);Zh&2W2le|)6{1GYV5hQ)ktyU)T&Tfv^h8W006rgskK!l4P;)>P z{u5Wp$=(HG;$mcMa|qn1fCg_IfT;!_7(qXOS-vxH;NUwVsFhxN+`Y*QI*1qe#$TZg z%2t8MpKL*Kpn}2|k*&v(Lm9Xq9^m$2MWm31k9DX~LN!)yleaYl1k*Tn(4&>e!H1Kx zbOzA^o;^bG&JprHHVDPbZ??df0HP9s5OD5i2S8QVu6PvQ zpUQ)Fgc?;eVG!W10N5S{44RB4e6%B@;JL^xg7%XL2>p}@2)~LVD08^lN5H}7ZPv?d z#1io22|j@L^OxmIVDTr|(aswx>(I(<9|q7G6$k~evNrt0`=0-Z0BeI<-M1Bd`0OPo z8tr2M)wO{SmOWGuZ@vxL?{MFt4mT7id++;e)!YG=Gw2G~v84*8!eH<;K*a%q0err+ zAgA7$0cE*?54H~weGcIKU1!hU1$18mDa{p-=$-r71JDl5{t5Pd(&d}kDmi_vXyCJ^ zd(O-t1_UN7kQPG!gl9s(g7?{FrD-r>-+6+zlU)sW1-^+S`2_OBmfA@*!}baV1E^|0Naj!8FZpI zz=O3{tc(L#AVPu6!V|uL!?^b@F8~~!KXBMG58xcBC||T#n_z%b3_c3*{rF}1%HBJG zqYAMx`zD{UrJXr^wv2+`Xl{d{Xa~X+^$#rYZZLBZc^DfH?$$aY+Ru=Xsz> zXl3}*_P=uVU2hOm;X`bU^$zJRXt28sc!RYIhH`j-(ud&O2!F-b3p!v2bO7w2Osay9 zBW&mCVsU7PKEdIuzz2f10lr`dQf@7LJaI=?BOCY~;BSUOo(!0S&YZwn$4&!$Fljq5 zQDJ8SIjkQ_R0PE)zo3N9Uk*74M9N^cpP}K=ZE}^ypN7M@p7<$>tk6)JW<-WsU zVZ8}BVdHv;{B#NOewP5xY(SUXKajz{S-uJb{{j4H2`C})av;bcJO>{M43U|q2Z$V| zUuZVs*O#mD3N&{G${>J&DF)f`uL&bzvqLK}i~A>5p#kDLfPi%box^`Xe7)54PqTrt z@-(9Ep$jM!7AX-Bel3VV)wVnWgL6o^4aJBeA$zwER4)RC1T03(!T}6dc;*Ym2+or} z_8Q0oP10a7+JL5hsYC=~1_CjBSpv0NiB|xIFTnUUnG2O=7C;}wI6^6Yv!d=x00x%a`U249w4og73u>^{*QLFH;9u z0v*E|K=mbHq*DCA2mgW+bmK@8@HJS5Ses1%gof5su)UD_?sqt8bGt)(fpLKu33NMx z6TpC7czw0`JBA9FsfN!*Fsc4K63{vne6Z^O^!|4QXc|kcU~hK_jPpp>TL%E)4fF%c zi0sxu82F6nZH90h1Fd&~!(xZg?&|jM2(T-5;3az-8;A|G=Ul<~rDlg$Z9?tC$p6jU zFo0eKQR#p`-2D&m@OiI~da-pGfTMwk%mTx^{{BCM!-w|5_7gP#WBnpF0)j9M^s8gX zej6SzYWZyqQuOC?B=z?{JtZt{4s~_C>--t#KtFy2p9l=OEY$x<4jeeQaW#efpbB3+ zob53R`1GjJ|06wVyMLf3(Xlue2iyc6aKjw1@_`cgm$&)5I^oN6@2W=6CxGh@^v4E+ zAB6KC@ZnS#P$Mq5yMS;WAVVjr`C!nW;vR|)T|gGKceODEX_gAa$P`*!9k>kO_nZVu z=k!B|v3r1q3b1L|=|OG$Bk9N+c|hS0ABK5R_-~+>66OIP$_OKY1mV9S!`FL(1ocuh zNc=;952J^{9VY%4T==M$vhoS@02(y-!;b3$s=uL1fyp#bDjw#KM2l zVHnP!{#R%fa8v<$Wh1B*j-HY6olz5z1bqns&JWgZs6i2Zh}A>w2K46-IiLaHTd0Je zbVBVWJ|e4W5IC!F;H;Qnglb{_M>_C3A~08|^9wK=Apj0Ltfnp;3jAZk!}mZBRS|r2 z*Oi&i#Xvp&zY=Q=n!cnTFQj8i0S;?1YK`uN1xk|CkRs z%%I$NPS3vrB<6v4gC*fA@Lx%Me~tE_TX>b1)m{Wh-28(?k??;daRI)f+D~AFumBP< zfW!rut|%7!k0js|_#&7R4Baaw0QwttNV7;DPT>1S1aUhP8+&KS_bUSrs^?<$J()qk zGq9NhDF%l0q0m3Km53R+7%AC<5)VG#o*`%LptJeB033D%Fv$D|a5z&G(1H7$nE@5L z&J+gb4Z#A?&tI0WjO^dhf8NTVYH4m~rmAG0}*G{Z&XZ04vEEGk6k%9fgmWrQu%)>3|b9Xss95Vus&r6 zy-x}(tpcS%H=rFhuvZ?Hc>>!)&Tk8*Gm5{DZwB*KSCGa zVjPScUKlP)wf`qB;P;*dS|bN5Adw0p6>M013Z_*LiBvzwklOc+WYk~(@D#Q)v9Ld) zCg>BHWMTp_*ca4{mtkbmGx(p0!Ix|4()o5;AlF$CVqi%vnEbD#4)M~{mGRu}fXo|E zRKgmjsrmm%3cgIy&Jx#e1E&!W*2!QOs4s$2@L&51J~p~Oozf2I5=UTiuo);Sn6>yP z>_f&a$2F~q27pWskVRoSUB=_@$iJrGY;3;Wm;J+006T*(ibKv)s~_lk0njHJFa#|< z|8E4p-H-g!`yMi32lemyxw(x)fc_f6!79?g=l{e5e39);re$aWIT=6>)(1xg{ugpT zed8fvi!@T~q%s)5q9BQufl)0sShf0_mHh0>pBl9Eg02QY_qu=;u_N}TJQZQ#I|=OP z8TeqsWhclj{zmuL22yBF4KY=Ov-k$>G}rd2E(TyYn!pzd!AQp(_rFm29?=fjZj$`s zR^l3m>BA$+JWEB0xn^;H_#+0^l7095%yVOMwsW?Cfg$bzxG& z(jIID1Y3nXOdyA>R6;4dHSd#zPRt1bQ-Cc!p5KK_;TPwkPT)lE?jhJJIH^*Kl6dLIvLnbHTbAu zY$*2uT>P&)a#THmUE0FehXLxNK~=!9JkSRf45EJ?TtqPEU~?2;%{vOnD-cFjK^UQd z0VFPf3#bOpMjT!5LdGkPa{yyN05bwYFp$D!a3O#0qXtWrVh}SUuu)#g9(W&POB-Y9Uje+f~x;YC1A511Zo9}ZUig_<4Mp9(eZBk?iz#5f)SjXMAvfwe&Ox})*G zO&uSNzIevH4FmM0A&>xeXzDlo6Z-dwdFakx_!grkCwqwmP#^^qV5eRmH6Bgjt1(_U zQaNZZuZ}?Lxf4J+u;3Ie{{VjRNbq5TSQ~2qo&>Ef$Y~%`(6I{7;`~{9`}90$7JU z5_)y*rllc(9r#1-RqaPZf8DqAE%YBr;nB$X_Ci2m1B@-$QrZ$E@^F~9{c!{UI4`iB z06M2}=spFg%Vo5E^u!bpNCG0z!;CWXo}&qfgT0A|rAz!>LyYf%&euVQ(!!wP^#2_d zz6JUzA`}FGI_&{)F|hGkdhlpWX=hP;u)qMePD6K=f>T14c5v6_q58m??n(IsIRE&^ zIHevvnu_YzeHY*H56N|2kOtCP18w62Ibgkv?f75NU5%Z;5;(Fq-?Hac^MIao1bG|m z`V0N!(fH7d8C8wUjy9H@h>Afvz&_Mb!WIj~vvA>m9wYhYU%nkGf#1El+N0HV0Q(+L z4Xh8KTsRv0+fsS%CPdyq%knIDNx?P}5I0<1g$e6VT> zT09#4=*?hIdsKVg5s?T~;){8(hLQ#;2OJ0RZIhq#`EMGxH!`(6WVMfu(Od}^AioEN zGwfU=^ZJpw?1YZ3%iy;3!_;9gHnI`~Q(T{O&htT+}TE z+H(iK6t<5_Paq!E{oi(!|APWC-_h5*11sqN!wM?V{v(A$CSoF*ah=UT21*GISipMh z>zMzI0(>2jILw*P10Br(9l?5RPNF06zaY9BgTv?hp_rPd3@Bo4 zu@6QAZH9k8TgY$ofRVEJ#5fZ@U2EqogLfF~nU2weo2=2cTIr@hEgPluanu!(+ zhz$Z_uruiEU`70|#8e<=U-M8mu%p7p2L8zwXw<(mwJPNV0)jvIU<2oX)RAQVo>1Hj za($);jA$3H{e^ahBZU313S6ffU${BpHheDG;<@rk$e@7x$H+mxolQ&W5hn!MC`*Hdp^Xpu~1y3)CGB z_|>KSHW7Uoqjn#yxyQd-ln4wgg4@5qe)C^pVCqR1(9+({z?~w6sU&}?~2-Nltm_O`zX9vaX!6Bsvu?0o8k&~x{ z{jWRM4`w74f(q)!Kx=`3MOgM;hQosd=@i@}5zw^b|5bMWF;!M!9Dfn{(fYxlC1eXk zF2k9dioaH)CC;=E#YA8xw2(3q5{H*S$m(i}HVH9O(yIcyN(PP)bw$g`pvjc5Dai)m z4MUasf7&w1aMyS+O9@N=H?Jm);;Ip=xK`))rzn0Xl5@4>^ew(h1` za$jk+uUf@hB} zXw)agN3C)#jl3_J#E8~^P>I5YPFuV!>gdwuXXjRdmH-+%Ozs{Q(`d=sKK(Y}87Qq- zVb!h@mSuY@iJX$N*ND@&TVFK}X8~u#YQWC?c@`BM4Z9fkM#Tm(l5pnXUtJUUx# zvOTqJF1+!7j!g?`GJyp5cD}H(a25>iw!Om3g1|gH~>x+RUBO$N?j;}bq zr8H8gjP-Hv8MpY@3;>EPs3}nYL^gc@aB?*~^kE+x3v;n?R()ie8`XHBA_IEJ#lxOWSUa`2+WWIVb36Ub&_yKzQ?^>Bw2PplO2PRS zE!9FFD*hP);tcW$2fF z9*r+6JnET<=~Rp96ov`w_*qQtSfBLc82C-gQ$9$|p7a{OVI{lW5;I;HuS*wr{)X-=4P)7RbgE z1$6XhF%8Y9i1zo5+5WVRF3~~Xy}!e* z1R|Pz4BKCJN4OPL!ph#;h_r~U{o{_r!`LHOm)Nk^`Wl6@r!^NjUV3gz*3smNG0nrs zT1we45u0V)7O8`5zdAvqSA4O}@-)!%fo4O<2~oPx#^khjL{ng(q3C)qv{CBA%l#o< zy{A+zrxCSW)yo~mYil5PJ>+I1q>5EywC(kJ>rG-=u1Rxli2jGV`C2bD|5doQw3Mk-p(S ttmcF^uNOl{7b$uY@!y_sLfx||C=~^{!3p8C(Pgqrz#2)a#{ZL~{{iy4ODq5Y diff --git a/cots/org.junit/junit-4.11-src.jar b/cots/org.junit/junit-4.11-src.jar new file mode 100644 index 0000000000000000000000000000000000000000..80801569a5b2a63019bdfdacd69125329dc944b0 GIT binary patch literal 151329 zcmbSz18}9;ws35BY<6thwr$(CZQHiG!;WpIV|3K9o&4#U_vYT2H+SBv|5SZdr%tW) z?Y+2{_K}kW27v+qfB*paUSPuy@NXYT01yCaVI_WQaTyWXw^0B9x&H!%09gJ2y>vRY z)c625{dkZ+o_8i6qk?g6& zq$b6b0U`iNsBfa&TC*Y*K1nJlI%QMv|D3pm*@2aEN{oU*W_pQ4N_12}$-0h&x{5@S z^m}4*vB^uXB%@T+W+1!06>s}|(6=^rwRN!kH|V9m@D274Xa{E-8)Jum1O4kh{srpvu@PtUe*^t1Ss)*8 zwRJH4H;A@O%RdqIA;sSy{!08`;n4mBXY6KY>|kzfY~!SF^=~i#>rM&(Gm@dcld-9- zgSqiPu@LJ&<6G;y{lmg|{~6K2*wNX_>7Q2pC*+mK`Y1lPpbF8RU?@yj#HaZShw(W;Dfz&hZLRRFo z1|mjqB2RANh{dmYFPZzWT2=EQ*^4hXo%{!7-GX4z#e@(P*3D2fZ`c9%XP_H>?KAeT zRQT3&nyLufvG_f;M#HIUMeqDn^HQdSd^n|uw?4qt+f)ao6Vwn)uryzDkM#S^PuGv& zN;6U5+LdFOv$o~>t48zyg{fV~14=;ahqcZUwH9)Bw^oH54G ziEPqMxUYYH;O+crQ|)V*{{hSVBjOrqHuPenwJibsYRoc5S&QIqq=#T>GHU1QV3320 zHMX(SRcL9|%XVpLiQ3aJ-K4U9@ib}47x2Hsm*3UU(!MXn9S{J(6&L{E*J1oW)KJ0L z&iKP!82wVj-*hlop~t3|4yN;-l1c`!q_>j})|&H#3G%^z8gtkzan#<=d}lM22^4CM zMR%v4cIuqH-1u7}RuFtCN~xRCyb6YOBeA@)b=c}?hEXuMV7pUzN@G`qV^hsdoDmZ` zF`XYqhn|gC1Ho3c5q>GPm|iSsFD8khyiW-(r-a2<3S~HV^6FrBO_-`_GfJwUiR24P zKs@I1PVj(PnB(G#>A^}JA;p*?ZH^f`Fi7}`>axPktKhmC5hTEwDVk6VSV94Ppj{d+ z5Ze)KzFokLQ6$!eteHXOvd7yr!wH|70yLpIDE1$NkCVyQ0xA%(is<(o)iSA7#}Fme z^AKFZfwJeG#0sD;r(l}Wk$Si48chY1X>mA5W{j`?SZfoPT_&D|5f^nkPrzQGbxxi& zuaV(-lJ0oB!9 zanYnCZ2hFAd~!{|>4S3E-Y-se@L55a|g2#)CQ1oul|LdJ%+4*E{E z4*w;&F_}I(gpLEsJ9Gyz-aLVV08RyRye;C)MW*J$+csf=SJy>&F<@#n34_z|$(SJw z<#tugAXZzZrH4tgtS^Jqkpg%kl3DRN^MJA`cekVL#5x-RtcP!4ONTG`Ne1%Dph|TC zq*m1AUqCv!{C6$foYB92D#N~j%a;#m3Ur{EP~H z1s_7PjZ(u!3|*}lE{%1PtCdWLHuk)SN9H!v5eCD?M|D|)kVTI^{}-~TYwTUXS-9#TQBozEb1@?+mY~qa_Y@3Rm=G5wkWLC8= zEtvI%3#{zzp&R){eRXQ4A5#dvd$Ek^fyvhOOK9@10GZo~ZNWk)1LxPt9n1KaS&COl zH%$){xkqk^A)waX881K`04eI}5*3@3V>f_|#2ReKo~Gv_!nILX)P>5BVIFiCL0ZuR znkf?`Et|=RYf8ZcxGq)(*k6x7G$f-4VGzO2Otia96bbMLms^gWx}tZ<=)GYZoL>An z*>hbl@X0F^WB@8|Ln>!JR+T)fN~MY=yj>*djJEZ0?r_f76_dszC16a}STB1{rOlI$ zw>nY~Z4qYK4Q&N?C8MOmud%T!X29qHX{O`6m)-VUf#M}abjgB6tLC`$wIpvl6e7-2 z+qC9=4|ab;#q9~~UjpUq0OFUyALf?(5Tw$_^SAEOPT$Z{-_)4e+{VQAH<`{Y&F&~n zD?pHq(vC@qQ>%zolZj7Aic8CjQBFwGjEql7j*n24D~XNKDqKKKj8VyxF)mh416#}- zP<&*vGE%b2!xW$q$NtQyz|6>+z<*?@zq@bNe$ev*PyhggkAVJHu==}#{VSd1cXTv% z_}yJW+dr42<3PdF7y zT3e>fGZTUfb(~BmAemuI;EJOU#&b+5-xiA_*S5Q~TRhIj#<|^s;PEShdVmN^QX)%J zVBRjr23k`fzmCjcKDUQ``= zcqmI4)bU0#*BM@O@xoP2YT#qWYn=)0VP&z&>;rhvZ|Rv{6xy+L8^dN=MEGw>}l01#ECrVv1(YgZYY)hSrR4k|%6L)s1QB81{g1@bSFdCms_cfIGM zskR4C=Q<{2-priPN`Kn@S=`nW3?i<#PH~7yno3D>Gtm!z)0O@mI07tz%vu+1InzCO zdjiX}Rosz(L95PrROJOH>CJ03ZY4~ccmk(TLbnxM3!j>RBes2-PNr&qM=9jHaz3|C zCK17g4Eg@qn44DLJKF$u0Ep_5X4fIV^<&`u^m$*oEzN6^dVB zLDZPRf^T z-4?z@ZvI+zU;0h!xZtmS5|y>R!=Y#U?u}USs}U=CbusH@gSX71?DAOV8TRFPM0n=O zwZ`%~UsgDh(wz@qQP^)sl}*GTTAJ>29?t~oT41>SEHp{UC#fOGnJX0qDsm9 zE@Zve(YATE^A3@cHBKO#{$cyW}$K zZs^+1(w~J+YHQH70VdZ551+*0r|*>J2dFs~Jz1dF_z;@Pql(B^)3pj#`QcDrFd z6bm_X0bd362z(~bD|tFy&8^&(EF#26EVVmz*hikU50PxirBp*$H!O7_>I|fO1(GS@ zp&Ih*jgI*2)(v+6DSJfH#=%SP%ktylJ5w*(9j1Tt{Z+T5FJlo;hx0~ggeE(9XmeCk zTa#jG+yM$&Uv=@mu#`neC}TiOSvN5sM1oZLft%=RUpAb6WT|x}s#~WUgh|2j4x$>< zSn&Fnm_e9=>c#`;NpMZ#1Z+_L zUUyi*E8MGZRG2~z9x?59GezyR_KqS&U&e6Q4Mh#-vwaN^L0-oTv|)z^whJogzG{OC zxb)#YgB<+yQ6447svOxupizYv5=cb>Tsk#y@eOR|s7ajWHLMmpB=`LJ`fo?guQHj8 zl%ed}hf8n#h#!7ceg59Hf26M>`sP-~M#2sb{~hMVO;~({c|qqM5d@?|p+Q=fQshm+ z0yeL$wx`YoBJmRv70@K-8`3!Zu+-X4D~~223w#s)E>T~9SZg^8h~j#(D-BkS&F1yb z={(ICt~G)mLHm=eY!nh5w`h|$vIu%Of8pO%8k80}>k8+L*XhQK_kI@4TFf2fGevlo ziAN+9o;a!^1z&o`N&50bM=ii32hT>{u(6t^ru_EnH-qvS)BPLXC-eb}xp=|p+~L9N zAf`HGYS$#KtU5x&F^d#l-Yq0{*SB>d?8JwvyqfJq$Cg0@|H_U@@6tcA{NGPMT2pPw zu8$mA>Z3+U_BSjNw6(U=cQALfwfXIv;eQ9h*~*%>D|E;{Q?(avWk`sGPaGLCVOMhD z(hFPG8J|C44@1B;X2X^5bxp-&KcL22`0(`~+-09@d4+sOJVSiY-VGpO_b0viN;ssB zkacXWZiG)sP^>4PJsF4G)H~4?r3}&m3b=J36`?wekO#w1lZ%F)qBkMtf3Mf7!QEAr zyMzx~NGvYW$RAm{XTkX1{BlPu<>Rxg*O~6S36Y4m*55!*2mDyj3!}XZwav}B%#)ny z<<4Fhm9O39lv9tH!nk=2&F^l1gjjXlfhZRKqak!aj?DCPM+CtL;iu_P-pgX7FI?yyz2bj0CMW{k*Q-!z*iWnqBf%6EPfTQ1_ z1aJOr3dL|jV@q<9v}G`2S`+tV^%>FIT=dzv4cHL?S3tS0PB1@TEk;9RzqSNuV_AwR z%6p3Gt*KS$g{8MMr9p_xgHLsYwya{hW4VJ&&pdvhEJtra^fv()F&WTBocWoRW(QY8 z7Rt@G?W*fH{59v?-FnFY<_K{YKcmSN2ca#+m0$;<8a(?iAU(U|ZQnS4tecb7@&Q*dF?&?YdM%`5XIdNG&TZ%`h)p~xY17qL! z$kw4#x)9dLEcF5SaUU+6er;0mM!4%Wx5tb)L|t%pRage7BWSLra=8Bz#krv8_5ikJ z)mm`Z)Rr00L%(a{TX@&_GZGFI3ba)~vA!Jq>i`ZJAFcCh1qEXNo8U>R#*mOeFo*4T z<`%H`zl4ChRSMEN;jWex5S%i~R ze;!hXTM{^M!$&ASV(9SULgcFWS?%FE->d_h=fYy;$8@wBO~Kz~V^ptY6YtSn$7^%1 zIlBhC7O0b>QuHV_KODKfj`(nX=*R$9(@WQ}!wIAUJ@R9x0Giyj8)?vDOc0@&KKhPs ze$O7UO{j}MCll2=zgi3XcIJ{Tsqu3P=4SQurn2+hlcyRfye07tsw=@#e_H_@3k5WA zV5SV~DCrU7PaN6ai|E6;o+WtW;=^QZi1yZ}gE$?c&7HB-;_5D!M?BTz>Yt-K&2eISJ*DMj6wu-N={(-Fb-5PVYCw z7Y7*Xz~HCtq72S8I+_DtMlM9nv4;)*jjgdhZ{orR4X7Oc&uR1*d!>C{*Az95DjWc8 z4E|V2i+;H|-2@eoC*CsnyWqmKVp&~$e+zaTo*YE@l`SX_1 zO28e69S0klHDPKyg`J6vZk zFDZ|HJAFHw)F)LgR|L0l646kEMBI6P^E-tP6tPo7DpYu z3gAqi(L;h-DW7_5Eu;i7NwJ-g6xFU9w> zaZaN;x##nSt4@596sc%@El1bM1xWUgq}iK3@0ZW`zDt=wErnVykn9tST0elI)61{e zrTu9QC0W}}0narDY5W;&YiG`5V#eoL-0X8!)i0yMhrCfIfifHzHKNea#?Et%BrhJm@4EJ z>gx__*Awe3>Ys4qwCs!nES>TG*-8>-kKf`ytYq!ON+|!vGye}O5!C-^W&LI<%_@?= zOy%2wsvRpD1Psiw`B4apd8G3(M_w%_>0G#mDhnCAHT_MOEG?%4CYpKu69PHmV?3Vt zjE&sdPQX@)^6U?iU7YnLFV0M{}*JLB)JsEH-7 zisFC;0@d3?$;?kq;w#w5%ji4o5hQ@zYA*tUQoTOC=1?-v9~qjTH)aYY6Ud61Dv(5Z zT|k8j^mIQ`rKN#&bd3z$HnbO4b~IMBkU|bwWeJG7r|>o>^5Fc+nUKA(mNP&5U;j9^DHPvpvK?d(gBT&Ebe zVz~@qGvgF?2k0b5->2P;4<;>5Z?` zCwfedaq~oBNA@blMjynxP{gp}m5ZGm8nLx#xI9y>NgSMKHFZ*;&Qj0SA48!pCJ9GW zw@DA16OJN%&Q2*@lWwK@dH>G(>Gt$KBF&gTaBkREc?>8jno;IERgGMTGyHhMu_vr3 ze1Jf4PAY+&D?bkX(i#e(z=MjK>Vk>`RCpP<&mvJhQtc0dL47O_e?)r|Y-R!~7=_-0fMPpWWyQIvHvm}6E z<5DHdcPD;!xdaH@(Kwo)E@($A!Iw0@rX1be!2emZnVG5aXg~6j_7Cm;yWHeonk}gB zXe^>{sBiSUUI)idNdVI$44!*O2X zv~6K0_22p9xBj6 zKDXcW1vtLS&t+!RK8_BwGmB!K!-9ai5K~eWy&%2_uQma{_QXZc9=!600Psea<#^|- zSq!~ymjZw|8w3*8bd)&`HJc?*o?}*<^g-U>&nA4l@9p#U+_~7*F9(}lSFZinu%;_- z(0}IovePVT?S~(M{op+Q-}nn?k8E2`wFQ7)$VxW| z4P)GGVJ^;@9DI4EK=+e4F*UtoQ|w8Gdp9L3z5$x);zwVnN(BW}Fp%hp+j4FI+M+=8 zo;LI5^p9ye0SEjgno_O6T)q~g@o|Sm(?~(1!QjFy_Ro~pl?sLyRWo!lY)(ZOzL0Jd z!R{$w?oe5ZcL&Ctw$-^&$Mkht-jVjn4w^oP3jw(h76l-)0imqAXD027(OqAfJv#r= zm~vK=c3=4*GWLU5jK3lFkA9T5tmLn*#`*!Wt$KqP9A7YBC;tHG;2DS%PWx3iA&J)U)<*?osfiisH0B1=BTi>b3V$wD)HI(5E{tUarPNpC))N5;l=?$RwEy zc9FY?yntSX!co1t5HDmCrY-yQRkIVCg@G-^1c&tDT2C*RIt>ubTecq=QF6K%<&!bc zS0L7&GGQAIPXdxD0m>*_1KU@^>)X31;) zNzyWg4UwB(i;)UfFI{h*aHS^hU-@f-Om>g4{w#fa2N_8v=#RlDegFWR|G+6#+ScV00Aj+_nZFd}RRgjlt}{!nIefMMu;nLf+A#lvF?+5kZ-;|i zU8hco^uT~dv7!}OwW-78=`=NI;^L|$bDw+eQ@S-KK4XrfN^igDR1Qv@=?|0{Df0w{ z0kJ^`nlwU>Ua`rp!wMrINd=VvsY-!s^`3FFcY7hkndLPK zqVQ?CmS9>%dcV5acjwFnyvH&#H6`tm#5<~_aP977czLVa*$aMCm3rsFim}nmnhlV@ zG-M`XTB^E1s4~sRpxzt~2A~nwb9DHD;2}8|UJRCmawy&cW`|mUDqGM*(lZboWCwW|ot8x%jHk^6Tvx3wN9K9la z82M6!K(~6fqV(AhdHMaWy|CmyU8s*oHJaw^7ivXdoxC#w`ydP9XuF`h){X$5`)l z^>oP+e2^p@*tB{iLwQ8dDf%J?BT(G9*@Cd~O{j+-$@woE3@sFtEFJSCQM|;4%1+8~u_W<_jf!!mM{fL>!j4f7~R!Fh82lceeswg2M;~ z4H81(syvOy#}`*cB^r$S(JP7}LsY5a_4y4-*74h$U?iV5bQswq!ePn`>$(Miq0p+9 z8y?#_ENOtVOq4=GF&PV|ixKWFCQ=TKb~MnGfK^l#g=}`lE}}^Nye%mQ${eiIE4f_& zmGIfDX-n826yQ@KEH$NJ@gDMl0GioKk9+l}J&Hq=)|ytC?(fm|98@S-Pnw0BcKt6) zdtGYeL=6f28>lHyZr=KC<>-t^K1>L#HW=-_*@eKR2so6H0o5@*>t4=H;vF$KoFL92 zxkr^3_f?z#Ykq~mnrM&MoCul_Vm^S#)49!V+QWGHu>Ip84a(#<+-BUL>o5W|G%^MU zn03B*df+y@6X7dyH^F`uA3X90U42%XE zTAxv}AR&Z}SCGZPTeVqG-mF*_?4UN(3@%|S)cM<9cfhe=x2S*wnxsOYU{0l#XT%VE zo0ii-2E8*eFQyhs6SR1@k8i_8ifTkw_ry>J#y+U#b(K(NumcwYjX)U~DRAF=U?c`$ zomZ@4bM0&QT0*fGpFqAd$hJavzqL!`T#CR{9%Z5^t9c2WB1jA68OTpBpgNE!KUgTY za=^2;Jh%wyUBfePF%Z0n|BOAvjLCNlj@upGM47ax$ zzznxsm#y!&`%wuk1pPj^-1^<3|4lO=QZ;WeQGo`(a~m(w+zl>*ihyCw0QplS1~Cid z8|65NirO}6I>}n4`p_e=ug!qmrr#)Py&Y=fge3PN>eiB+U+68enqm)zDD{q;2`jM) z@Otb~K!#8yLt4B3jO&`)7ZG%9D8}u>FMJQc-J$V%sEP7|i(!J6Uji52GhV)3zeJf^ z)M$UZCTLpX8O{dJcU4qH?J1qeXydiDsKGu4a}N|$*QY7^2JjjJoEz~;6D<#`&mqjx z+>MK^Y0tn(Dkf&QI0!IzL-3QP0<-^JbhsRJzH7s|T8NmdSzRUl*H}58d)?JQ)ojrH zKtio+SXj&(gZwPM18^LP#m`RAbs&%%bcf0kDV?s744K8qS4a4b(vWvQOGYqMTb^Vi zDH>`0R+RXm2tgIaIe!N9;*VJxL7WP}rtsg#!AvCjzMBeZbO+b9#HA{8)GKWVqv@Y^ z50isuwz0pX!`N9{o;(3#ywKBS%fNvy(*P}obi2MutMxAM!c6w%1tYF;gK>-8XKC}_ zD;XVXF8WCmu#nP{`e|zpn0NRq98~rw7jENI1mDN_=gpo+vnw z>!~rnq>xTm@RnNpGMz!w7u4XnD_Xxd>^6*Q3@X`hjg3a972c)yWN+S+*w=fU?5leX zCpFaY)fn>Bv2rdefaj)d!RlK_l}TNM+|S&meviD6z^ESB$TvM?G|sOu4CEGjuQ8^0 z8`tv|{ln_~iD6vR3%i`{_250_u6$>Z-8LQvbp`Gna941}t385L-m)|ez)G)%4!SVk zsyQOCQZnGpH573(ShR^cF!t~^wM_`{_?Brd&-O(;2-YPgzCnjHgHT7|0d`9|LPK4B z4WM@N@q}pqN|vt?-VQGkelg0smRBBfnGJW?0?NYNN%Z2I_W)pb3O03Drp7o>#??XD za;#zIYG_+iCtCbf$-#5|tb^MB)F(U1&PH+k25x2iv48Q)AeT?ovTuvl*7h)!@ zuZy*%Q8<_uG-PBIH(TCwh-%=8japS-alEaiE0@y^x8@mQ-x_HZXJI;8!cQ4GQw4rO zMpJ2}R00?)r4t0Wl>7rU9w%Nf#^%Bvd=&Kw9na;{g&aZs#!FmZ;v2A|Nioz0^}`&! zgD?sqwT!XOW+>~ICskL^+b>I_)Bw3Hh7ZP8(Sco!toLfbM(-Zy6$fxXshK^0$^cRH z4{z_itrZ4u0zV8c{x`Y}K#SYY9RJlAi`PpFTb&u8T3_w23)Y;;-NSdvRnIU1x|PpLqvsNK zv~s6f*%c2nHp_RIL9(2&Bk7$kIJCRxVIRY7s70s(VHjL4o&~^SU^%N0J^N!WR~r%j z=Riz*0-gA_*}&iMN!j|+znj+QT^PN}e8ZqVnvdM0>&~A2l(MnKquoA(rrzrP%{yZU zm!~ySkfRECIhMNXY$sNe)9~fB)QFw(HO0-C1z|NiF1D3Idk1$rho>AvhucT4oi$H? zO^3G$quJHp%C(5We1pOlt4_*8N89jxJ2_`TP$iw`b*}MvM))4;MUbzZC@B+h&DgUK zv(MGaEzEjl^QH4qXZ$24=WF4bw{?cCFT~RHR1OeR9^!h z$F8+m&)uF))Z##C(R;xr=~tXB5>ON4+O~8dMfc6QF63{h`?@moJWWh*kq(kb+z<@} zvD7p@x-Cj}9dO^V9%yK+_%3GWx84nv*lAuMutKta6u3)U zGYafS`b+XLzlr}J!tsAExMwTV#eCU35&A=#7W7JP3BA@Sg;Ey z`2I{r3BMxKuHSapvvePij8&YwfT_Q#At=1J0PQl#OWQc!!8G~FYC#5N5QVp+{$>tK zpbL8pH$3<_kZuh1+8xZX#b5GN;^igC|17CoGd4By4YaA!avqtFe*lTfUk!4&I-cb) zpRp;N<^f2f`4|@PZFV`%{)--ek~X+d*f%`7Cg#gILdz9pYo#t9hm1~w%FVi0?tc<;Rkza-!5wuD>3tb#@^leeZGor<34EFzgYOr_f7hSIBdA0 zw26hYDZHU!&rjprAikHBp;s`+4p-j?x!Wwv^2-5wDn6KMub2BQdc6TN=5>@u?Wcy# zICBx1f*9LbgnCEFX`<#08R!d{7Laq>a!*Q5(?VGaPuyO?T3kykmP@oG^d?qv>l%*z zfHCHNC+{x7bLns-{U?sKhaPm~6Wl*&rBO{R>$^L7uA zwrp9CH*DeE;|OjM#7zZNdMn)F%07UpW5i!b>|%hK)A7ZjjSz8*;~FgUk-`Syr@jT9 z7R?HOipC8mT~~~)!^+H(ZMwm0WRkx3{c*TlJCr4hWk1Tdc$jsa?8r<3{TUldaaq2ATM^R+|;Ji^$p?Z_Ak|xi~Jtl?hh5}{YZ5Q{(~w>nLB>mDEY5Kdh~St zuf!f~t5ep#5D6H5t3NN1h*oX|xN}?S-5OfHu*Xd@^!fQ!+OvGJL6{A8(QYHI zW9#s+1EpY?0T3g}jxJ}0kbf5fom)`0hUA9l1bPPE*%TRlOe|UnLOG1TqSEu zov#3&y%>ye{;`96mfcd-lu4}GmA);)z+!{XnV5C7O>oQE?FT7bG}AiYL+-cS-gBQL zZX_(zUAWS>;EEd*v)kH)x|oMbef2A>KPR@z35qVW9|Lk0AH&xF8j}0h z4AZYnU*Weq8Na2rovN!gyDY!vn8xQ+#GzZKCO|VMN`(DTAsbfV^NQ`q)joqJL?qH& zoo8$6id6AC0ymQfgT?a-~cCs8|^633Nj?J}^?$ zK_|+2Pg%_F&}pBS4opte_#VGNxlla~p@XXq`U`qZScC*Y#nE%#=cbX z9q?lm4)iM@ozF->4ls|taL7D&CA3`;L~@;4Z!@qtKUv%;M?Qs-{i2NB0{0r!-S>Qd z6}BgNlFUa5fepDSho=&~)PoT*?dj$TKOz7mpHk4o> zTvAH$cKy?VN>CL^k6cS&%Oh0$D&gH$s_juMApN*gCkj=Y=p5#jhUsCFhRjVK76s}a z@ShqB4^DHfnUAFFH14|{9Ya55$zgX%F#t-9=PdBJ97{ty^L}419>3ZO1st{MpVXmFJT+V6-jG_4%S*-<86- zT{5TOD~DJ{yFlRaaDh_6(SU9;0_?_MbaIb1-Cn3ai%aZ@X1%t8`-})W@vd85-FGc| zrJc}wYRDr}%z|qk!#O4wnDx&MRrm(_(Yd2 zP`yA)1NGy$(G)?M#8SzoE^!L0+y0n7d2nklkqCEsp7znfRKJsNG+6H8&1pxg4tkxL zSvkz+{8}4av^qx{dFpF2Z+s`Y9}QEtD1DGWRZ=8Am1uQeUqP zQe{%P8p%eAdnO(X+baYt543^%qi1b+^O8)9-inuSrJJ|O-9=OtA1?ISys~cZ7g9&Y z-v8_l$D4OgeszqJhyeh8U0wNWKmWIp;XiJKbZS^Tu6;p#tI-A2HC4zd%wO9VG%ZNg zP|oU~dom_uPG8)GM+k2Z93ZLzD7#j6eD7?B_5;y%ZeZ+$uNR|2ZHITkI|=xHaS}rd z`mB^ZTLL|?WKemtel!!WWt;TnZDm&)&3N&zNz=KmkI! zbghzkRSiRBNs&(KJ;km{#Z}00aa}EssX<`uC&vwlc7?|zztKGbm+HzYs#(eE$1}Xy zW&e6r<7U*1d)3mJc=0Z%1ATOPk8}<mD59XHQfePn444)?d0Fm6-R%t%R>lyWVt zH3-96%I@ovpqzB3sONf0P!DOQ5>%Ky=?DoO&5}x_Vn*e>b3IN8wKzQt*50BM(|k~K zs`Q8PrA&dk(QddMuXZG=&15fXMpjZZXvo39jCqXm0nj)3%wd?f`>bSx)efosQZgYy z@+n7bF}WSsuaq8X`FCSnxfAf8Uiml1v|g<5ZS$4W99@vA{JSnT0Sx*1G~H<<*6Hz?%g`#(; z?%P^^oZ%+<(Tqc1q&UFfBqiBr@5TV_XjFrARBSE~5HZ$OiFSi6jMlmmGA593dn*DU zY=FIMExoCDJPG~DpY#q+{G0XJOj3&jNSv-CPT>IY#)a8#5!R3PN`>H88n5sVq$$wU@Y z1O_x$NQ@ano*BdedYje9v+q7~S81B(^S{~<=@Ibm1-%8Y2LYID*fmUo0vUgL^u1ex zX4)O~KZ3~OUyNjD>wTdmv`U&Xc!Oh5IWNF?h}=ET0t{4iV4_W|JL{Nf2<>S49zkNe z;GA5I&AT{0rJ=Gd3vJhBq$zVj!Zmglml_{V;GBpG zaoO#Ks;TjQdv=$|hlJ<`71c+8MiuUecj7U1nFSir=0CwW!bL6A8q~qbYf9Uelc2EH zbB!9vr`8ohs$&w+GK+D&JuoypzYL^6@CxIrm**%rwoNOJ37N$y8$FbGaYWl-+xeYQ z9stWHni3DsuGrhO+?&^E&4}_S&4+yN!h}uFw~|8R`MH)qQhr z24Txwr>D{bRRMwO%j~csD%|5n$_O3YotEvvf)Vk79?>^!-;J59yoawTh!{#7&M%WR zT6Gg(itB$WXk}T?n`VA;4Ll=RtqI#~QscJ>q&!uF25_4~b92f55~@|`5|ZiCgE}wZ zZn+!(LzZ^GGz}%^C&O2aI<%U_0UCsi&?r^AE%8Vcx|ifeEsJR&=8aRhjL>FYO?)v4 zvel3;%Or8fql;MWmKGB|d9fPQUG{7s&q@pm*5sZpC*3!dXyN(r1FhV&l;7N-RMH zqoRq9A44+70cJK|JnivYci-s+&`=1AI#>5%4@P*w=c`6-^|UQ%67J?W0&&LWG>!Sr zw|kHmk*k5v3~x5V%o86wqBjsmu{-hjr z+|uM8jt{y6^YdpWgu-=b$S!uw9M|D4Ty48hdM3vd+~G@nP3Y5&|7SbQz|tIJqB}14 zb^DWJ&a(Zda@a?(_G`LPTpiSgj>`Jg%s{#>u{owPvuxlr8)m$RAgs8^-T9|tUnQDP zWThg8^w_FOF!v>2Qex2h=OKAwX2LXGTgc6I8}p4uC!C#+8=9+I*ZtwNkezH?#jsc~ zI+RFs#zl&LT3n@*tKHC9rWnej=x5PE>vV-K3L;Os1KX47XST3=dk-YGP%8|3U zgz6e8lU@DZ3-Ic9jC0YCdj*<-PnN}JN%y_UW7GqEatLh#?o;zLkDG@5h3oag#LHb) z(d-$+r+Yf$CpAu4GQDz15?=_sJJi~+2tu(>985-eIvr?k=K+az$FZ2f_%XRwKod&B z^kL~!AteUK&QITfvFp1ib`gXGUk(^OsF}^^3L z`%gZXniN+Mc73r(gi+D?s&Ua?K1;DC*HSQ^$>b8#h!+_$*s3qpd4}u{!AMcv=~rQB=^Q%2hgyrm z61LY<%2pO=CRKrKsM7pU(}R8zqJ?oj*Nt643u)YT?}%8EO~gkNOK+~}a~#=CLZNsV z|90FqAwF7h6uI_im&2GBebJ$eGSmF*m=m3Qr@SJjM8b#TTg@cgHyW{wtJwTf7d+U- z(=VJycLu=9dhZ*0zIlys6jgE@xy=DHGp=(b<_=+SHV@Sb!CMbF9pHM)AD1D|^M=1Y zhTPh+EUr^Vi^8y39o-t@5%;8Rq=hON6k22Jt*h)w_N|0o1Ln$N%G>c9O3 z!f&~HHRh@Umgrq}t=W{Ii%}Aw?ZUVILCs}`qFmTFs6ktlgfA*-(M_-5e$OkN3n^9YPfVxQqqPxVUPA zj9^!z^=JJt{R;zAY43+6uVSD?_L)%vsN5vYv_C=033+CbA((h*LIOAD2aLO|# z2C)i>-ON@Hd|F9SR+Lw8F{8d(9rDG+#oc)g>~vz{resbHE!!@a zqt;Q-{H6Sg&@%S4R32$G&u08q+3heUZS8hCNE*y9_7FcrE|Bd2)2XH`tedQ)7@9Qh z4ugXofc{h# zgGF0yA-K-6MOsxn@yfWHvVbfc&WTnbD|Jrr=;(lpGWBzSTX~ zPoTIqouwTUBIcS2ISU4UcE%OPwH#fycb!d&6OKcU-kJhn~sACQLM^J|QNg zlA63`q@F1iF>>SfWPUX?vaqnXu)LKZdjMANVm8jiTV8OdwI~xiHOZ@;4MXQ@#~0wa z`ZIsFlvGgH1^L|ul}W~5*V_-1-Q#tb+j`(&gCW5{oL~189|$|Ub@A9TfCfqqrA7%A z0by85H{<$?vB3nEvIMazsU+E;TtxjoN}GmiuR$IkxKrS*ZE;36J;0|ep(~< zlm3~KIU=Jsg(U@$?c1vgxvDq5D4<y4FD&q$!}Sz_P(Pn8 zJ{#ZTFbH}G;Nr9COUbqR{VdVA2;^h+&_75mK>DOi z<|v9G0SE>_7UP00`w2T8TR;UTjIojWcCMq?cgeJibnvrZIS0K1thy52nYTVWA$sDA z!yQJ(@NuTR9vf505dzb(e33a+pT9{^yv36PJgz}0IyS#6Scs3X?+k-E{q+nyhZ5by z(=t9eFQbnK*l`B6xi?p+iRg=Ni>D3#y)Aeax59njWI>DE?$;b#rGVfb$SzZ6ZD^zR z0E5H|z0Y`9E#!VU&_v=B+W<^{x@{5kRjrP^mlThvaVoZL+eXEIIG(d`WYz+vUsLw>-d79y+uY;ywi{R{+`#M zheR;p<>!HeH1%TUsxB z$XqXqW<+CVipMPpNQr<$f+eW1=02E2yBk8tB~@}iYeR6lgTj?Gg1P$OjAWXI0)M8q zZFpf5Fct!_y$^f5sXJ#us?R)HOvEC9of*3Q>q-_$Ds=&04-5Qkp1QNbb$RW@mPMm1 zQCC##T-Dj3AEP{fRn5xMh5gMov;=V;ptSXBQ38cphhITAzs!7ub{L#@o)c31qRY5_ zPU!@Ey_sRt`58QD4K_@N@}#W+ch%pyiO8bCD7Z9AYw2XOcV^Nt-l?_^Q_Pq6-Tn7S z0|6#^$X4BS>U)-XWgYnncsTMwpEj@YnA&X3V!6goZ0^xQYl_ZJ6WK>#iALUVR!`dK zk>{Ebm+hZ**m7GW%6@tEw$AX;!LY-lk~5m9!f}_fv1sxWMc9jc*u)yTcCCk)AC6E( zfJdT`W)ex}=YKqRVf~u_KqDw=orkly7joFUY-m0om($675J2GGAgR;EJii>X zn-`TI?`|b+J*240ILp5(Wj^=H_Jg+aJ678`S#>gqJ~oIyH9!6hK<9hn75Z34~(ct zqH7KDag&rHhxgbP`O@e6nc(n)g-&eFm~KuDq>LlZc9r^fgGfCw$T~(ns%y=}CUvt3 zvrG8uTFq@HIfXQjPJaS=BEcf>c?idhfPsR>X zr)Y`rH$BFzw$)5k?^gj19MopKzh~tj_SbX{9u#5&@fW6ZLlGvqP=>ClMj}eh2?_2Q z$KvF{R!__45ju*Fjr`JQ2 zBh~JX382+0%q&(HCo!yYy3pKW&D4q4wszERKbfSq-0>_kzuqV}U|r7v`z2q_eXGc^ z=7-TQ-@rr|!syAkw%fbHq*98!H*awe1X;W>E|3xFfO(MBAG2ftmty{eTSk)5xZT5< z4LsvQJ5yu!5wqagt01pKv;Io4K0w63W#xfMp#E)PN@>Q$&GpyWmuD;*!8+R7Cjn3cawAY zmuhx5vg(9B!JY7XPhkiyMrEU9*m1F_5&8+=?c)pb0M6Dlojq-8oTUs)@-L0w2XeU$ zijT~NI#Xlx$|~&bU;e_Aha)eg7?}@^WSi@{FK=8%W)ym+lpqV`kE+NEJGg$CR_kAc zcaoDUH>!K*?K-~!1M2r8{LSY5 z_W~$?%XfXxvHlA&Xiag$`t!kq?xb@M4u}-`#;&*lYxrOo)b)iHut^%5h)3>T(fCI# z6473Jq)jQqt>bL~CmbQ9%CQU~sTt!1d`598Rz2dFcOVpicj7DZgQ(?+-X5TBAUB7c z5R(5wrJ+`8;FyYP5$DL;qWH>pWDXXWY|^ zs)k_j;ey&bWFDX4F}2aV1h-D`@7N^_!l@Wzd%r|*&ZgYqV6?+#1GeDL@cb+3@?Gtr zuOQb24+!N`@ijThQO{bLv`NqdMJm2qKa)r#!hlixO+a-j;}UiH@hxGWtB49wCM5zJ zK+I62rTl2hi}iWxNr=fG4h02Z?vj~P!Sm>qjo!%@+1ho}-@#WKT(V{1Say}S{4@AQ zRTZ`S@1O_1j+;6N&$ zuMa&m&;s3)0AO&~4{-TE=wAV4e{@mc$-WHr40U((X8_584k5s!gP`-V7;rFAuq=<@ zlkM5*^z;xTeCrcJgLeyntvdF^88A>$Tbn7^TuvP=HSJyVgI#8EV<2R-O3pBAD1W23 z4mbphSZ}4J^_GdgUj~t`s0MR6WYgr+7}nqE53QPMH(dW_LNg4Uh$wwh$RaLxwZ>ll zDz0g#G1fYpqe@xVV3zvau-`A@Z__4lYe^vqyRzG4mZJ5vd7QLSsH&lXbj&^_W#00Cjg5|Poe*$UD9upe=?RNYw_As#qx=)=zo3sTdzjuy>}XN2lD zSC1GD3<^mnYD(hS_@QcFtI=n_nt>Z6v%&c)U^00Nt<26I!Rf6eX{_5e{wr$5Ohy`# zGCQ-7`kjnqOx3R!<3HZzUo(j)>h$oQ-!y_>N2u;IM4i@-Gm4MXuL!^%B*UnbK7dgsPh7evYYEefR12oH(twH@jHFZX=O1qrLYGk|6wC9~pf= zzrAcZr$yaiI#6dXGymm&4$-woKrY7@W}Ro^oHjES+y499kdeql1!#MZ_}mp7;sFp! zPA&7cx2PyM?#x;(xO#nE6Dnzy>{-N*cQ?~;oxo^ijS5f+=|i{5SZtNx|t zNq0-4+Vh7fC2e0Xpm*aKp{)ll{xs;Xrmx&4>=*Q@)joi9%K(pZj>kj?F>dh8`PkJLR+&Hdh#AKrF5(MJ(+j9f?;#aOHJfc#DzA_sKMdrj zLW#&YFq_oIQ2M@#V4{J=89!*eM@?H~?=SC3&$t5xWt!cjWHBt&3) zY=5XD%TxhH_ryV?)|X2aQLkBfp&GX;t(Ib1?RPK}4EMO2?t@;^vUf9y^27HKqR5VT z1j=u`i)e~L0STCaKSV+fSPn7qXF~2u^Dt$K`H1j_oB0WiqY503#2yFrnh!DWMN&)0 z#Sd2XMGbUR4sx{F`R=DSY{n+htd}3ZmqSd!QSqY+XW{rN*}1baHlfPRU)fKG>JdQc zX21o1wFj_ewlJf$yv+qS&7bWoyT_`^S_VaD(`6{QTEkJed(Ih^{Kd5!Yd;o1 z*oXnd^M-%CWMbYXZfxtnjVJDl5+%ju69dzQV+ea|Z}0Z_y8ifb^z!nOTgrByylmD0 z))KfpJL??}$k*=35x;p@C)%c#hP~?gYBe~@Ev~jjE{$=8*!JVDtJb^Y=nG}4$|S?6 z;P{Kn(#y8-s6qKgLF;EB#8LLV(T}Bc9FjZI886maxMg=v%Lc3GFfG;;;|BhZzMcZ7 zq94deaNmRFImL`pwvzSy5YW394-bx36Bt6#HeGUCER)XFOBrS#n*>*03NJyqv#9ej zw*b}}d>2lPNLK05fwP;+5<{5JBg^cVZ!E3tm&g`1$91kZUK!D-{iz>0bh6B@ z(>m>)QNKGXsw8db#V1WS07cq8u^TuU;s(VAO>woa-n?4bLUd%d0q(Pw`=4yx?%jCa z{z3nmso`E+_+}Blp?u#J{_j@&?~Usp1=S)|D}{9t_^+v&l{ZNcHiFY(G*gIuN7IDZ z-WfxZen;5TNZOHj2bcOh>@N=&6_+{jWb9N|27cQ2ue*zE6oTJ~EeKsnzw7Igo|_d5 zva+z5b&%HjSnH7LDE4I351sX!knZK~%joPWdxMyanzg<; zbj_4PDQ+}QA1H$jNL`mDuNvkB;aFL0E9>ii+-!b@snf#Q0>$#*Z?k;Ob}UjQIVt63lUGzI z#&<;g$5IBd-+tlaeX6g?A0vS%!ja(y!1uFv%~1vog;EhZ6I30b&y`k<*~k@V_4=ZL z(;-T_C!#hj8g?7np@rkY-?))Dpoqm;9QWVHHAoXa zDqFU%Z6LE@fc8mBQjVscLpN0+|7Zbz5mZR-lPJaTZHL*G+5}amL{y5`@}}P;=)X`) z)y&F{CQa}e(wU;!{h=MzEZ@z^?&0G^|Flrkq7c)a8O^Jeo#pfJ(9L1c>UGirULtH= zNrM<|w6A`#g&PQ&zC2rfpXIGMGJDXg${rIjccm=C&7*`|oMj$mFNYkaSK2pVR<7dh zr;l3n=_ds^)hl6ee!@)Y@Y}qE+&+-k%8~PRy1sp~t@JCn_+7pan#NP^Q6mBYUHAuE zsc9W+E4U*)9Q|k_tLEM%Rr{MA7!6dCe79(%Ur6^N_f8R(L(A>@jH-Sf-Lfk#vms`| z#pO_{u@Wj{A@NFkWK|$ydcWd2bV^_jEHYvoB33f;mrAP03ZMTB-gKXxE15*Ny z8OqU+pws*nDeQn|DHZ`0P2A-Lr;)+HuG=DTb~;G>ke-AI#thfaeZ>%L_Jt=7DgqqZba&c7 z#?47Iz(yz?N~gvLp>rt;4hm6C&~+bLgeyjb8Yen8TBYyT7*X8NuW{%QSy6j<47V6~ zESgkozZkDu!(!VIFA-fq`n4j)aYFQMiFZJlp#m#LW{-vD<#pLxFnGfa=3Z_1eu%3v zxIY}a7u+3aI4p4-Lq<@GZbov6A~$mlU{_}ykSWTY7< z*Q7!HgbdyWi9hT80a~4sS;aA&lOjL8oHnT!sLhW)&C>^DJ=}g5Fmpg+owb;-d0kV^ zwRZ95h|un#wx4VIArAPix9EAzR_GB{h15*hWK_`W;%f8uKOcf^FKgJ|94ke$W90%p zPZBGKrnz$F8a(JY7W+^pa9T&zDX$#({J6;C?`GDRKbzPHWR8(KjaSI7dotf7y`l(S zZmY}hMa~<|fRFkt!J&mj(5ra^l1;wr~oCjB!oWUtyCdMJXE$dic)k z8niNbP&p&}P_qL=J zq^ks~%i+VOifE`o>W)jGu8ET5jZ9UsLo0Xz^&%5YG&6zro4YTDd)#1S1vOPt^^B3mO`LrgZ1DwwP+0e-D<%tJV+gP3* zIX4QM#ji{;;o_FVo8{AqrbBO@qcVCDW}Z4e!$?2?H!}J3hFeA!CR^jjX7*_fbrgHg zB^ELxa#{${X=olG$&{O}&|iPW1WIsv5srao9WssVY-T5m@ai)7+-P3OBv;{Pz~g*E z_P~{#M4(p_tY^mGEUr+N?_fw^okr2c$ArNhgSaeSsg>_gUagk9S~Ci&&v53-7ik-n zSR)4HTAyz$D*pAA40C)(mNyUY6UA^)vM(I%!nDXQj#LwNBDLJ?xP-kvz& z6tD~R%bQ`!h2fY25H1kDAII4PU^;^h;5k`T5`|lUIF=QEP8*ia{EgAmH+STFD9-#e zAULCBsCR)72mL$>wUQW@QUPBx)FE6%nBMC*9av2@tlghy7dHn^Oq6*~8R(}g3Oi29 znrm;^h^)pkg7bC}1jpnK@@C=Ne_Z;YQq%tMe5X~xcUt{b5c@}330mqoIQ$EzCMot> z|0SC9PWb~GEnZ*Noy=LaoZMCRlr2ZK>Wz_ z3y#@hDzEPMt)%PcX*J(u34yz$l)5<(N<+)~L zR0^sM68vk!LR)6^Mg5Qi9Yj$JWkA1@rIC@m4{)F2GBtRMaKAFo$^`U0W z5X#8b9kq7HC3%`;zFDiN_Q-?r=#m@f{GL|%_1>Ex5^nAV7g>o%*J+PdhwLPrT46|O z=wm?dfFZO$5cG_G(ZOz)AK*Y*h`frWZ};3umvGOt%pxfBd=FoRT@Dm|bIr}{y=feW zi)0yHntA~~G>lHq$HyN>&MXtfr$-nU8`)>hEZtvD%o7|=3X|IjIs}B*Vm@Qp4c-5} zmj!=qG2DKegAn-qPf_kalFs4(>cn1RkK3=a-Cfo2IgX6s2ul|~8FJ#Z-<3)&lB}-X zUg@X`eAwUfvLrSFgSjSYj$!! z9{}vr8KzHzQ+48w(-0`btH7gE_tIE>!yv9YQAGiCxB$lXQhP zSDshQKpFgYmow`gYftM!&`;)^k0+=S@?_`bG^A#aOsiU~kNo*qDE#ce5(PI$&}#OD#P~%k=`{T}6S9_Qi7EsSU&5O* zo{}Ovr!v~@uy7yR?*)Q4_+dFJ+;={l*YgMF4-TG{!Ulk~OmJVhMG{`vT8KR253D$! zfuG=MaqOY#!>5@6+C&&Rh`jhrgxF1lw&XJgw?2fs{ABe(w|VCKPd!!=%3^%(iNM;X zv-d$}e2gp|76a;%aR_S!bUe@4|{68OY|K^&)8!;ox%oX3+TDZCZkK6#okqdKPlGep>^a&!F3 zdZbpb7_aQ!9_@Jvu7a0!d(Fjik{PRp1R9Bv+H`OW+|21Mr|ysISYIa)cvQsG0+-iH zCY<@majp>Aq|bPk7fdQrHIE(G0D$VvaxUTJDRk@DU?Iql-V+g`Jjb10i=+nib2Qv4 z3Jno7@^J+bZtiM~qr=@T49#Rc8555=%4QpZs3$7E4@7LlIx~4VC{|5lJ-Wfl5Lcvn z=KMDk1S%W|Yn7+pwh&SJCm^>gK|EHlS%@uI9PDlZ-Clw*Z%;Jb-zL^FRYj^GjSQ*o*+>MusV=VWl`( zO7@rGV&X5z4b=N8+PEc^;!=N8O8Gje3mt{2M*Nc#onmU0XPCF8x3W-Q`6hL_@_6wB zKZSW2q!{GNMaD$_mScgY3Jd9?UqePwSKJ^d@_t-ou*7dpkYZ?H!t^8*1d{lU;E9?o2xD%FPMUbJ3YeKCmIif(;$!tW3qT)jDO78%hB za`qdR`o%qKt137qlyAa*^^FRNLQSVg#IP{3EFI1UoxUd=OIMrvoI$1FbW8lJF-EkD zEPMW=@J1S9TGuIuw~xje(2?Z?Y&Yrlvk?ii-EwFU;(X(P(uN4rI-zEgJj4YG~1?(sTo#ow+SaQksIHXj!2&kp`GY&e+rdhE6$?joe^CN^Farq)jkTt&xU71unYIT z(YfPgklnJspx&zXl%bSY6jx7`&!UYclQk-6fIRmH;l6oB4Ca**{ure&{q@BVsjsQ` zCeTe(w7C?vDcI)kMQg|idILe@hSPiE9( zlY5=~P{^-ol*&$B5F=y2u2nMm)mB^UMkA`U>D|~{W3L$_?P1HS^|FDq>5*vMVa;7K zqDzufa#$Q-hpu=XJmX2a+}JxlM;8arfB~~Jx01fClopEm^Oggq_0QP-GW1HQK<1C( zctQM`39l+1?lg``^4`aVRQ8|Omd>$DRP5Ui>zGzV;Ru6y^DQRFI*9=~b zaT-YFIPE8vpc2MMi3C4#VF`R)AY~7|Wsd-q8*Ng7HWSQXR~aO!>IU96RxI>uOLSc5 zt5%a6-orWqAOqOf<2RB4Cqd8InegAvdI}{%5R>0pvWC#;p*xWu6lW&Avz)u~ZxJ2W zGB2gaTzcJ|)rE8}8_ONpq}RJInK&-#9+YPk_*vhb)(nF%V{)>WF+5%5eE_RXx{+Th zuvJjuh8>=D`J$>hkq(iQloV&YH&GYfK(bi(+Y+9zOS7?2YgO8-sJ`jOPu46^G@Kww zzbWh&>vdF+$E{_iRUDc*&9*?#S2ccmHMN(|?Y>z2X`Vl+?Vr)$mjT_pSTHXr79sEKZ`Wizcoozg(Yx*0YW3;=wXXA#0J#YZvmJ zs_@hAe1{kU47ip~mh(Mlhy3xe$j^sra+dtS6%Jnuu3!-fASmY`R|QkvfqLw-1$onf ztlI**951zD6c8Akaxd`=Rr>|c;<+`P zp%delq5f$-eb>V86iszfxqYLyaedm=uiSFjV2IjTcdlT-(U^VK;^eXdZGHjZHMaHn za}W=E?d9!aoj1Z}+_GV#N$IJAtAT)4csMzk9(9w3vg;|5R;t_D(_pLbMgJr1ZZUD{ zuBCLe0(yIO{mM>Y<|G*6wH9B(G_KrGw7XO*(wO6^bF_b_=JBW8V~V;x(A_eJ+h~A# zd0{ftqzCYxfMQa9d7sOUVoyVqvn!$5bwJxkL}~)^mS#5ixsO|?G!9{peMT~4&$}0Y zy9_;#zZsf-SgUeU@Ph{%ksAv`*rRL8Z0X&ps$8qyFE<<6YynSF6=<>gdgk zh32f0XY1v?Xp4WL2b`Z3 zCx7h=Z&E)>c~(ev){*Ii#}dNF)KayECga*$dCpgH<8eeBaADamL7T{Mvl5whuC@Hk zSwmxf1?>34%ycza{*^_7A7lk;Y%a@^NOY6Ap&|m5eF;{S0#j3Y2rLqy_d<$~EfP!?UfWy{s5)sn=Df`bZ_vT@6sz(~kq;z>zm zpO9rHt>EnM32Ifmx>2^u9{RChroE3PhD3Mesl6U}=T-cdCTO*EW-%0H_ny&(UHll@#ome-X zAQ*1yqPdr=>et?uYt_N3#*h%QX;hxcp*Kl7B*}b;JY3HsmKGUv>RUMF@IMGI8UcSSmHyxV0UNp&F{0u2F33i zxSgDdYsa00yj%s?+qbYy$NGk(0P=d>+mFg*NsNm*U6JOGS+q;|;lQKJIfmvg5!gAC zmrQ2EJFI?IsRwBf49NOT%%i!;fU#lZl;}Q76h;Q)4OI^J76HzTIQNIzk_WdWj2Txm zRK-^y*HYOC3*!K2Id5mp$t|S-kyIAglAXySsgOZR6}PD=$u;=)0QVXi9}ur8~>0sQ=881VBJvPI^7BEK>Ra0a1-1wPC>yExO7mJ~Zi@^$1f!K8uStnZ;0 zg}_^k@TI}`*LjyqKZPuT`ta@CgV(uPlE*X3iY3abkwxI8iG@^nwh6ovMH0bmft4F_ z1ksne?>uEBiRWi$+-2AOU6PyTucw>X{|L+r?{Y|CqIlLiNN5r$6VVX_#_zaqnLe_Q zs~uyaw$V;z3@Il?eXgxXDY8cYvq^WWAnfkZ?aNU2X^wX7XK#UT!F+Z83Zc;N8 zi(q27DRp#nzwrJyMqDC3AP4>KMv;7Xqy8dp{1--avicu+xl7e=c{!H9e8?;_1<7Ls zh#A=jtB0!-CJN_?Lde)3f#M|*A;fF}W|~O~{%mOhc#73)vR^i)oajdE=;v&AErfq$ zw2I6eaeS^Z&t>6YkG3ri`8oBCVs(XM#yLxuKYU9<)R)!zh)FtT7*6COI9boMJxE}B z(rRkw)sb)Is&zW3;(80O^_yW{@;FL({VeYn-N2}MaA650+&z6LdX}NU3@QG30Bh0S z<|NOmQ>fghcY8!5>cjU7m6TM}7AQqG&N@Z5pu$lvuR+xrQo_nVev&!VFAg;Bbjq&+ z-hLB_0c#A*nleoVuP4qPkGc*KW|LUi3|;}UtTy$=U!VZ=F1jR&3hH1yZFajhP4GxK z3~$=OI;tx!sC(Ih0&}hjWnwNu9l^@4=p->RtU$5AQ(ER%n?^4MTkxozyc(Eu;a zVN;eY9BHS#L3%k35S>^#R*%?P%%4h^bs5K0U;fBtnAU`h4&?r_7(`E=%nwHlApae2DcvK96*skF`&Jp# zEVWx04>K6yFEhCJ4thAr>e@zW)XXE>)M9xS&_=&Zx~iS@1$_OKPou6U1cN>fz4KHF zM#b14i{Mv;2d}`bH>=3ICWjXR!Qgu)-+Ts2S8JoTda?p8@w~IGU6KCl2-c0=ldz6@ ze@?@ju3IqoVHACd0Wu%ROXr2mjorGJ%=G37|5p6q5iS-r5hKx!2ndeBjKB(y3oE^C z_Z8F}mh;((FNnDbcAE`2+wmzWykwJap<52%ZS8CJzGMzeZZ2CL-ngWYG`*h=i+G-$ zB<+$GS;dfDkk%IFlM{{Hei;JU3PiGPO6-~+* zH=BziK!(IU2HMm=fYW?~Ru^zulpkhTUqf@d@Tx+^WZdC8;|ElW`A?y#Fx1TRab;U- zqU!j(oD>O7L<#G{s}sIu>Pf5V%tG0@4}k!2t6pcW^VP2EE7vPktZCzOYAb;UgWB_E z1L9T*!n}0GSh%un)b&GZidMO8H>SifDM*3LkY#5az{b0PEO{nlA@+a}TB^OTS&tBk z30NoIwD&aoh?g!Z!)uvy(smQ{PP*$yqx=!KlE9&RvQ?7ZGfRo#oc=LO+7?u2jvLiK z6Z<)CAB-`$NyF=c{eM!H10Z8$Zl+OM?lb%gG??@l5BVq@y;qB^lxB;eGAn*kTTia8 zo*bc1Gx5?X*<6h$7+&FCt$IU9qPXRGNt#N7rPwt;mdMWK%-?RLEha*Lytkq-dP$(L zj@CVf-%w zDv^q1KuBp=`8bgLk{X4I=5rKlrN_OTP$b$OMjm-cx7XPFQW63YdlAd~tTsc}tLwR* z1E79RP<7@}kOfo&C=_Uq ze>fmcdX;z9gEJRS40faD-U>4xk^JhaEwc;)c6_@-ozx3P-wPobHtGwdlZfAQC(NRK zIiZsKqcdnng?Cr7;#ZI*vSLCe1CL+a1Sdw;(Y(x<06+WKe117|hVz|(@ZR)O;p?Kh zxOyt^04z%Fj3*KdyZ6MYZP0FGE}XGGzD>V!!LBZQ^0Lr5!M4QJFZ<-Lcjrd&bl^Rb zItqlg6mgWRO*V|aOV<_(X&z)pXV-`ge_$284qr7w9>{B=i`x>@xG_)M9lNY}JQ56k z_G{ffIxkJ%J$$%}b_0C3L9DxcPE9t+?Tu2q1&pr_wv67X-hux+Yvxn}fB*Q-8iVhw z`HP15_if{UvgYqTNS1v`BZyr#$NWNjwAHG# zr0S*5wjED7P`Lfx_}}LuO?<;B?VtTkGoQQ`A|S; zIfz+-l|0heW@jlGfAtnVUaYj-r-9Oy)&b_(Ge5rda`|E)BeV!v{Q(%TbjX)3g><|t zMS!qkgNJ5i{LP=oDFcbb=%d=!h0FhpU#sCi2mT6 z>l^@K6s+bWnc+{yl&G!&%Q!CBr_&@mwCq8ajewuKwW@MT*}U-%D1`U!7=rscP{21qk7D^q{F)9 zCPbkuuZwk^SHP7sJyY6^mbfM3vfAFQ(}cI%UtYbhvaM#{e)0h9&;S7c?Y;Z2%#r^#O8!?D?NIsK{7wYk ztGY|y7pTe*-VxUysA^LnyZ{gOj3oB($&DDcNNPk&-^DDA?&Ugb^-!wbaQM;y6s_3# z*!^hYCsf@R1Ixv*Y-Y_| zLQeNLk%noGg!41E{USQd1IX#=DG^(+2HPMMDve6~q*P**4P`dE)O`LX5jrCgk~O|) z>xy>|6%66&)L}ZP>e!T}UdTK$6-DU*aeL;8}h9ObKTeF`5_m1Cou_ z{4!3^NGye1q3x)Q3%zODsGs#OS(z&~zXuJDB=YL)su3slG=jsxRRr-X2LnGdkFInk zKseKkK=SkLE0*4(zMqI-h`XdpH^?2R8QUFi-rxdNHv4K}9Nawd0}`}Ig3c(F z?F+JHPupA&M9UhY1S`lqx$o@ba3`>idRYVh38cr8n^h!(GRvsdd2M0Vp%@MnU5~-$ zy^<46I*Gtxp$N)(0s0BXd9yb_shFffIR0s1wdjYu@p zFBo5)BHjZTpakZ7@JjqHu7gI=)t{siG%rKfkK%SJi3Y~=N%nzYsN(LJ) z^iQ_#Ab2mR=nnrrGn9v!TaG|ZV`8{@O9x`(fNAPQdJ)^f?TI}3dpcj58EZce$(%Dk z2(3Oqny65dc>CbNa&hr^-?z8a$IYh{mtKFR$8XPnhYUXM1|mc0EANVx9Vw(Io%+k^bF4Boub zXqDjt?ospf5cuaCcdpZMb4Jhn2@#T&98?j`Zb#c1qq&J7&CV;;InXy!Wpr4B*%B*q z>te(;2$#p)It4elxwqM7P@iWa@oE2lu8--Q7uu9#7;yJTB0m%&qoPNQwVM~8aWr=e z4rw@3od9j)xqHtynaVdX``(|?pBeE_XfE}>`vaH@Gd`!)=lhO^qZ4WxMFezrxwjK? zJ}aT*fAaUnc{{40Wx^Jj7Flm;A1*zaF17QA!E5Gk_pYW7A16H-(t}-&Z})dVdAxnN z|Lkjl^cQ5j-u0Kb3>*c^DU|)FRg`Uub_CJpe*2GUl)pF~P>#mes^5)wETsP#WB>cq z`TsUcs#4Xk*%SE}SKO!wnP`VdDMvyqKy^)I%&2L`xu`rGj1lZQojwaaL`dz+V_MS_ z6E3#&JY*%?;m_2hp;TXuAwT|M#E#^U{wgmA2R9FozdCNp?V} zdK@Jw1&&Q5Tqxx4$Z3qyw9=34l|KZFMi~cwa+RQ4{z$-6fFE}RMps8JjqKx!CKw}! zBA+PTkc||!mj5AVC6JRyoY(mikf&nVf@F!l#37Zt0MUY=pIC@Xs~7%NuaT%UMj&Hn zeUW3oRCvx7J-07<(Uw@>=&ED~dRsbXX_YEW@CV`m5XLTmSA60mC>qm#Vida!dj}Sv zHV5LF{Aw=Ry+X&Ba;$7~>%+1fga z*m@Ab!n3dfU`HHP!QY*fetOAQXC<=58*?&`UX%NxNgViL184=QaUlA?1}<;z`%k{C zIlj2OTG6*ZSw6ABZuZrDS`_2!LGeK7#lHp)@Zo(lefaY3F)K&P6U(w0Zn{#;eQWcP z(L~7w;p=4~C#+QiOC*2J&+-AD8iG<%1fC%T>2a0(8k%ijNXRiDP)#O^Mw(P87zjsA z0CxR$Y{Lf3&sw^8n(eoYV^vx#C0#fCZQ|B|d=vp}kZS-XrA45ju+{9J#&CE4G?r>j$zxbu zRSYs`eIF}SrS1E+-7tx8!kDqZVPJ)`d0ql*&mw950I4lTeVVU7naVK_8 zZ`rD8e1?pAf^@FV4&mrPt;z1MLi}a-uwUfHKHX|;A`qH=Y28Sbv=ouQ=G+P7n)Ga; za`gt^97e*u*vc~Qmj{-@WmV{Ii57*q!)CgG3qLDUy~2d%>#fy-J0)UN?tu@P-D6SH*L zzI0r;F9xzpg?pLbN7b8aIillA<}6;s zhGQ$be6q` zi`4?0hp-e&?FKA<0!?(1)X5TT{AHL)Jz0S&+ z{3juDs>mQpW#leCI48&{BqCEvBMNZJrHJX@Uq3_X`C%FfCf96X#DJ(P$$gzr245To z0BXdWMOrvh!(D#S+Mn9xTV0Xv-r98+tQDbNB_k-<78Lo%>QT;hfkC%6k2xGS5)EX_ z!I(lI<&YodK1~-{pgV7>*C(=Ie9>7*FX4oxS%EGg0P(8`ZyY_LHdLXI+Zp*-lpBE= zQdf-IXf}MiCu4VQJAZqzQJ=NEUE!TtCurGL&asu~CsEdn*s+J|GL9yB2ToD1)cYh9 z77lq9*2}0SvU_c+4Q+tJoDIX}@Z?0&EGR(PQWv^o*V=lsWPI_ozq4fJ=uCC97ExBD z)?Cp{t6@W&Mxiysyx4}&WQ4_f9xpX}OOP%&g4=}j8uF63(}Ib(dho{3n9O_AnUx6I zIMC(yoh(l}uERMak%rg!YvBpHBp`KtFwF~O18Sxq1XL(rpEF7Sk|?2^pu~X7Xi}u_ zM|J`ma4_L_$dGK@xK)a7uDXTwS@Gm_6Aaimzcvw3dAUCwT>YFjMY0U|M>Rb}?$y=d zJEuFobNaulBH||2|63KQ`mTzs@xgyn{6rMX0fb4a@^OF!6e*Mx!k8p71!DrZS1^~_ zm#)$W1U@`WmSORk^4S+qZ`_YMS#7eL`y8X#{aD;SWGQ!t@ZK1in=2#KR$X!R3P zfJ+Au#`uejfHCOVkwe7FRPFP>>R3B!`Dq6cV)pxM<}pHHqZ-|iY3`CYGmZFkYn4MmIqqyi}%eYtMdBRwhlgiA9FR) zOGaA6NhK~ps0vb~3=x1xYMD>Wy79TmA4^r1L;IZzj5dwFqG1Kzrr&D3%nHJL?PlF- z3L#a6gbvj_(=^c|yOKPt==7UtA6;l?ibFFoeG$x0^XOHZVm(~97-HX8R2CeR5-DCu zN@OvSpKHoxisMEm0?w>%}2am6&w?{SrUCGZQN8Gcv~FmgMu z!{4@*BnNILDTY8|#5AbMP>5-Stx}~@J7`9>97Z(XG`oS63iHBcncb0HEq(SO@xgn# zWDwpMhUvgP;19i|Sn@Qr4Q7P|WH%*tCLDv{!q$?rp=C+#q_Iac-pW;k4#pS4MH&xx zM9`*(22b~9y$5r(Pnueuynn3 zg5RUQV{gDuIGA?$A+X8Q9TZmt_z5kO%Pq@OlZGORn8H1Xz|Y6c?@3i=b_%&G+OQ-D zW3M-xo9^Ol^-nY{5I=2)N`96y;K!(JYM}2VcBTqRH=xdAV4EoX3@;kSlGSjBo&JH^ zIUwM4{}5w@U#TYg*m+xGw+EPmC=7LP&#DLmE$HJ8F2NHQcdz~2m z<;gj~J{ggthMYvCt*_`ITYi)j40#}LSPA$*Glo10XXsszafgi`u_T(_)pb@7<4I?! zZG_g_P>5kUPVV_e?#l6Xeu#!)n{2$gy% z%raMY78g}e7x@d04s|nWqX2kNHW_vWRh0st1n4*g$s*8Rs%qSz!k+deK~^kfNhI8f zEoGQch|wiV7E{CV3|*)=De6oyY9#egC&heY_4Ki1Cq5bF0L(H2e0I0E$CF|hyKo{4 zu{rBF`K%v4OGT4<%0Q)zQZ}1Ot7L_ogWNYL*C_3 zxfOC^nuo`BZ-<%{lt>hvB}n#I>dT=B(ghTME&uvR zSc}LzFq`tt;N6z!A+ui|n<0+6xf+tM@$=(7UU|u`?7Yk~jRCoa#n|BI#g;$9>>DF` z>_v`xR7+;ekIRwp17gl0Ir7%%(#Ny(7a8rb7Oj-Bq<(&t4JC$vtr?;Ju(VBE))j?D z#1qmI*ExS^KHReKNAsK~kGnI(@?$U<1;7Jig@-dOEjedt+4CLC^pu&U`5iv9 z;WM&cYCaXDBpw&JyoateB^I^6VET4|NPNln(WbXaM_wT6RTqs9K11f%rS)-R2Q^T& ze)w|q-Z5a3G|{9GDkei3#qw54P%!XML%LJ0MuN#k4suIhk5TFWc#MDS0{&Ueic$Rw z0)1H>Mu8w1SlBH<6yIt@cCFPSa?`cW;YCiGIEqmeisTR)?fDT`&qRCLuHGx&)X9v) zc{<&2;1*V!n4)VsM|^R+B7E$6Q9rH2qM@%sG%%s)L7x!*k&pTC2XG z<_F8GJY)|37MmVZmsslV$qQGYbsAfPX$ZrVYG4B?7B}v*JjZi@DB)N8L!>CMD$Uy! zPqrhU*|5T6j`ODlwQB2%T3_{^C+NWlEQ7VCo*^J-Vy)0@6^Pgb%C?3UOIn}Ov#Gm4 zII~M&{~YP^w49`|Yo_+GrWFfHj#}DeMBu#lQ4r>SH;Jw764*OFIt7|2XYdK;#su&V z-^j4)*{{YmMK^H#QS#<}p(mHQyvS~*HF(bFH|b%~3d+|Jq(UzE5tiZj0c8R35JuY= zTnW^5qBOP{L};4&)6(=gIg?{Nm>bIc8U-t3f$Ny4iK(kTi2~;U2{8))Zu6~+iuFA6 z_6*&3rjLsOlK9Syp$BF#Vv5t96OkFkrPVIRQrqFT8KsuAph4UX>nS+=wz^Y-eKS4w z-vWqWi5PoB?=R>}sK^)UPt_kX>l`N$+1Wscd8R;E#h9egYbJE@QG2LN(R~iv268?_ z0m2mV@pF1Gg}W3T3QTEIP5BTypm|vq_nk<~AwtCdO?{>2f&_q%Y<@GA`8%c&885dc zhpW{Z3M~mMq$*jK1CnDV*X*E!0tPEI$p}^>hg@l*bvoDbGZA}95LX1PzDb~$=vBH& z{^e?DW`31ZQA1;fv&unStG^Ftjo+kJ#*7|h%yp_Rf}cv}61MKk;46E~HV9muZg9D{ zKWJ*c&vVSDHvHUi)KOUHsN`C~WNm|{OVTNTV_;@b;iKnl;;tw|I|mb?Q|Sgo$C<}U z&l{$-kP(ozofcLyiwEU=5PaO|{N^F^^4pBZ50)yGv_y>S9mXcczR%xlNYhlL0u*&>&b#` zq;!z}g006`c(o=~1e6^|eCUnac+dL#8BN%HKe9U=^{>km_drW=AC^3q! z(7tI$2~T|?8&XB3s%n}Q=&@W!tRJu$>0gu0K?u^nhfe-`lGB`wIWeeSyPJHrB(*7M^`>VJfArHgT|MNmyG_8ZI=+1y zeA8gbH5#m{1tb!?*d?tC2M}p07&!XAI3>Da`tRZh7FPM~)3zdOI0 z$?P~jg*aoBz_Y`{GhZ0nA9&P+zlOtTqWN~9_L9F?U7IG?0uu!Qvx2UsA@Men^3y!7 zYns(GZE`DGp5%tZ*M|Jo`}*hYx@(8TNT9ZE%KGw16Zt-6Gd8o^$areae)DAthpeIE zMZp<3QR$2hr@~Bh`I%2O0nScVPU5o?~wBWNGS5FZ_?+KYeA>SMBz1 zoR6shxl5Qf>`+*VdA3wijapjTc@%Gq7XfK;Hf&8MiSdZ_m!7M5BGNOXAzLk8k`xcR z?Y7%^X|&CHOd&e6-7unks=-%MsP0~wI+p0PeoZ=#@qsShZjB?MKJaEE!|{5}(Rvzn znHwJH8bw6#cdm_?U$Qy37Mmn=DDnfygex!hbW6>ws|^bC9al}XUo zxcQ(HPxTVgS?D~f6mBHlf>NlcWAv4MjUqYW;wR_Y{YI(6*R7XT(P5s4!`bg4W>yP0mvZ5 zq@;rzsM-t_1sC&a|HlVb1*O8;*CE&UA0R$zOS!)Ie>@*O51@8v0V zp14%_N>ekT5vgezpR|Z_zoA~G(Up9=w>zwB=sZOJRjK5wg5l`d3jUJ!|r-?-YsMlV^5uCO{K^_QLGv%JdD_FG2dWn5@L@Xca2U0F%LY5=T7&yZk zS}CC%wcXHXfaoJyn8c4MZJmgWo%}^(p>#e9R`y_ktUP378@>6`YMA6lrPOJk(9Ej< z7=n&l7bYtemPoO#0 zh2^ZfvgibC572-xdBp~iBOtJTuSs`bd=A4~HXPi0Y|HGeMxki1@IA9w+Y;a2KnQJW zw>J!JS|NMNG8!ojw5y$EWle}SFVzM?4SlVco(fW$6fPym`8oH|EjkFVI8KL2y{VEt z5q(RV7%eQD;b$;m>Ty(&)}!~Frbg-@wDL22Xiar9lUq~2ZC`oRsbm>&4qp{@v_X!< zn7P^d+}*7lp{-~!{#A?M_HP8A51o#S^I89q;EfEC4l_enxQ&!ZFW^%`D6O#*QlhB+ zL>Aa_Ws}iDGnjF}&r1Fp@i^4x!ageHoH5!P+UK8LA7$RXBi-a3k#6_S$q_F+7J8#C zRbn3dDQnY95vMoF5u6G~@T$$Ece!ET1?rcgYr0*Nf9@joX+Cayp9~&Bvys|+qEkOu z?4$7e^P4!ZjxCw*R=;+kU7lQM7GlHdPq%gzWj)hS(yvI>LKoDDj3 zh+Y7%d_!x(=q?aFjG0j{?)$0NstkEHd`Dum`okt9=g7(r4{IIQ2s#lFOFo*t+b)yi z9LwWgQD5rT?_rnZb?uV+O?fzd_KnfnIJf}v3K#&j?!qD3?6 z4ElrY>YFdKlo@Mctat&07=w6+YrxK!=O_x-NJ6`|;Kx!W0B&Jn^mNg5A2tJ5X=uMj zP=U->dtyAIx7~+yC9fQUB+**Hx(*JZvFskrcJm=0ZA-OrRM4T6S!;=)iCkMNr6;Hn zY-SLCq_}xLgJ$p~kTI5)40xB=x{w#GC_iqO&$QQJYuC4*N{t(1 zrh6^~c617O(;W7(!yRE{XcpUx={Kp(RJ3y%DEgmG@>R3qO0z_A{_laZnE9CjR& zNsH@=0h#ef92s3z_CC#{MmO)C&n%xAB3)UljLm(X3d7sNwM_3WpZn%58H52x?Ee+z z|IvtUl-UDY{8F;`m%=&!du7`ide95oyV{t@*?%#i8JY-xRgOhHj7=R}{x@u*YkZv? zFe8G9xBpPe7^-`IY$*^Zk^({Q_EQQsvbpW5wNc>hRV6*SBIBWj+3!`v3q_9lZW0Yx_<8+Li+91&*f_Mn=`1Fhx_y_`P{H|9q$G|3z zG!3{d&00L?P+tl^AGq86u9Tjd6r(60RYE-GH%@*q6~;Dt6kN3I#_L@S-lyILud{5W zpZDtnxEuXb1xPJFg*F#YC8rZ2lRLQvTpuGJ=x5D58S!`kZPinXb?&3s8aHXDhjb?Y zZN89I^#joX8~_0EYg?ZDKOdE>p~oL5^yhn+(y;xbZuya;@5lhABByF9+=C*UK`N10 zC7J*i5e0`48u0xjEr!Ml1$Bh>ZQI?w&_pX`6Go#B6VOPxv*j3X3s*JrUT;Hk_K5CT z2YsCEwk}Cb*3?imM`mdMV>&h?WliIW22Uj4#i`h-t*2f?JDGfBIQ+S-+-9Z$Is2HY zNeW$cMwxuEx&hmmxY((9%9kl2xvM%^cTI<@0*YETFc#}sJ?6Fi0E@kJ?{fToi%JPS zghkcKDw<8b{ywPl1*Po~-|_jdB2h{z~#=ToH?ER%0V(h#}^R=i8vf`V|{ZoP?rOYctWQzK?20sHaCVQbXBAX zxiz)EvKPw)|AaBuDJltA(S!kwswO5FGC?TQb23WIDlyNqHpzs^h?RhINyYcO0Xfoq z1cg!rHd%j=0d1P>7Ce`%by9NwfwKbW)iJmQyP#>IeXw=$v?4I44kuFp!!0W>@9Z<- z=gbnJ&N#TGUT)s4iGs%h=3OM(|`k-<%OcZj}K%FS!3iYbgV6#5JU<6eZN)Ot4h-hCW zH=*yG-xwWMS}kd)LKy;jAul*ff4hypu&GlPy727?@hE-lp2O{wu$%>Ml+)aji(2xi zJJ`auIXn9J{oXy>yT6!vjZ3`}W2d(lD_JhcOuXAaKhNB*mYdmnhqE_eK;vvK6tS2&AcD}_syH<2o5_Q09x*ioC};xBD7fAzXsSmP@tBtllY87jbuFY>s^Bvzh)Zg{_L9t$VP;sOF{#69S) z`c^dshP(Dt;;53LEpK+zRM-Z%hQZfyWy;Z}o#sWXTE_K2A@o()u<`R+CPG04R zJd_(ZKHwE3SYuJj1-7+#e3rL@B`6&r0D2-=S+|8{bi|*o1nyT@x@`q!`D4;|ZTX|S zsRM|AcvH9{`a7c?UERW$z5&l+i<9wp2Hjq8SQ} zRZumm?mzc@XC)VkH8|38C>`0aCA>NT(awI0OTYowOISCYKXoUn|F!WAgVmJO(!jO> z&mp*I6e$L8OG`Mz(22Y%bE6r-3=&%LSGnV23~CNHs`5Cnl3|p?+=zp=HlBe-N?0mv zI0uFhdCN7v+55}#8h1dZ4(oZB7MvSoa^)J$n zC*&5J`v_57b4Fw(e62VW-kT0VcPzpPM0wGP<1v4%ey^;bem0#PCj!$< z%CUECDoa~OEZM=tghC!k9;mWd(C;%0L;=2?oQ)W?4nv`1*~=a@Hads7(i6VG7}YT} z=dX+32V?hT_|gzXvBPs; z0xzDIb2&OYf;kkufqBgoL;fj+?5@h1@~%tj`CzlTHh6-mwu7n0tKN_ugZdf?Z7>h+ z%B^16nXqFmnAr%i-)2E4S6~)?C*H))IsxgZCq;voMYdRv0yjtzXSa>bC%IYZ5PrGQ z0sVPuOqKp^ZYLPgB+>}oiF|fbqCTM9A7-bGT71Uv`Z#yl)Zf+VWR8`>;Wc0P*9)%Q z)#KLw25t!BR`N$@(H?95G+NYf;16CaF7UP~F@L-k+_ML-lWZf!_5%j0P2-d81D->e zVFrxK_|mcnn_Z=KW?gj6%-e_h6$H$>tDqI;i^|w^BTfe^qnQ^4kpXmBKDaCNHlO%5 z{K{;JN#&T#>eI<*bq+cCyE3Wt@;a?cry6!8-lA09F6ITV0XMgeNyp-;6Kv%qc)~R0 z7qdaX;Yw`yMVq=dI`fStciR96_9_`fY3}X{uixM#C0BtyEYaA^=gLX`v)G5<)HE#^ zcpyfRCuLxEwG@>0rt;jpjR-_zf5_CT<=MdqtClS8wAA*FF17d za2c$~=5zvmCMM}$*4jW^D(hA9K03g1Gmik7=#AMwA%Lu*Zm*VGEcCV^Uh}a8-PaVR zx;)I4@28e5?fp{~^N;vusn(Ib_p9}7{55Dt^?!BR5?>s*_D+Aru|hEjGrQmJfDR(+4YMg}RUkrpefkYq?ddpTA86^E z`B|Fez{ykH7mi9XV%ohI7nT^IQPt%53%uvJZT7h=-ht!(R;G&D{Q~BCY3IZAa2Rr$ z?$d+D;38P9t83yJo??UUH|vlb;Iai;>YhH|Rk=PV;T^qK(@`k5Ef`ymQ%C2{c_8j* zv*%{M1yxb+0l5J*u~LDTh`Isw>F{H+n-L+DoX)K>or&pA$f9~O7y3^?yWEslZ*S!0 zk?J|I+Gu9&DO!RkP-kfaX_CdGhz}t8l*vF>{D==_(zrL}$O30OTYxd z&BSq!wn1SeQXV12Ic)hlede_vl@)C$pw#ih_0S(rtl?srBnl^*Xx>rpSqwVX#FuTr zp+vYjdJsdTiCUXX=MkTP#)^xN4amRKakC2gT*k3wt>dz-^%6GupPEEq7*))`=S4Rj6yvtfRZn-H zNTqByb_l)DW8kiDYTSpMFANAy3kB)y-#) zDWHf*3=ezJoRTNGdaYVUuFao-PYhq!#ase!l(}vx!Eh>dH6#~N;dJ*pcWH&0J&Dui zw(uS-J6+cc$RT%f2Q781 z?z5ep(tz1BqgcA;^$C4KBBGzUg@%Z1;?;>NU)o&Do*+?TVqP=3(@fF^=0xgCWe}7_>hFv0T+Y8QV#s8BMrC~nckR)HAM)t@!P=JG`72De@{Z-! zI(!nG7$^A2ZRP3(MRF4K6~f*IwEFx9&DrHIxE!NAs*Wl^5GLc&yYe*eN!=66i2>-x9`!$kL=osb#h2QobYnF!J z$RjM|dO#-B=B*iUk`$VIfJ03Qqyub7kpkxOKt?a-`YKEB>hWBw9a=S~0^!(ag5br2 z@80dn%M70z^PC5yH9bbwBd8#C{SU0T7l9g6~i5eI-0?;5BH zVYpqT+R7)aY_{28o&bJ!^Mq!LBhAgp*c2Pi9sRAp5 z4cWgJHGlvC5NN(~+|#d))_*8!IQ_};?MyFbXldi>Wcmjq!{0@XKD+)e475jT8an7y zpI(d(+j$bXH^EUI258Gej$W3VE9o^C+Gxp%v0HDy-wg{`uZGPKu=WppUPv*=Xz6e# zLmX2W`H8iqR9ua)(7&eUPACrUBZH!!>v9SnN4+*x={^R1iB%F=g<_U#LUl~u$h~oW z?P4J%fHlm80`lYUu2luSXcy)ngk-lkMthYBd4)H@SJlO1u*KcV^Dgg>MY;J`6=#6~ zCL+wl=+(#HnR2&_Gs<-cC5QIQ4i%~TPLJc&_8%<@z!227k?J!gv8DSve+%H^G zp6StW>KL}6pyg-vQL9#_gZ3mig>&| zYkcsagYR^KI5`b8ML}Bdr0za*n5wFRI6s#Sv8`8Pg`wlGjeONmrLjZI%%?GraLV8; zNo1SGRu&WzwkpqIUqKwW6G^DwZ6XVPn?DXJwl9;ZA7uXR>I5BshSf1immP8(HNFJV zXnR8%Cd2(ACrDr?_#oDwGete;@$$^$n53CS6Nl2Z8Fo~rz%_(IDNuRmRX`~;16Kv6sO3q8hWX%Gwe3L(WTrX!Z7JsrLvHdN|h zGUrIysT+E;MUdx3(m_m8qz?GVx&&kNQrsr((%>LelLZX!M&_D+ZkKk`F{Rb z?+dEdaDv3D5{jmLM8C~K^JBgH@S0SK4X;(P@9oeJ7oww8_b$ZHYD2yky=)Sv?Q%E3 z|DNwiQQF_!QcsM~S5FgYt;Z>9Gs)COTs?(q%BqolIO96p^}94b_Syx|V#VIp!Nk9f zPO1l44(okg-Keh)IMe_A>i%_OWer`7ExzbP{xlmyDsy&g3@E-c>N+eTOQmZ+7?M6OM?x`O=K}|gw^ociags(wX!J*?^1pe*XP?$&v0*c$bBV1r_=en|egNgJp;yHT#tWLNvVk8|yAbN!=r%Xnxs4Cr zsR)8&>dKrNBwQMbW-tE92dpKSq%WBUS_jY~1d$bp2|`A?vYDpA2er)6%XM^uR5!z2 zEW^dJZ_xwOK1`v(K#2Vf-=$!~JhSIU$ilW^ABUIyWmDftm&jqeOIG7IB@Z_bnh+zT z%7PI-LG?AdOTsO{1AU*j$z>x&9t>gjzRa<=XUzI;_xi>1)_KqpYq?XXb?T$qq!7Gb zlgsJadfQx7N-=7c?D_2xTnr*99ue2F7Ll?-(~)`kb?&99#-~kO_Z zie>8Bua=3&KIuD&L z795*8J>U!9#aXVJ_52&dkZEPB_|}()YxyeM|A%>vzX&#*=|$~~ZS0**P5!*6zRI%p ze?ok!UpJF5B)uZJyla5NU@I6(>I(O@Diu~6J@i;ufy;HdT0cH=#76`bm+ z&$NqP=c&q%VJbbX88hH=&8vkR;DokPK`lJ+&0^YhDrK5LsDJic`NXKbk9Vw_*u(@b zpiT_s2Y~w6@9ZGoM+7h^f$TpSQmCkngx3XQi<7eO0d${Lw`lZlb;yInII_;daf7yi zBXI3&aRU6XkRrhG7UphsPkul=XCju&K)pVoXIZCh+s1$mQz6|g$Nsgk zsTeD`S04G4k=kb>l_^Py(kSs)ubyz>B8!igP&B0mayAn$$6Mc!uSIdv^)TTGys=%D z`IX?_^z49l7tZ_WCARkxg2MVEych0GC#Z9_YDxBKqAA?fVrZtcJ#8cwVh;^nr~J@v zQgC%_e1{TLA8|`YG$?licxhu34D5c z>`>j)Kdqkq0dMSgCPftVWz7b^KDz(js<~L0{x!`YV(4P1VE;v1@>d`f%?Q^o00ZLP zvnOTo7RW-Gn+qU{$kUrOxf{Py67@|WyvG?86m|3Rmj&|>HYuDM5?oXyF+US}x<C#O1s zmg2Ef-l(ClT=o*49)SJRKMfB5A2 zqa`9pQR>Mrmy-ew0Kon~P|hFISGJ~KV^_+S=5~fIUm@#Xen<7M_k67GklHWEYlz=M zI)&hZ!C(LkM$?iDu4-oF8fzmVwQMx%k8jFdXELGLKH=hM#G4QohhN?LG}Z!9v{fJ0 zm5{Ql9HMoppsB}@X6@~etwMalZ(O%;pV&724w)=%l;3Yt;?Wdq}Bnsqx*^j+8vwZ%K; z+8fA4E6Fh(f@3HX9v00YmS1+BAyoH0t+{(+P6FUi7#n6ipZ8gZSKWnCR{J&a<_2U( z&YUTI+UnX6iO~OR^cn9i4jN%|`%coM*MkgiXM17p_Pe%^BV$lNOZ8UL`U_lnfGL#j z$wRjPh2pL1leG^pd+znJr@{Qu$#n5zyo9M>!eJ&R?-6f8r9e{?r>?I4tImcaBIZo} z;1G_Ol#sl&XDS?(Vg-(5X0LMGG2uKUnO1p>N+*XUTnf>Q5rn?iNlN%>Ah9NB_kyB$ zw+35kC?`kR1_P8G4>b^oNoa$sehR1)Xi!BFf`%r!op_|4ITP{O_Z!E&bQWplmNVbL zAFgfETu~aWiN;vzT=U`EX||hz*?diL25X_!8Mx!Ej?EGD$D&$`M|lLX8<@0NfQW7F zXOLRk$lL1)&29Nt3W;x;Se)#-UgBT@@@T4Nz34{4D!KCW0eW*1S5ZW0?%k1G`fX@4 ze1vMiY!xBPdKGvPb#i{_)>3hY343lw-6iCC>f%9fx5Rpeg7jQTP%v)>hY8knAI5i7mELfl0~S<}cV zbZ9) zk9ULuoq2kFi%*!WCyymVYC**936nc$D=BwigwUrS{aJC6LD=Dcg5qX&w;iViH2oiEm z~%yihlLKj;YS?b{p62op<+0K^3Tw!)sO$R7N>Srav&U7b4dlVBiS}ro;*! zqflp)&a^(8?8l`s6vfAH?>{N^{#AHkZ*fwQFTv-(q8N_Q>;^3Z+sEewpMo%!19(X z>IwKC%9S3pb!3$40fo=$_FHMIem+=yalS}-mjE){k4j>t@r`C(yv%I;)^04dT64Lw z4L=~sLHM>}=FB2fpnG6vsu|AC6zPetBtGVg6M^=Bpc$3F1BgG>(S<4Nyg_z< zsW0d=AL}jw&uePjQl03MWoaXSQ5Yrzr(xtCp;-rPVO-Mi*##dDl7OI9vfw14cD=Rl z>%T)ghCdofM5z8`t;!U0x}PG|oL5AKbIyvIpxDI0Wt3SJkL63s9mGkgt}#zq(l&gB zaX4i3_Ex_Uk!3+P&P}AQ(&IaM`qPKZfiFCW7Bg8lUWz$(riet|pP`7@+^%Ewktv&6 zv`9P+0c{%smOI*^*SKOHXCGSeW>4y5+ftHr?jCs;6*rPeG$T1<9LbHx^1XCGk477L>|-TT&{8Zn_GLFgoQ6`Mq>L#oHmy)^$cR*6A+d(&~`t z1wxD-B{C}NgHNc|Y7vaG0inj9QyBhe1m?5}Wg8`OR0)|uTGe1<(varY<;Up9fZsNP ztQ`o)ci4M8gQ;h=dfWgmxeW4&`&~4T>g?hK!!&MT3+QB`-;?jL>)j?|wdt%W&;jOO_*gN}O?^9U|3xs8ze4~Q z&EJvaAtAy+ep##}BH0aQKRslo?FtDOZ3tu8>s@V&yrR6nOh5d-w#QbcWdv9Q&W$_}ESX!m7nu2(l< zw)$(Uehl5OwVY|rHW~Lnk0h+XYMFd9SyoQ2%J{9$hV9{ILE9kn6YdQOhdCuvcOSoN zg{G4v+I&PEB?-{AkP5o-VXJT%#0Nh}ToBamSDeJTG8FORlWOZb6mHzsN@ZgBD;bm5 z4or4rx=K&#ko`1RmMq3fGbf_Z?2V2^hh3~CIV+Q$#Cz)Z$ub+Ga#0OC?AOeM3wJ&y8Y z!&_kMy~qzxlL85(l!swlc58a!mg2{7z{~7hgsu=f+LbWRKKPg4PP`{^bR*WO^gCEk zZQ@qP7Ym+Rvq-^P(hx&Ay+u;XFx^;~W!cwuy`GU!fdsjm%?_;q>iE6j?#lQq+l8T0 zol)f_n|d;aSqgO*v_vF9W7MVX6|CWrYspWTscrl%pIHD6)u=gtvk!s7E@vcxKE@%n zRCmi6ULp=cMQdy3Zwj##bzHvtGMQl&gx&5edCbNnWU$vw8|P&X8cs_c&92llN9w4G zUA1TlnUqe-#GJkKxiUyXipdktnY4u6=b*dW&Yy(kNczLObOLvGe?o;f+u|-b;_|^2 zNS=+Gcx+!a3d(q^%dRVbm zRHX=z5zMtt1Q)nu8*fV*3xe}TiFuo(oM`(@3IU5LIiKUiq@EpBHjgVQHQAxCGxf=o zY)Rrj^{Hga)#VZV=t&c=7?&H)3(3~&bR<^}Z~5>@anKr`6gyrYp+%3ppzt5(TFY9- zi9xVJHhrmKJ^cl_gik|b!ov#3tU2Q=uG6qE5S$Ii=v11v;8e6+uwO|UoIrm9H#jJ_M{iKv{s3nG*vw-SQl*upGZyVc4^mQi zAG=|^&09q<&sQrn7(MyX6}CblO-%0}!!=+%tZ$cDf^=7zF>eWb9AQLVgh|}I7A+IT zeP7#hcC*xNnUxi+vf1-m;Qvqg=O6uLJhB6x%r9?v`t?!&Prc&b;aP0mAK{tEqff|) z+Zen{U|=9%Fx3+PyQ{R6m3Y~=QiM-A4UDwbQEqu48h&F0K z8y@N+K-|9PJFAeAzM=)uBNH5ROV}gG>@{+~aeFlUUU!gE#c9zHYwtv= zGkL{qH<&^_V)Bbk2fNRfCTU-cu`NwzkZobO4|csygQ+PNR$nrw^=Sj+cP)m#KYgpr zW2OF?N+k%p?)MEy&C(BoO6W?|g{8N=Z=J@mzCS&(h8o;g$nBpeVb+~Qeo0lLI=Ai8 zuVk2~+Y~rDl(=yar}4C)P0c$Q)QlzX4G(K)J7M;a8@sP<=sC5_oeDl%+iixJpyj1y z;o!>dKuGb^>Le1w$E$+Z)|#Z0BKlk<=cplUALg<{s~)X*z>Lo<=Kfjuj@| zF+0#5n%3n70YCBLF*h*)Ky}Ligt<;Gy+#=?<@+^xj;4@)9w3MjIp>8*%=wcPQJr&WnmJZ=zPniF3+rapKJDdtMAU}a!Ni7fnO>YL# zHs_8;=R&s-xAs2G*nHBc|8c>$n~sc8UCj*lZ7n;`kfXS%oJZ7e_nKv zq0%&3wr^ZKL#hqIi?CF;*v1qW`6Bj2XI!v*Ko;20)lLo0ev>Uv3|ReA+EHXVi6f6M zaAhNKLPgVhKyAE@httHuDIt7fu=Z=g`v3qc!y1xWB~~#2@=PYW^jMvpgu&vr^=;ty z9YFNQFut?X5=SSXGO(gevC;<|JEtfCD_>}8TZ0PNFx=Bx-I1K+QuXOvyZ&9=mI%Zm zdU~m4J)`{TI1TTMZ>ZhLey$UpN9-D^EXRZdQrb`PcwimY)-wRAUF;b0@^>FVC^p!5 ztEKm#+C|7~=nr#A2=&g5Ezj)zv3FlKs4YQ3)N2?%5?a#iRBoA4<)Wc}CYWMLY~z6J zbuAFVRzMdp^9M+hJETGGC)rO#u$u;egNk!{SJ&>$&NSYZp9&fIH%+~m;uW7xL;Cjm zkR|0l_*#`00k9A-3f<{_AcSQ!j#`ATWs&hg2i za(T){n?2_IVpaCblJ#Q-U=*zJCi#F;Q{V$X;4t_R_u3nQ+IXxo#iBhog&JVr@J4~t z_`3_0)&uFi=|g_PZ#v$ciS}81=1L*5A!uOo(_hb6&f(4W@jX>@Q?c!?-8kY;`!cXe ze2;Q~S@17;qCV;QEWR6-F*Jb7|F)oq)33g-0ep>9$Tf1Fug2CS>+8dgQHG!wVjm44 zb+0;a7JnTHXZ4HhiGRRNY^uI5b(VjU0wyq~m~tdy5dFgCXT*h)_1Njd;s_zaPa6i- zt6LxJ)cOLPOGrfd+GCro{Xn3rO$XZvVWJv5PE_}M{dIZ|Oa4dHbN6GBH90e^4&|0E6Q2MIi6G!Fb9*n&{Bou1 zg8(2JUSDE49wiaf@%p=K$Y^Qj1$hgBpt(h01|6KYP|~u|GJ^yR|=9^wYQ{)gVd3SbpkRjrx z3Y%4tK11%ktFxt%=c3_T!sgXh!uPD^@~J`8wCh^XnldGA1gLsdXwj%8#GGVG^z%?= zOHvh!eD1nz+SNmiI0CVAYdEX?DsREi*w6`LEa`;T*aW!yJcA-xnX}?SD zdoW9sfx-cfnrpuVxd@ht3RDA2eR9E%vn|&ms9?w7#XND`tDP}{`uNPBxJ3GmmLsyO z+_ZG#->w6>t|wV#NC@A`a5f0;U3Y)<`n?4|n*X|M_{RHtDcO@w>oau}r)EF6)8=U! zZmrFdbaJ5jJS(FfcKQY53s!89a^sMfLn~J6hsvC^M*-MYZ9pm%fv-RP|wv)!TjmEaw*tV0#O&Z&_ZKr8$+qT){x%b{Pd#0T;|8t%f_lth| zCcpJvUe~%-Kjg-twG00-S>y`w%oKO7g#<+2NGPSzJHoFyVt{~292Q`3p$o_pCI0{9 zh<|r4%{`2b08Kn&hd)+IL>wG!|4J4Cth?U;>qG$7U06Rb9CU$+qePn(UK*OT>8Or) zydU=*s-@!R;-&=>m#|haF zdA)>xz=bLS2qEV^x6wBvml!AcqG@@&EUXYiU0>3V=V7``2~_LW4G1oQ0yYygK?Cev z!2ENkc#u3p-#p%dY&Pct7+f`YUtrpYlET*DnS~Ie)lg->FW~l0@j=WBl2Ig3zE`_VbtE9eR7e;fZ8T7&~2sK zZXw8H*KGai@QuhliBtTDT{g#el8hj2TdFsU&i;7Yu)cj#YMrg)$nyAO6iuM9JW(#fjb8u57^K@75f%5 zT;2%V8iiL`bC>_5dHBE?-0t5KP-MP^WcGGej4c^2fVOe)O(G{`Y3n!rJF=!!X$0t< zB%pWve;J%P{$m{ANdE_?iLsHK&7Y-7L?rJYHCfO@I?*440Uat5aPVw@CPMI;)Yw=q zg;*lQ?eqL?IYIHwp4!Zxe4oC}0pY~{V4b`#2c8^?Rl>FBhtrq)L3zFDY1u$@z)YxY z8Ua(=PwX#h^C3m1I~%soU(o3X<;z7mgQm&>`>k3eFs{qg>Faf7F&^CcYg%UfF36mt zk2pM4#Cj2tZ-*S8f42cEHTjG^l~q@S|0tT+Av|@gTxvTc7B$^`TFwi}*msrH-%8Tl zji(}dfEdmJ=J@IVV2b}KieIX=1ce@1z^nuSeJju4g4zS25IT)y$tR@y8erbB9YdP1 z6HZv~OMWz8G9CN@Kll5+=Y-Euwa-9ex0L1lR1NmBGf6vPks07F1xBHs;3?M#Ne&hC zy3=P=fZ?GeRHS^{Jm7_>7`F_$jeeKe2LfZyCy}zjwLmR>L*R{kcFkXi*RQ`pjJ2XG z3T=C|XbE06fV>nJDA8#4!!b)@kom%_@<>I{zh)psv?~A32N))1(NlYM-2A_%22Z&X#Sh`^BT06UV8ZQ@_5iQ)Y2R3|cW%4M~ zYZC;kpCize?S@_`9uy=TL52g-I_)L$CwHS=9dNdLszXYU>57iA;Pgv-ffzlyw|PGa zj4P5@TUBEUY2Q}13qA1Afg!F?%?d2X4)_ukSX!O)b@q4~(|VIq;)|N~t|+2EslceR zlcK}a}Tyr3$zs7nsh0aBKglHg8ODzC3Y|!@w`O5DR9%? ztiIwDpYj@biVdR!)<+zt)L}a~rdC*k9V=*3$jA{Z1KcZNcz7#EypH{=6Y7C;KHxIf zXuei`(9FqN!C9%nh&@;c>k$yBMnjJ$>vmBFni0UzmMSN-U2#%=Og5D9u7rUNdP);j`T#sUn9UcHQ&gfT$`Mb~A#muQ_e78B#qV_La7L+JGk>->h0+0Z2jk&sH(ZG6@VGT z=-0i`HI;v^3pa8O`RRl3{&2?XB=5_pgR7G9N4o41t>E(R{*Ix*msg@0rRc+tQo-t zw|LHs8^^&2V{|_$w{mv{kO0<=Y*4AEkM!)51aa|=$Dj-v{v|5plE{reV~2a8DS6Q| z`W=`83J^lV7-Cd4ylT@GO47OA_z{k3XG*R z3t4|XcsZcv2#C@x{%EfJB_vmX6>=3ui;{HEtoS_nu=*2~;pW&e9t@7XXNke(Q9q|L zuR=H20K8j*Sc_0gVMo18u2t*Y7I~5RIGLAhZir2CrAUS+1um;%lkYu20tf%*nqc<7*!558$ z-qUVTtMhu6;WENM_m>2VL`)ObYe~3WBKA`AXu=!&g|cOvOIZ8 zWLip1TTS5uE5qdxwa$6>!}W}ONW+y3cn^|;!`{)wqx5O_4S?8Flg32Gv&gJpX=`|a zo~D(Jn%pR!vQt`II2|}&8QmKLZ`da-7Uin z$ZAJ7T;}Y9h5UZN-i!3v1uuMI$y=^I1RnGZ%~*6W@VtdZi^ zRp~o+8@H!(6Q#>BVAjtP8ZUd{%aNsRs3R)6msO)Q>t^iq?R;3k8w%pu($c_IyVa~( zgh3ki1BbEdB|%cK>6-MSpa)m6)VI5MQNAeNt*q7hlapFTp!eLSX)*w_!dDoQn^hau z0=*W&RhJXhxAk{!Kz;^U!7Rf~jS{YD z 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 literal 0 HcmV?d00001 diff --git a/cots/org.junit/junit-dep-4.11.jar b/cots/org.junit/junit-dep-4.11.jar new file mode 100644 index 0000000000000000000000000000000000000000..93c717aa8a1a5b0d107f3f3ac585b237b7ac7fab GIT binary patch literal 245039 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к(}LW_6mdYXD&~zmR5xB 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 KlZh}0$ovmwdV<6N literal 0 HcmV?d00001 diff --git a/cots/org.junit/junit-4.10-src.jar b/cots/org.junit/junit-4.10-src.jar deleted file mode 100644 index 1449d28b5b963734bd8561a697b775a6b2126ccd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141185 zcmbTdbCl-El0RIw)n(hZZQHh8UFhmUmu=g&x@>jXwr#&PGrM>1%+8(to%cB>&w2ic z_-2Ma84;N&F9i$&1poj60AQ=b%LnjpKS%%&02vWw0U8NeQM&gL008;_B8333`6TTJ z+Y!+FB)9q;D4*kBq%s1s5~3nX%Cs_~H!@?R(o!_EQ?ODrl)uI%>J;f`nKt(v$Apj^ zsKup!iK_sF0+P_&hP$_z^!-+BJDcCgO{S-RL-IMe<2qW?Dy;=gE2+?`Eqoh9VArzwA@_`ihz@+UeIcY6~@3mX$#X9Meh`}kj1O8B3dj0~Jj%7 zDgPfnRFJI+{4Rm^l5T zq5te&{}S(y0Q@Jt5d6KE|IKJ)XKeECVe!|P`#;znU9A5xDoFo%b|>f0(E2Sj|4D*B zTlW7!%fF%7Z%Fb7PW*L=f0ghzsQh>8{{zu*|Bl?oz}CXv#oEC66KDS+)c=;(*3Q|& z)Z!Ck{>=N=Wg`8}y#KDXztW@sE&ZR(4e|TlQoN-DD+B}pFainyK=R4;huZ#a-w-fz zws193{`62K7Yk<-T1x|0g9v3Ar!;y5p5CfOA_t_^^b8;ORaeq>XHp3#H3J4qpkEX$6n62Q;j{>b1u7&c5hMfs?2ofiU?k1i6rB_@pX*Mn)S9Gng=O z83(rFMWJA+X0-v?*pvlx!fUjdgPKdfQKkqK1~^s2I0qs6jjh@RzlP+Ej0`B*gd>f? zdI0$ulD~!fjU*UsmrKoVMMcL!N7YB=9nOU(m^r^(1^90)f~x}d8gvC~>*UBhFA{cj zgg*1D9my2J@Z2Mjk=J#EG_38*c7+1m>GOZc6q?=uMKxCwbzix>sSNS+g|@ow35cJfVyW5tY|L; zoZr$faVud-4DBLPZmM zlTWlT{>=}6cR}yiQQ2O41d)YdweVI)MU+-Le1vNKz}b87RpaGUQdef&CXwQgNHR!y zToc46h6T6Cs+nWQvIPjbZcN(CF7tMWdAXTc<_aQQN~&qta~zv6(65>AYUw%fF7f$E z9+`r0ZkN6VMB|aZY^mSa2*LQ%IbBVCh*_h&FHh;R3HymZ)Wr?-5Hij#Jt`R{t93<%(XOR}oxS=?>^F?@w zLVUXS2of&rk^7o+8XoYf>v>x`NV3b1#(BJ*MEDUifbo#Ql)xSK{IwH;SZKo-RY}!P zpYRPuI($2gF8Qii4bEeDs>e>dxQwGs)kMdBI9A?n@7#MNupaw)===(MBYk+0rTT>I zo6cK4>yMb{$EsQdx1$}dKN}1IDUsXY(_l=%002aPXRzN4C2V43=V;(;=lF-k6a{{> z7&lqfqR}CNH-Dfos9U}w?&f0J{N(b~*EPbN_lyP{7LW$)Q}s5cx*Z3w0=_x8Eh5fQ z8XtyM{dVZG*2ckZ^=>xPe=E!_z4KqX0GBCycvz0j6&p*#X~ zR0e|37l1bomZbnc#SY`0Zv_IQx4=A4%2&SkI>j1oi8~O7OuDN2BD6^l0BCX?B9t3l zlUg!&;l?v4u9n5!#l-3dF@h0b9AcQz5m^I-R?0wVjD8JX>pq@ZTy>Y710f&&ZtT=W z#7WEkSXuU+JI~Z1n#vne;aJ3(bir8s`ZBs$1&nXMr?ir`N3vUW+e&L13DAL4r&MNq zPvv#Df}&c+dHhz8|LMj`oQiQ=9Y-tz6N$ha4~J~Aj$7UwDk_?&#WCle&ag7Zd(s