diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1ee2e3bd..1ab93696 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,10 +1,11 @@ version: 2 updates: - - package-ecosystem: "maven" + - package-ecosystem: maven target-branch: "develop" directory: "/" schedule: - interval: "daily" + interval: "weekly" + day: "saturday" open-pull-requests-limit: 10 - package-ecosystem: "github-actions" target-branch: "develop" diff --git a/.github/workflows/java-bundled.yml b/.github/workflows/java-bundled.yml new file mode 100644 index 00000000..77e83eed --- /dev/null +++ b/.github/workflows/java-bundled.yml @@ -0,0 +1,59 @@ +name: Update java.bundled + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * SAT' + +jobs: + update-mvn-property: + runs-on: ubuntu-latest + name: Update Maven property using the latest release version (tag) of a GitHub repository + + env: + DEP_PROP: java.bundled.version + DEP_REPO: adoptium/temurin17-binaries + + steps: + - name: Checkout source code + uses: actions/checkout@v4 + with: + submodules: true + fetch-depth: 0 + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: 17 + cache: 'maven' + + - name: Get latest release version + id: lr + uses: pozetroninc/github-action-get-latest-release@master + with: + repository: ${{ env.DEP_REPO }} + + - name: Apply latest release version on Maven property + run: > + mvn -B -ntp versions:set-property + -Dproperty=${{ env.DEP_PROP }} + -DnewVersion=${{ steps.lr.outputs.release }} + -DgenerateBackupPoms=false + + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v5 + with: + commit-message: Bump ${{ env.DEP_PROP }} to ${{ steps.lr.outputs.release }} + title: Bump ${{ env.DEP_PROP }} to ${{ steps.lr.outputs.release }} + body: ${{ steps.lr.outputs.description }} + delete-branch: true + branch: PR/maven/${{ github.ref_name }}/${{ env.DEP_PROP }}-${{ steps.lr.outputs.release }} + labels: dependencies,java + + - name: Create summary + if: ${{ steps.cpr.outputs.pull-request-number }} + run: | + echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" >> $GITHUB_STEP_SUMMARY + echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/java-ea-maven.yml b/.github/workflows/java-ea-maven.yml index 6ec751ac..7906c032 100644 --- a/.github/workflows/java-ea-maven.yml +++ b/.github/workflows/java-ea-maven.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '-ea' ] + java: [ 20 ] os: [ ubuntu-latest ] name: JDK${{ matrix.java }} on ${{ matrix.os }} @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 diff --git a/.github/workflows/java-maven.yml b/.github/workflows/java-maven.yml index 96ea2107..3aa58e6d 100644 --- a/.github/workflows/java-maven.yml +++ b/.github/workflows/java-maven.yml @@ -4,7 +4,7 @@ on: [ push, pull_request ] jobs: build-and-test-job: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + if: github.event_name == 'pull_request' || startsWith(github.ref, 'refs/heads/develop') || startsWith(github.ref, 'refs/tags/v') strategy: fail-fast: false matrix: @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 @@ -28,11 +28,31 @@ jobs: java-version: ${{ matrix.java }} cache: 'maven' + - name: Pre-download dependencies with Maven + run: mvn -U -B -ntp dependency:go-offline + - name: Build and (headless) test with Maven uses: smithki/xvfb-action@v1.1.2 with: run: mvn -U -B -ntp package + auto-merge-job: + needs: build-and-test-job + if: startsWith(github.repository, 'jdemetra/') && github.event_name == 'pull_request' && github.actor == 'dependabot[bot]' + permissions: + contents: write + pull-requests: write + + name: Auto-merge on dependabot PR + runs-on: ubuntu-latest + + steps: + - name: Merge PR + run: gh pr merge --auto --rebase "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + snapshot-job: needs: build-and-test-job if: startsWith(github.repository, 'jdemetra/') && startsWith(github.ref, 'refs/heads/develop') @@ -46,7 +66,7 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 @@ -96,7 +116,7 @@ jobs: steps: - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 diff --git a/CHANGELOG.md b/CHANGELOG.md index c0cbe4a1..7290d80a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,31 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [3.1.0] - 2023-10-11 + +### Changed + +- ![OTHER] DeepSelect instead of Select to read MetaData with "." in key +- ![UI] Modify menus for reference specifications + +### Fixed + +- ![STAT] Correct deviances in diffuse likelihood +- ![STAT] Correct covariance of ARMA parameters in models with quasi-unit roots in AR +- ![UI] Save correctly modified multiprocessing +- ![UI] Fix non-removable star on data source nodes +- ![IO] Fix NPE in grid reader when header is null + +### Added + +- ![STAT] Add Poisson distribution +- ![OTHER] Serialize High-frequency series (modelling part) +- ![OTHER] Add auxiliary functions to simplify the use of JD+ from R +- ![OTHER] Add specifications and auxiliary functions for linear filters +- ![OTHER] Add default modelling for seasonal adjustment (STL...) +- ![OTHER] Add handling of time varying trading days +- ![UI] Add export of SA documents to Excel + ## [3.0.2] - 2023-06-14 ### Changed @@ -39,7 +64,8 @@ Install instructions are available at https://github.com/jdemetra/jdplus-main#in This is the **initial release** of JDemetra+ v3.0.0. [Java SE 17 or later](https://whichjdk.com/) version is required to run it. -[Unreleased]: https://github.com/jdemetra/jd3-main/compare/v3.0.2...HEAD +[Unreleased]: https://github.com/jdemetra/jd3-main/compare/v3.1.0...HEAD +[3.1.0]: https://github.com/jdemetra/jd3-main/compare/v3.0.2...v3.1.0 [3.0.2]: https://github.com/jdemetra/jd3-main/compare/v3.0.1...v3.0.2 [3.0.1]: https://github.com/jdemetra/jd3-main/compare/v3.0.0...v3.0.1 [3.0.0]: https://github.com/jdemetra/jd3-main/releases/tag/v3.0.0 diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/pom.xml b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/pom.xml index deae4c01..06c129c5 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/pom.xml +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-sa-base-parent - 3.0.2 + 3.1.0 jdplus-sa-base-api diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/jdplus/sa/base/api/SaItem.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/jdplus/sa/base/api/SaItem.java index 4368052e..b9621e32 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/jdplus/sa/base/api/SaItem.java +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/jdplus/sa/base/api/SaItem.java @@ -35,6 +35,7 @@ */ @lombok.Value @lombok.Builder(builderClassName = "Builder", toBuilder = true) +@lombok.AllArgsConstructor(access=lombok.AccessLevel.PUBLIC) public final class SaItem { public static final String COMMENT = "comment"; @@ -151,6 +152,17 @@ public SaItem withTs(Ts ts) { .build(); } + public SaItem withTsMetaData(Map info) { + Ts cur = definition.getTs(); + Ts ncur = cur.toBuilder().clearMeta() + .meta(info) + .build(); + SaDefinition ndef = definition.toBuilder() + .ts(ncur) + .build(); + return new SaItem(name, ndef, meta, priority, estimation, processed); + } + public void accept() { synchronized (this) { if (estimation == null) { diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/module-info.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/module-info.java index 90fc70fb..152348a4 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/module-info.java +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/module-info.java @@ -15,7 +15,6 @@ exports jdplus.sa.base.api.benchmarking; exports jdplus.sa.base.api.diagnostics; exports jdplus.sa.base.api.extractors; - exports jdplus.sa.base.api.modelling; exports jdplus.sa.base.api; uses SaProcessingFactory; diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/pom.xml b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/pom.xml index 718633f1..621bb6e4 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/pom.xml +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-sa-base-parent - 3.0.2 + 3.1.0 jdplus-sa-base-core diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/AutomaticTradingDaysRegressionTest.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/AutomaticTradingDaysRegressionTest.java index c200bafd..44e6e415 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/AutomaticTradingDaysRegressionTest.java +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/AutomaticTradingDaysRegressionTest.java @@ -142,7 +142,7 @@ private ModelDescription createTestModel(RegSarimaModelling context, ITradingDay tmp.setAirline(true); tmp.setMean(true); if (td != null) { - tmp.addVariable(Variable.variable("td", td, ModelBuilder.calendarAMI)); + tmp.addVariable(Variable.variable("td", td, ModelBuilder.calendarAMI)); } if (lp != null) { tmp.addVariable(Variable.variable("lp", lp, ModelBuilder.calendarAMI)); diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/FastKernel.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/FastKernel.java deleted file mode 100644 index dda7445a..00000000 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/FastKernel.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2023 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved - * by the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package jdplus.sa.base.core.regarima; - -import jdplus.toolkit.base.api.DemetraException; -import jdplus.toolkit.base.api.modelling.regular.ModellingSpec; -import nbbrd.design.Development; -import jdplus.toolkit.base.core.regsarima.regular.IRegressionModule; -import jdplus.toolkit.base.core.regsarima.regular.ModelDescription; -import jdplus.toolkit.base.core.regsarima.regular.RegSarimaModelling; -import jdplus.toolkit.base.core.regsarima.regular.RegSarimaProcessor; -import jdplus.toolkit.base.api.processing.ProcessingLog; -import jdplus.toolkit.base.api.timeseries.TsData; -import jdplus.toolkit.base.api.timeseries.regression.ModellingContext; -import jdplus.toolkit.base.core.regsarima.regular.ProcessingResult; -import jdplus.toolkit.base.core.regarima.RegArimaEstimation; -import jdplus.toolkit.base.core.regarima.RegArimaUtility; -import jdplus.toolkit.base.core.regsarima.regular.ILogLevelModule; -import jdplus.toolkit.base.core.regsarima.regular.IModelBuilder; -import jdplus.toolkit.base.core.regsarima.regular.IOutliersDetectionModule; -import jdplus.toolkit.base.core.regsarima.regular.RegSarimaModel; -import jdplus.toolkit.base.core.regsarima.regular.RegressionVariablesTest; -import jdplus.toolkit.base.core.sarima.SarimaModel; -import nbbrd.design.BuilderPattern; -import org.checkerframework.checker.nullness.qual.NonNull; - -/** - * - * @author Jean Palate - */ -@Development(status = Development.Status.Preliminary) -public class FastKernel implements RegSarimaProcessor { - - private static final String DEMETRA = "demetra"; - - @lombok.Value - @lombok.Builder - public static class AmiOptions { - - boolean checkMu; - double cval; - double va; - double precision, intermediatePrecision; - - public static Builder builder() { - return new Builder() - .cval(2) - .intermediatePrecision(1e-5) - .precision(1e-7); - } - } - - public static Builder builder() { - return new Builder(); - } - - private static final AmiOptions DEFAULT = AmiOptions.builder().build(); - - @BuilderPattern(FastKernel.class) - public static class Builder { - - private IModelBuilder modelBuilder; - private ILogLevelModule transformation; - private IRegressionModule calendarTest, easterTest; - private IOutliersDetectionModule outliers; - private RegressionVariablesTest regressionTest0, regressionTest1; - private AmiOptions options = DEFAULT; - - public Builder modelBuilder(@NonNull IModelBuilder builder) { - this.modelBuilder = builder; - return this; - } - - public Builder options(AmiOptions options) { - this.options = options; - return this; - } - - public Builder logLevel(ILogLevelModule ll) { - this.transformation = ll; - return this; - } - - public Builder calendarTest(IRegressionModule calendarTest) { - this.calendarTest = calendarTest; - return this; - } - - public Builder easterTest(IRegressionModule easterTest) { - this.easterTest = easterTest; - return this; - } - - public Builder outliers(IOutliersDetectionModule outliers) { - this.outliers = outliers; - return this; - } - - public Builder initialRegressionTest(RegressionVariablesTest test0) { - this.regressionTest0 = test0; - return this; - } - - public Builder finalRegressionTest(RegressionVariablesTest test1) { - this.regressionTest1 = test1; - return this; - } - - public FastKernel build() { - FastKernel processor = new FastKernel(this); - return processor; - } - - } - - private final IModelBuilder modelBuilder; - private final ILogLevelModule transformation; - private final IRegressionModule calendarTest, easterTest; - private final IOutliersDetectionModule outliers; - private final RegressionVariablesTest regressionTest0, regressionTest1; - private final AmiOptions options; - private final ModelEstimator finalEstimator; - - private double curva = 0; - - private FastKernel(Builder builder) { - this.modelBuilder = builder.modelBuilder; - this.transformation = builder.transformation; - this.calendarTest = builder.calendarTest; - this.easterTest = builder.easterTest; - this.outliers = builder.outliers; - this.options = builder.options; - this.regressionTest0 = builder.regressionTest0; - this.regressionTest1 = builder.regressionTest1; - finalEstimator = ModelEstimator.builder() - .precision(options.precision) - .build(); - } - - public static FastKernel of(ModellingSpec spec, ModellingContext context) { - if (! spec.isEnabled()) - return null; - SpecDecoder helper = new SpecDecoder(spec, context); - return helper.buildProcessor(); - } - - @Override - public RegSarimaModel process(TsData originalTs, ProcessingLog log) { - if (log == null) { - log = ProcessingLog.dummy(); - } - clear(); - log.push(DEMETRA); - ModelDescription desc = modelBuilder.build(originalTs, log); - if (desc == null) { - throw new DemetraException("Initialization failed"); - } - if (outliers != null) { - curva = options.getVa(); - if (curva == 0) { - curva = DemetraUtility.calcCv(desc.getEstimationDomain().getLength()); - } - } - RegSarimaModelling modelling = RegSarimaModelling.of(desc, log); - RegSarimaModel rslt = calc(modelling, log); - log.pop(); - - return rslt; - } - - private void clear() { - } - - private RegSarimaModel calc(RegSarimaModelling modelling, ProcessingLog log) { - - if (transformation != null) { - transformation.process(modelling); - } else if (modelling.getDescription().isLogTransformation()) { - if (modelling.getDescription().getSeries().getValues().anyMatch(x -> x <= 0)) { - modelling.getLog().warning("logs changed to levels"); - modelling.getDescription().setLogTransformation(false); - modelling.clearEstimation(); - } - } - - regAIC(modelling); - checkMu(modelling, options.cval); - if (outliers != null && ProcessingResult.Changed == outliers.process(modelling, curva)) { - if (modelling.needEstimation()) { - modelling.estimate(options.precision); - } - regressionTest0.process(modelling); - } - - finalEstimator.estimate(modelling); - - return modelling.build(); - } - - private ProcessingResult regAIC(RegSarimaModelling modelling) { - ProcessingResult rslt = ProcessingResult.Unchanged; - if (calendarTest != null && calendarTest.test(modelling) == ProcessingResult.Changed) { - rslt = ProcessingResult.Changed; - } - if (easterTest != null && easterTest.test(modelling) == ProcessingResult.Changed) { - rslt = ProcessingResult.Changed; - } -// if (userTest != null && userTest.process(context) == ProcessingResult.Changed) { -// rslt = ProcessingResult.Changed; -// } - return rslt; - } - - - private ProcessingResult checkMu(RegSarimaModelling modelling, double cv) { - if (!options.checkMu) { - return ProcessingResult.Unchanged; - } - ModelDescription desc = modelling.getDescription(); - RegArimaEstimation est = modelling.getEstimation(); - boolean mean = desc.isMean(); - if (!mean) { - desc = ModelDescription.copyOf(desc); - desc.setMean(true); - est = null; - } - if (est == null) { - est = desc.estimate(RegArimaUtility.processor(true, options.getIntermediatePrecision())); - } - double t = est.getConcentratedLikelihood().tstat(0, 0, false); - boolean nmean = Math.abs(t) > cv; - if (nmean == mean) { - return ProcessingResult.Unchanged; - } else { - modelling.getDescription().setMean(nmean); - modelling.clearEstimation(); - return ProcessingResult.Changed; - } - } - -} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/FastRegArimaFactory.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/FastRegArimaFactory.java deleted file mode 100644 index 27874021..00000000 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/FastRegArimaFactory.java +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright 2023 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved - * by the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package jdplus.sa.base.core.regarima; - -import jdplus.toolkit.base.api.arima.SarimaSpec; -import jdplus.toolkit.base.api.data.Parameter; -import jdplus.toolkit.base.api.data.Range; -import jdplus.toolkit.base.api.modelling.TransformationType; -import jdplus.toolkit.base.api.modelling.regular.CalendarSpec; -import jdplus.toolkit.base.api.modelling.regular.EasterSpec; -import jdplus.toolkit.base.api.modelling.regular.ModellingSpec; -import jdplus.toolkit.base.api.modelling.regular.OutlierSpec; -import jdplus.toolkit.base.api.modelling.regular.RegressionSpec; -import jdplus.toolkit.base.api.modelling.regular.TradingDaysSpec; -import jdplus.toolkit.base.api.modelling.regular.TransformSpec; -import jdplus.sa.base.api.ComponentType; -import jdplus.sa.base.api.EstimationPolicyType; -import jdplus.sa.base.api.SaVariable; -import jdplus.toolkit.base.api.timeseries.TimeSelector; -import jdplus.toolkit.base.api.timeseries.TsDomain; -import jdplus.toolkit.base.api.timeseries.TsPeriod; -import jdplus.toolkit.base.api.timeseries.calendars.LengthOfPeriodType; -import jdplus.toolkit.base.api.timeseries.calendars.TradingDaysType; -import jdplus.toolkit.base.api.timeseries.regression.EasterVariable; -import jdplus.toolkit.base.api.timeseries.regression.IOutlier; -import jdplus.toolkit.base.api.timeseries.regression.ITradingDaysVariable; -import jdplus.toolkit.base.api.timeseries.regression.ITsVariable; -import jdplus.toolkit.base.api.timeseries.regression.InterventionVariable; -import jdplus.toolkit.base.api.timeseries.regression.Ramp; -import jdplus.toolkit.base.api.timeseries.regression.TrendConstant; -import jdplus.toolkit.base.api.timeseries.regression.TsContextVariable; -import jdplus.toolkit.base.api.timeseries.regression.Variable; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import jdplus.toolkit.base.core.modelling.GeneralLinearModel; -import jdplus.toolkit.base.core.regarima.ami.ModellingUtility; - -/** - * - * @author palatej - */ -public class FastRegArimaFactory { - - private static final FastRegArimaFactory INSTANCE = new FastRegArimaFactory(); - - public static FastRegArimaFactory getInstance() { - return INSTANCE; - } - - public ModellingSpec generateSpec(ModellingSpec spec, GeneralLinearModel.Description desc) { - if (desc == null) { - return spec; - } - ModellingSpec.Builder builder = spec.toBuilder(); - update(spec.getTransform(), desc, builder); - update(desc, builder); - update(spec.getOutliers(), builder); - update(spec.getRegression(), desc, builder); - - return builder.build(); - } - - public ModellingSpec refreshSpec(ModellingSpec currentSpec, ModellingSpec domainSpec, EstimationPolicyType policy, TsDomain frozenDomain) { - ModellingSpec.Builder builder = currentSpec.toBuilder(); - switch (policy) { - case Complete -> { - return domainSpec; - } - case Outliers_StochasticComponent -> { - resetArima(domainSpec, builder); - RegressionSpec rspec = removeOutliers(currentSpec, domainSpec, builder, frozenDomain); - freeVariables(rspec, domainSpec, builder); - } - case Outliers -> { - clearArima(currentSpec, domainSpec, builder); - RegressionSpec rspec = removeOutliers(currentSpec, domainSpec, builder, frozenDomain); - freeVariables(rspec, domainSpec, builder); - } - case LastOutliers -> { - clearArima(currentSpec, domainSpec, builder); - RegressionSpec rspec = removeOutliers(currentSpec, domainSpec, builder, frozenDomain); - freeVariables(rspec, domainSpec, builder); - } - case FreeParameters -> { - freeArima(currentSpec, domainSpec, builder); - freeVariables(currentSpec.getRegression(), domainSpec, builder); - } - case FixedAutoRegressiveParameters -> { - fixAR(currentSpec, domainSpec, builder); - freeVariables(currentSpec.getRegression(), domainSpec, builder); - } - case FixedParameters -> { - fixArima(currentSpec, builder); - freeVariables(currentSpec.getRegression(), domainSpec, builder); - } - case Fixed, Current -> { - fixArima(currentSpec, builder); - fixVariables(currentSpec.getRegression(), builder, frozenDomain); - } - default -> { - return currentSpec; - } - } - return builder.build(); - } - - private void update(TransformSpec transform, GeneralLinearModel.Description rslts, ModellingSpec.Builder builder) { - if (transform.getFunction() == TransformationType.Auto) { - TransformSpec ntransform = transform.toBuilder() - .function(rslts.isLogTransformation() ? TransformationType.Log : TransformationType.None) - .adjust(rslts.getLengthOfPeriodTransformation()) - .build(); - builder.transform(ntransform); - } - } - - private void update(GeneralLinearModel.Description rslts, ModellingSpec.Builder builder) { - SarimaSpec nspec = rslts.getStochasticComponent(); - builder.arima(nspec); - } - - private void update(OutlierSpec outliers, ModellingSpec.Builder builder) { - if (outliers.isUsed()) { // Disable outliers - builder.outliers( - outliers.toBuilder() - .ao(false) - .ls(false) - .tc(false) - .so(false) - .build()); - } - } - - private void update(RegressionSpec regression, GeneralLinearModel.Description rslts, ModellingSpec.Builder builder) { - // The huge part. - RegressionSpec.Builder rbuilder = regression.toBuilder(); - // all the coefficients (fixed or free) of the variables have already been filled - Variable[] variables = rslts.getVariables(); - updateMean(variables, rbuilder); - update(regression.getCalendar(), variables, rbuilder); - updateOutliers(variables, rbuilder); - updateUserVariables(variables, rbuilder); - builder.regression(rbuilder.build()); - } - - private void updateMean(Variable[] vars, RegressionSpec.Builder builder) { - Optional fc = Arrays.stream(vars) - .filter(v -> v.getName().equals(TrendConstant.NAME)).findFirst(); - builder.checkMu(false); - if (fc.isPresent()) { - builder.mean(fc.orElseThrow().getCoefficient(0)); - } else { - builder.mean(null); - } - } - - private void updateOutliers(Variable[] vars, RegressionSpec.Builder builder) { - builder.clearOutliers(); - Arrays.stream(vars) - .filter(v -> ModellingUtility.isOutlier(v)) - .forEach(v -> builder.outlier(v.removeAttribute(ModellingUtility.AMI))); - } - - private void updateUserVariables(Variable[] vars, RegressionSpec.Builder builder) { - - builder.clearInterventionVariables(); - Arrays.stream(vars) - .filter(v -> v.getCore() instanceof InterventionVariable) - .forEach(v -> builder.interventionVariable(v)); - builder.clearRamps(); - Arrays.stream(vars) - .filter(v -> v.getCore() instanceof Ramp) - .forEach(v -> builder.ramp(v)); - builder.clearUserDefinedVariables(); - Arrays.stream(vars) - .filter(v -> ModellingUtility.isUser(v)) - .filter(v -> !(v.getCore() instanceof InterventionVariable)) - .filter(v -> !(v.getCore() instanceof Ramp)) - .map(v -> v.withCore(TsContextVariable.of(v.getCore()))) - .forEach(v -> builder.userDefinedVariable(v)); - } - - private void update(CalendarSpec cspec, Variable[] variables, RegressionSpec.Builder builder) { - CalendarSpec.Builder cbuilder = CalendarSpec.builder(); - update(cspec.getTradingDays(), variables, cbuilder); - update(cspec.getEaster(), variables, cbuilder); - builder.calendar(cbuilder.build()); - } - - private void update(TradingDaysSpec tdspec, Variable[] vars, CalendarSpec.Builder builder) { - // leap year - Optional flp = Arrays.stream(vars) - .filter(v -> ModellingUtility.isLengthOfPeriod(v)).findFirst(); - Optional ftd = Arrays.stream(vars) - .filter(v -> ModellingUtility.isTradingDays(v)).findFirst(); - - TradingDaysSpec ntdspec = TradingDaysSpec.none(); - - LengthOfPeriodType lp = LengthOfPeriodType.None; - Parameter clp = null; - if (flp.isPresent()) { - Variable v = flp.orElseThrow(); - lp = tdspec.getLengthOfPeriodType(); - clp = v.getCoefficient(0); - } - TradingDaysType td = TradingDaysType.NONE; - Parameter[] ctd = null; - if (ftd.isPresent()) { - Variable v = ftd.orElseThrow(); - if (tdspec.isAutomatic()) { - ITradingDaysVariable tdv = (ITradingDaysVariable) v.getCore(); - td = tdv.getTradingDaysType(); - } else { - td = tdspec.getTradingDaysType(); - } - ctd = v.getCoefficients(); - } - - if (ftd.isPresent() || flp.isPresent()) { - if (tdspec.isStockTradingDays()) { - int ntd = tdspec.getStockTradingDays(); - ntdspec = TradingDaysSpec.stockTradingDays(ntd, ctd); - } else if (tdspec.isHolidays()) { - ntdspec = TradingDaysSpec.holidays(tdspec.getHolidays(), - td, lp, ctd, clp); - } else if (tdspec.isUserDefined()) { - ntdspec = TradingDaysSpec.userDefined(tdspec.getUserVariables(), ctd); - } else { //normal case - ntdspec = TradingDaysSpec.td(td, lp, ctd, clp); - } - } - builder.tradingDays(ntdspec); - } - - private void update(EasterSpec espec, Variable[] vars, CalendarSpec.Builder builder) { - // Search for an optional easter variable - Optional fe = Arrays.stream(vars) - .filter(v -> ModellingUtility.isEaster(v)).findFirst(); - if (fe.isPresent()) { - Variable ev = fe.orElseThrow(); - EasterVariable evar = (EasterVariable) ev.getCore(); - espec = espec.toBuilder() - .test(false) - .duration(evar.getDuration()) - .coefficient(ev.getCoefficient(0)) - .build(); - } else { - espec = EasterSpec.none(); - } - builder.easter(espec); - } - - private void resetArima(ModellingSpec domainSpec, ModellingSpec.Builder builder) { - builder.arima(domainSpec.getArima()); - } - - private RegressionSpec removeOutliers(ModellingSpec currentSpec, ModellingSpec domainSpec, ModellingSpec.Builder builder, TsDomain frozen) { - OutlierSpec ospec = domainSpec.getOutliers(); - if (frozen != null) { - ospec = ospec.toBuilder().span(TimeSelector.from(frozen.getEndPeriod().start())).build(); - } - builder.outliers(ospec); - - // remove existing automatic outliers... - List> outliers = currentSpec.getRegression().getOutliers(); - List> defoutliers = domainSpec.getRegression().getOutliers(); - - RegressionSpec.Builder rbuilder = currentSpec.getRegression().toBuilder() - .clearOutliers(); - // use frozen outliers and outliers specified in the domain spec (avoid doubles) - defoutliers.forEach(outlier -> { - rbuilder.outlier(outlier); - }); - - outliers.stream() - .filter(outlier -> !belongsTo(outlier, defoutliers)) - .filter(outlier -> (frozen != null && frozen.contains(outlier.getCore().getPosition()))) - .forEachOrdered(outlier -> { - rbuilder.outlier(outlier); - }); - return rbuilder.build(); - } - - private static boolean belongsTo(Variable outlier, List> defoutliers) { - return defoutliers.stream() - .filter(o -> o.getCore().getCode().equals(outlier.getCore().getCode())) - .anyMatch(o -> o.getCore().getPosition().equals(outlier.getCore().getPosition())); - } - - private void freeArima(ModellingSpec currentSpec, ModellingSpec domainSpec, ModellingSpec.Builder builder) { - builder.arima(currentSpec.getArima().freeParameters(domainSpec.getArima())); - } - - private void clearArima(ModellingSpec currentSpec, ModellingSpec domainSpec, ModellingSpec.Builder builder) { - builder.arima(currentSpec.getArima().resetParameters(domainSpec.getArima())); - } - - private void fixAR(ModellingSpec currentSpec, ModellingSpec domainSpec, ModellingSpec.Builder builder) { - SarimaSpec arima = currentSpec.getArima(); - Parameter[] phi = Parameter.fixParameters(arima.getPhi()); - Parameter[] bphi = Parameter.fixParameters(arima.getBphi()); - SarimaSpec.Builder abuilder = arima.toBuilder() - .phi(phi) - .bphi(bphi); - - SarimaSpec refarima = domainSpec.getArima(); - abuilder.theta(Parameter.freeParameters(arima.getTheta(), refarima.getTheta())) - .btheta(Parameter.freeParameters(arima.getTheta(), refarima.getBtheta())); - builder.arima(abuilder.build()); - } - - private void fixArima(ModellingSpec currentSpec, ModellingSpec.Builder builder) { - builder.arima(currentSpec.getArima().fixParameters()); - } - - private void freeVariables(RegressionSpec reg, ModellingSpec domainSpec, ModellingSpec.Builder builder) { - RegressionSpec dreg = domainSpec.getRegression(); - RegressionSpec.Builder rbuilder = reg.toBuilder(); - Parameter mean = reg.getMean(); - if (mean != null && mean.isFixed()) { - Parameter dc = dreg.getMean(); - if (dc == null || !dc.isFixed()) { - mean = Parameter.initial(mean.getValue()); - } - } - - List> iv = reg.getInterventionVariables(); - List> niv = new ArrayList<>(); - iv.forEach(v -> { - niv.add(v.withCoefficients(freeCoefficients(v, dreg.getInterventionVariables()))); - }); - - List> o = reg.getOutliers(); - List> no = new ArrayList<>(); - o.forEach(v -> { - no.add(v.withCoefficients(freeCoefficients(v, dreg.getOutliers()))); - }); - - List> r = reg.getRamps(); - List> nr = new ArrayList<>(); - r.forEach(v -> { - nr.add(v.withCoefficients(freeCoefficients(v, dreg.getRamps()))); - }); - - List> u = reg.getUserDefinedVariables(); - List> nu = new ArrayList<>(); - u.forEach(v -> { - nu.add(v.withCoefficients(freeCoefficients(v, dreg.getUserDefinedVariables()))); - }); - - EasterSpec easter = reg.getCalendar().getEaster(); - Parameter c = easter.getCoefficient(); - if (c != null && c.isFixed()) { - Parameter dc = dreg.getCalendar().getEaster().getCoefficient(); - if (dc == null || !dc.isFixed()) { - c = Parameter.initial(c.getValue()); - easter = easter.toBuilder() - .coefficient(c) - .build(); - } - } - TradingDaysSpec td = reg.getCalendar().getTradingDays(); - c = td.getLpCoefficient(); - Parameter[] tdc = td.getTdCoefficients(); - if (c != null || tdc != null) { - if (c != null && c.isFixed()) { - Parameter dc = dreg.getCalendar().getTradingDays().getLpCoefficient(); - if (dc == null || !dc.isFixed()) { - c = Parameter.initial(c.getValue()); - } - } - tdc = Parameter.freeParameters(tdc, dreg.getCalendar().getTradingDays().getTdCoefficients()); - td = td.withCoefficients(tdc, c); - } - - builder.regression(rbuilder - .mean(mean) - .clearInterventionVariables().interventionVariables(niv) - .clearOutliers().outliers(no) - .clearRamps().ramps(nr) - .clearUserDefinedVariables().userDefinedVariables(nu) - .calendar(CalendarSpec.builder() - .easter(easter) - .tradingDays(td) - .build()) - .build()); - } - - private static Parameter[] freeCoefficients(Variable var, List> ref) { - Parameter[] c = var.getCoefficients(); - if (c == null) { - return null; - } - Optional> rvar = ref.stream().filter(v -> v.getName().equals(var.getName())).findFirst(); - if (rvar.isPresent()) { - return Parameter.freeParameters(c, rvar.orElseThrow().getCoefficients()); - } else { - return Parameter.freeParameters(c); - } - } - - private static Map ao_attributes() { - HashMap attributes = new HashMap<>(); - attributes.put(ModellingUtility.AMI, "demetra"); - attributes.put(SaVariable.REGEFFECT, ComponentType.Irregular.name()); - return attributes; - } - - private static final Map IV_AO = ao_attributes(); - - private void fixVariables(RegressionSpec reg, ModellingSpec.Builder builder, TsDomain frozenDomain) { - RegressionSpec.Builder rbuilder = reg.toBuilder(); - Parameter mean = reg.getMean(); - if (mean != null && mean.isDefined()) { - mean = Parameter.fixed(mean.getValue()); - } - - List> iv = reg.getInterventionVariables(); - List> niv = new ArrayList<>(); - iv.forEach(v -> { - String n = v.getName(); - if (!n.startsWith(EstimationPolicyType.IV_AO)) { - niv.add(v.withCoefficients(Parameter.fixParameters(v.getCoefficients()))); - } else { - niv.add(v); - } - }); - if (frozenDomain != null) { - // Current AO: Add IV (ao for the frozen period) - for (int i = 0; i < frozenDomain.getLength(); ++i) { - TsPeriod period = frozenDomain.get(i); - LocalDateTime day = period.start(); - InterventionVariable ao = InterventionVariable.builder() - .sequence(Range.of(day, day)) - .build(); - niv.add(Variable.builder() - .name(EstimationPolicyType.IV_AO + period.display()) - .attributes(IV_AO) - .core(ao) - .build()); - } - } - - List> o = reg.getOutliers(); - List> no = new ArrayList<>(); - o.forEach(v -> { - no.add(v.withCoefficients(Parameter.fixParameters(v.getCoefficients()))); - }); - - List> r = reg.getRamps(); - List> nr = new ArrayList<>(); - r.forEach(v -> { - nr.add(v.withCoefficients(Parameter.fixParameters(v.getCoefficients()))); - }); - - List> u = reg.getUserDefinedVariables(); - List> nu = new ArrayList<>(); - u.forEach(v -> { - nu.add(v.withCoefficients(Parameter.fixParameters(v.getCoefficients()))); - }); - - EasterSpec easter = reg.getCalendar().getEaster(); - Parameter c = easter.getCoefficient(); - if (c != null) { - easter = easter.toBuilder() - .coefficient(Parameter.fixed(c.getValue())) - .build(); - } - TradingDaysSpec td = reg.getCalendar().getTradingDays(); - c = td.getLpCoefficient(); - Parameter[] tdc = td.getTdCoefficients(); - if (c != null || tdc != null) { - td = td.withCoefficients(Parameter.fixParameters(tdc), c == null ? null : Parameter.fixed(c.getValue())); - } - - builder.regression(rbuilder - .mean(mean) - .clearInterventionVariables().interventionVariables(niv) - .clearOutliers().outliers(no) - .clearRamps().ramps(nr) - .clearUserDefinedVariables().userDefinedVariables(nu) - .calendar(CalendarSpec.builder() - .easter(easter) - .tradingDays(td) - .build()) - .build()); - - } - -} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/ModelBuilder.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/ModelBuilder.java index 12d08d66..20dfac81 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/ModelBuilder.java +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/ModelBuilder.java @@ -323,7 +323,7 @@ public static ITradingDaysVariable tradingDays(ModellingSpec spec, ModellingCont } } - static ITradingDaysVariable td(ModellingSpec spec, DayClustering dc, ModellingContext context) { + public static ITradingDaysVariable td(ModellingSpec spec, DayClustering dc, ModellingContext context) { TradingDaysSpec tdspec = spec.getRegression().getCalendar().getTradingDays(); if (!tdspec.isUsed()) { return null; @@ -332,7 +332,6 @@ static ITradingDaysVariable td(ModellingSpec spec, DayClustering dc, ModellingCo return null; } else if (tdspec.getHolidays() != null) { GenericTradingDays gtd = GenericTradingDays.contrasts(dc); - HolidaysCorrectedTradingDays.HolidaysCorrector corrector = HolidaysCorrectionFactory.corrector(tdspec.getHolidays(), context.getCalendars(), DayOfWeek.SUNDAY); return HolidaysCorrectedTradingDays.builder().corrector(corrector).clustering(gtd.getClustering()).build(); } else if (tdspec.getUserVariables() != null) { @@ -387,18 +386,15 @@ public static ILengthOfPeriodVariable leapYear(TradingDaysSpec tdspec) { } public static IEasterVariable easter(EasterSpec.Type type, int w) { - switch (type) { - case JULIANEASTER: - return new JulianEasterVariable(w, true); - case EASTER: - return EasterVariable.builder() - .duration(w) - .meanCorrection(EasterVariable.Correction.Simple) - .endPosition(-1) - .build(); - default: - return null; - } + return switch (type) { + case JULIANEASTER -> new JulianEasterVariable(w, true); + case EASTER -> EasterVariable.builder() + .duration(w) + .meanCorrection(EasterVariable.Correction.Simple) + .endPosition(-1) + .build(); + default -> null; + }; } public static IEasterVariable easter(ModellingSpec spec) { EasterSpec espec = spec.getRegression().getCalendar().getEaster(); diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/ModelEstimator.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/ModelEstimator.java deleted file mode 100644 index 8e485c5f..00000000 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/ModelEstimator.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2022 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved - * by the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package jdplus.sa.base.core.regarima; - -import jdplus.toolkit.base.core.math.functions.levmar.LevenbergMarquardtMinimizer; -import jdplus.toolkit.base.core.regsarima.RegSarimaComputer; -import jdplus.toolkit.base.core.regsarima.regular.IModelEstimator; -import jdplus.toolkit.base.core.regsarima.regular.RegSarimaModelling; -import nbbrd.design.BuilderPattern; -import nbbrd.design.Development; - -/** - * - * @author palatej - */ -@Development(status = Development.Status.Preliminary) -public class ModelEstimator implements IModelEstimator { - - public static Builder builder() { - return new Builder(); - } - - @BuilderPattern(ModelEstimator.class) - public static class Builder { - - private double epsilon = .00001; - private RegSarimaComputer.StartingPoint starting = RegSarimaComputer.StartingPoint.Multiple; - private boolean exactDerivatives = true; - - public Builder precision(double precision) { - this.epsilon = precision; - return this; - } - - public Builder exactDerivatives(boolean exactDerivatives) { - this.exactDerivatives = exactDerivatives; - return this; - } - - public Builder startingPoint(RegSarimaComputer.StartingPoint starting) { - this.starting = starting; - return this; - } - - public ModelEstimator build() { - return new ModelEstimator(epsilon, starting, exactDerivatives); - } - - } - private final double eps; - private final RegSarimaComputer.StartingPoint starting; - private final boolean exactDerivatives; - - private ModelEstimator(double eps, RegSarimaComputer.StartingPoint starting, boolean exactDerivatives) { - this.eps = eps; - this.starting = starting; - this.exactDerivatives = exactDerivatives; - } - - @Override - public boolean estimate(RegSarimaModelling context) { - - try { - RegSarimaComputer processor = RegSarimaComputer.builder() - .minimizer(LevenbergMarquardtMinimizer.builder()) - .precision(eps) - .startingPoint(starting) - .computeExactFinalDerivatives(exactDerivatives) - .build(); - context.getDescription().freeArimaParameters(); - context.estimate(processor); - return true; - } catch (RuntimeException err) { - return false; - } - } -} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/SpecDecoder.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/SpecDecoder.java deleted file mode 100644 index 5e84ae4c..00000000 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/main/java/jdplus/sa/base/core/regarima/SpecDecoder.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2019 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.1 or – as soon they will be approved - * by the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * http://ec.europa.eu/idabc/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package jdplus.sa.base.core.regarima; - -import jdplus.toolkit.base.api.modelling.TransformationType; -import jdplus.toolkit.base.api.modelling.regular.EasterSpec; -import jdplus.toolkit.base.api.modelling.regular.ModellingSpec; -import jdplus.toolkit.base.api.modelling.regular.OutlierSpec; -import jdplus.toolkit.base.api.modelling.regular.TradingDaysSpec; -import jdplus.toolkit.base.api.modelling.regular.TransformSpec; -import jdplus.toolkit.base.api.timeseries.regression.ModellingContext; -import jdplus.toolkit.base.core.regarima.AICcComparator; -import jdplus.toolkit.base.core.regsarima.regular.RegressionVariablesTest; -import jdplus.toolkit.base.api.timeseries.calendars.LengthOfPeriodType; -import org.checkerframework.checker.nullness.qual.NonNull; -import jdplus.toolkit.base.api.timeseries.regression.IEasterVariable; -import jdplus.toolkit.base.api.timeseries.calendars.DayClustering; -import jdplus.toolkit.base.api.timeseries.regression.ITradingDaysVariable; - -/** - * The Tramo processing builder initializes the regarima processing, which - * contains the initial model and the possible AMI modules. It starts from a - * time series and from a Tramo specification. In a first step, we create the - * initial model. In a second step, we define the processor itself - * - * @author Jean Palate - */ -final class SpecDecoder { - - private final FastKernel.Builder builder = FastKernel.builder(); - - SpecDecoder(@NonNull ModellingSpec spec, ModellingContext context) { - if (context == null) { - context = ModellingContext.getActiveContext(); - } - - readTransformation(spec); - readOutliers(spec); - builder.modelBuilder(new ModelBuilder(spec, context)); - readRegression(spec, context); - readAmiOptions(spec); - } - - FastKernel buildProcessor() { - return builder.build(); - } - - private void readTransformation(final ModellingSpec spec) { - TransformSpec tspec = spec.getTransform(); - TradingDaysSpec tdspec = spec.getRegression().getCalendar().getTradingDays(); - if (tspec.getFunction() == TransformationType.Auto) { - builder.logLevel(LogLevelModule.builder() - .aiccLogCorrection(tspec.getAicDiff()) - .estimationPrecision(spec.getEstimate().getIntermediatePrecision()) - .preadjust(tdspec.isAutoAdjust() ? tdspec.getLengthOfPeriodType() : LengthOfPeriodType.None) - .outliersCorrection(tspec.isOutliersCorrection()) - .build()); - } - } - - private void readOutliers(final ModellingSpec spec) { - OutlierSpec outliers = spec.getOutliers(); - if (!outliers.isUsed()) { - return; - } - OutliersDetectionModule module = OutliersDetectionModule.builder() - .ao(outliers.isAo()) - .ls(outliers.isLs()) - .tc(outliers.isTc()) - .so(outliers.isSo()) - .span(outliers.getSpan()) - .tcrate(outliers.getDeltaTC()) - .precision(spec.getEstimate().getIntermediatePrecision()) - .build(); - builder.outliers(module); - } - - private ITradingDaysVariable[] nestedtd(final ModellingSpec spec, ModellingContext context) { - return new ITradingDaysVariable[]{ - ModelBuilder.td(spec, DayClustering.TD2, context), - ModelBuilder.td(spec, DayClustering.TD3, context), - ModelBuilder.td(spec, DayClustering.TD4, context), - ModelBuilder.td(spec, DayClustering.TD7, context) - }; - } - - private ITradingDaysVariable[] alltd(final ModellingSpec spec, ModellingContext context) { - return new ITradingDaysVariable[]{ - ModelBuilder.td(spec, DayClustering.TD2c, context), - ModelBuilder.td(spec, DayClustering.TD2, context), - ModelBuilder.td(spec, DayClustering.TD3, context), - ModelBuilder.td(spec, DayClustering.TD3c, context), - ModelBuilder.td(spec, DayClustering.TD4, context), - ModelBuilder.td(spec, DayClustering.TD7, context) - }; - } - - private void readRegression(final ModellingSpec spec, ModellingContext context) { - TradingDaysSpec tdspec = spec.getRegression().getCalendar().getTradingDays(); - AICcComparator comparator = new AICcComparator(spec.getRegression().getAicDiff()); - if (tdspec.isAutomatic()) { - switch (tdspec.getAutomaticMethod()) { - case AIC: - builder.calendarTest(AutomaticTradingDaysRegressionTest.builder() - .leapYear(ModelBuilder.leapYear(tdspec)) - .tradingDays(alltd(spec, context)) - .adjust(tdspec.isAutoAdjust()) - .aic() - .estimationPrecision(spec.getEstimate().getIntermediatePrecision()) - .build()); - break; - case BIC: - builder.calendarTest(AutomaticTradingDaysRegressionTest.builder() - .leapYear(ModelBuilder.leapYear(tdspec)) - .tradingDays(alltd(spec, context)) - .adjust(tdspec.isAutoAdjust()) - .estimationPrecision(spec.getEstimate().getIntermediatePrecision()) - .bic() - .build()); - break; - case WALD: - builder.calendarTest(AutomaticTradingDaysWaldTest.builder() - .leapYear(ModelBuilder.leapYear(tdspec)) - .tradingDays(nestedtd(spec, context)) - .adjust(tdspec.isAutoAdjust()) - .estimationPrecision(spec.getEstimate().getIntermediatePrecision()) - .build()); - break; - - } - } else if (tdspec.isTest()) { - CalendarEffectsDetectionModule cal = CalendarEffectsDetectionModule.builder() - .tradingDays(ModelBuilder.tradingDays(spec, context)) - .leapYear(ModelBuilder.leapYear(tdspec)) - .adjust(tdspec.isAutoAdjust() ? tdspec.getLengthOfPeriodType() : LengthOfPeriodType.None) - .modelComparator(comparator) - .build(); - builder.calendarTest(cal); - } - EasterSpec espec = spec.getRegression().getCalendar().getEaster(); - if (espec.getType() != EasterSpec.Type.UNUSED && espec.isTest()) { - int[] w = new int[]{espec.getDuration()}; - IEasterVariable[] easters = new IEasterVariable[w.length]; - for (int i = 0; i < easters.length; ++i) { - easters[i] = ModelBuilder.easter(espec.getType(), w[i]); - } - EasterDetectionModule e = EasterDetectionModule.builder() - .easters(easters) - .modelComparator(comparator) - .build(); - builder.easterTest(e); - } - - RegressionVariablesTest.Builder rbuilder = RegressionVariablesTest.builder(); - if (tdspec.isTest()) { - rbuilder.tdTest(RegressionVariablesTest.CVAL, true); - } - if (espec.getType() != EasterSpec.Type.UNUSED && espec.isTest()) { - rbuilder.movingHolidaysTest(RegressionVariablesTest.CVAL); - } - builder.initialRegressionTest(rbuilder.build()); - builder.finalRegressionTest(rbuilder.build()); - } - - private void readAmiOptions(ModellingSpec spec) { - builder.options( - FastKernel.AmiOptions.builder() - .precision(spec.getEstimate().getPrecision()) - .intermediatePrecision(spec.getEstimate().getIntermediatePrecision()) - .va(spec.getOutliers().getCriticalValue()) - .checkMu(spec.getRegression().isCheckMu()) - .build()); - - } - -} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/test/java/jdplus/sa/base/core/regarima/Converter.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/test/java/jdplus/sa/base/core/regarima/Converter.java deleted file mode 100644 index 746dc4dc..00000000 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/test/java/jdplus/sa/base/core/regarima/Converter.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package jdplus.sa.base.core.regarima; - -import jdplus.toolkit.base.api.timeseries.TsData; - -/** - * - * @author palatej - */ -class Converter { - static ec.tstoolkit.timeseries.simplets.TsData convert(TsData s) { - int period = s.getAnnualFrequency(); - int year = s.getStart().year(), pos = s.getStart().annualPosition(); - return new ec.tstoolkit.timeseries.simplets.TsData(ec.tstoolkit.timeseries.simplets.TsFrequency.valueOf(period), - year, pos, s.getValues().toArray(), false); - } - -} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/test/java/jdplus/sa/base/core/regarima/FastKernelTest.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/test/java/jdplus/sa/base/core/regarima/FastKernelTest.java deleted file mode 100644 index 6e60fa62..00000000 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/test/java/jdplus/sa/base/core/regarima/FastKernelTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2022 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved - * by the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package jdplus.sa.base.core.regarima; - -import tck.demetra.data.Data; -import jdplus.toolkit.base.api.modelling.regular.CalendarSpec; -import jdplus.toolkit.base.api.modelling.regular.EasterSpec; -import jdplus.toolkit.base.api.modelling.regular.ModellingSpec; -import jdplus.toolkit.base.api.modelling.regular.RegressionSpec; -import jdplus.toolkit.base.api.modelling.regular.TradingDaysSpec; -import jdplus.toolkit.base.api.timeseries.calendars.LengthOfPeriodType; -import jdplus.toolkit.base.api.timeseries.calendars.TradingDaysType; -import jdplus.toolkit.base.core.regsarima.regular.RegSarimaModel; -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author palatej - */ -public class FastKernelTest { - - public FastKernelTest() { - } - - @Test - public void testProd() { - ModellingSpec spec = ModellingSpec.FULL; - FastKernel kernel = FastKernel.of(spec, null); - RegSarimaModel rslt = kernel.process(Data.TS_PROD, null); - assertTrue(rslt != null); - } - - public static void main(String[] args) { - ModellingSpec spec=ModellingSpec.FULL; - TradingDaysSpec tradingDays = TradingDaysSpec - .td(TradingDaysType.TD2, LengthOfPeriodType.LeapYear, true, true); - //.automatic(LengthOfPeriodType.LeapYear, TradingDaysSpec.AutoMethod.BIC, 0.01, true); - - CalendarSpec cspec=CalendarSpec.builder() - .easter(EasterSpec.DEFAULT_USED) - .tradingDays(tradingDays) - .build(); - RegressionSpec rspec=RegressionSpec.builder() - .checkMu(true) - .calendar(cspec) - .build(); - - spec=spec.toBuilder().regression(rspec) - .build(); - - long t0 = System.currentTimeMillis(); - for (int i = 0; i < 1000; ++i) { - FastKernel kernel = FastKernel.of(spec, null); - RegSarimaModel rslt = kernel.process(Data.TS_ABS_RETAIL, null); - } - long t1 = System.currentTimeMillis(); - System.out.println(t1 - t0); - } - -} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/test/java/jdplus/sa/base/core/regarima/LogLevelModuleTest.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/test/java/jdplus/sa/base/core/regarima/LogLevelModuleTest.java deleted file mode 100644 index f28df9a9..00000000 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-core/src/test/java/jdplus/sa/base/core/regarima/LogLevelModuleTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2017 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved - * by the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package jdplus.sa.base.core.regarima; - -import tck.demetra.data.Data; -import jdplus.sa.base.api.ComponentType; -import jdplus.sa.base.api.SaVariable; -import jdplus.toolkit.base.api.timeseries.TsData; -import jdplus.toolkit.base.api.timeseries.calendars.DayClustering; -import jdplus.toolkit.base.api.timeseries.calendars.GenericTradingDays; -import jdplus.toolkit.base.api.timeseries.calendars.LengthOfPeriodType; -import jdplus.toolkit.base.api.timeseries.regression.GenericTradingDaysVariable; -import jdplus.toolkit.base.api.timeseries.regression.LengthOfPeriod; -import jdplus.toolkit.base.api.timeseries.regression.Variable; -import ec.tstoolkit.modelling.DefaultTransformationType; -import ec.tstoolkit.modelling.RegStatus; -import ec.tstoolkit.modelling.arima.PreadjustmentType; -import ec.tstoolkit.timeseries.calendars.TradingDaysType; -import jdplus.toolkit.base.core.regsarima.regular.ModelDescription; -import jdplus.toolkit.base.core.regsarima.regular.RegSarimaModelling; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * - * @author Jean Palate - */ -public class LogLevelModuleTest { - - public LogLevelModuleTest() { - } - - @Test - public void testNoAdjust() { - TsData[] insee = Data.insee(); - for (int i = 0; i < insee.length; ++i) { - LogLevelModule ll = LogLevelModule.builder() - .preadjust(LengthOfPeriodType.None) - .estimationPrecision(1e-5) - .aiccLogCorrection(-2) - .build(); - ModelDescription model = new ModelDescription(insee[i], null); - model.setAirline(true); - RegSarimaModelling m = RegSarimaModelling.of(model); - ll.process(m); - boolean log = m.getDescription().isLogTransformation(); - ec.tstoolkit.modelling.arima.x13.LogLevelTest oll = new ec.tstoolkit.modelling.arima.x13.LogLevelTest(); - ec.tstoolkit.timeseries.simplets.TsData s = Converter.convert(insee[i]); - ec.tstoolkit.modelling.arima.ModelDescription desc = new ec.tstoolkit.modelling.arima.ModelDescription(s, null); - ec.tstoolkit.modelling.arima.ModellingContext context = new ec.tstoolkit.modelling.arima.ModellingContext(); - desc.setTransformation(DefaultTransformationType.Auto); - desc.setAirline(true); - context.description = desc; - context.hasseas = true; - oll.process(context); - boolean olog = oll.isChoosingLog(); - assertEquals(ll.getAICcLevel(), oll.getLevel().getStatistics().AICC, 1e-1); - assertEquals(ll.getAICcLog(), oll.getLog().getStatistics().AICC, 1e-1); - assertTrue(log == olog); - } - } - - @Test - public void testAdjust() { - TsData[] insee = Data.insee(); - for (int i = 0; i < insee.length; ++i) { - LogLevelModule ll = LogLevelModule.builder() - .preadjust(LengthOfPeriodType.LeapYear) - .estimationPrecision(1e-5) - .aiccLogCorrection(-2) - .build(); - ModelDescription model = new ModelDescription(insee[i], null); - model.setAirline(true); - model.addVariable(Variable.builder().name("lp").core(new LengthOfPeriod(LengthOfPeriodType.LeapYear)).build()); - model.addVariable(Variable.builder().name("td").core(new GenericTradingDaysVariable(GenericTradingDays.contrasts(DayClustering.TD7))).build()); - RegSarimaModelling m = RegSarimaModelling.of(model); - ll.process(m); - boolean log = m.getDescription().isLogTransformation(); - ec.tstoolkit.modelling.arima.x13.LogLevelTest oll = new ec.tstoolkit.modelling.arima.x13.LogLevelTest(); - ec.tstoolkit.timeseries.simplets.TsData s = Converter.convert(insee[i]); - ec.tstoolkit.modelling.arima.ModelDescription desc = new ec.tstoolkit.modelling.arima.ModelDescription(s, null); - ec.tstoolkit.modelling.arima.ModellingContext context = new ec.tstoolkit.modelling.arima.ModellingContext(); - desc.setAirline(true); - desc.setTransformation(PreadjustmentType.Auto); - desc.setTransformation(DefaultTransformationType.Auto); - desc.addVariable(ec.tstoolkit.modelling.Variable.lpVariable(new ec.tstoolkit.timeseries.regression.LeapYearVariable(ec.tstoolkit.timeseries.calendars.LengthOfPeriodType.LeapYear), RegStatus.ToRemove)); - desc.addVariable(ec.tstoolkit.modelling.Variable.tdVariable(ec.tstoolkit.timeseries.regression.GregorianCalendarVariables.getDefault(TradingDaysType.TradingDays), RegStatus.ToRemove)); - context.description = desc; - context.hasseas = true; - oll.process(context); - boolean olog = oll.isChoosingLog(); - assertTrue(log == olog); - assertEquals(ll.getAICcLevel(), oll.getLevel().getStatistics().AICC, 1e-1); - assertEquals(ll.getAICcLog(), oll.getLog().getStatistics().AICC, 1e-1); - } - } - - @Test - public void testAdjustTD() { - int n = 0; - TsData[] insee = Data.insee(); - for (int i = 0; i < insee.length; ++i) { - LogLevelModule ll = LogLevelModule.builder() - .preadjust(LengthOfPeriodType.LeapYear) - .estimationPrecision(1e-5) - .aiccLogCorrection(-2) - .build(); - ModelDescription model0 = new ModelDescription(insee[i], null); - model0.setAirline(true); - RegSarimaModelling m0 = RegSarimaModelling.of(model0); - ll.process(m0); - boolean log0 = m0.getDescription().isLogTransformation(); - ModelDescription model1 = new ModelDescription(insee[i], null); - model1.setAirline(true); - model1.addVariable(Variable.builder().name("lp").core(new LengthOfPeriod(LengthOfPeriodType.LeapYear)).attribute(SaVariable.REGEFFECT, ComponentType.CalendarEffect.name()).build()); - model1.addVariable(Variable.builder().name("td").core(new GenericTradingDaysVariable(GenericTradingDays.contrasts(DayClustering.TD7))).attribute(SaVariable.REGEFFECT, ComponentType.CalendarEffect.name()).build()); - RegSarimaModelling m1 = RegSarimaModelling.of(model1); - ll.process(m1); - boolean log1 = m1.getDescription().isLogTransformation(); - if (log0 != log1) { - ++n; - } - } - } - - @Test - public void testAO() { - TsData[] insee = Data.insee(); - for (int i = 0; i < insee.length; ++i) { - LogLevelModule ll = LogLevelModule.builder() - .preadjust(LengthOfPeriodType.None) - .estimationPrecision(1e-5) - .aiccLogCorrection(2) - .build(); - ModelDescription model = new ModelDescription(insee[i], null); - model.setAirline(true); - RegSarimaModelling m = RegSarimaModelling.of(model); - ll.process(m); -// System.out.print(ll.isChoosingLog()); - System.out.print('\t'); - - double[] nvals = insee[i].getValues().toArray(); - nvals[nvals.length - 3] *= 0.25; - nvals[nvals.length - 2] *= 0.20; - TsData s = TsData.ofInternal(insee[i].getStart(), nvals); - model = new ModelDescription(s, null); - model.setAirline(true); - m = RegSarimaModelling.of(model); - ll.process(m); -// System.out.println(ll.isChoosingLog()); - } - } -} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-csv/pom.xml b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-csv/pom.xml index 972508ac..b059880d 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-csv/pom.xml +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-csv/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-sa-base-parent - 3.0.2 + 3.1.0 jdplus-sa-base-csv diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/pom.xml b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/pom.xml index 44bf9972..2530495b 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/pom.xml +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-sa-base-parent - 3.0.2 + 3.1.0 jdplus-sa-base-information diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/EasterSpecMapping.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/EasterSpecMapping.java new file mode 100644 index 00000000..e28000ac --- /dev/null +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/EasterSpecMapping.java @@ -0,0 +1,83 @@ +/* + * Copyright 2020 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.sa.base.information.highfreq; + +import jdplus.toolkit.base.api.data.Parameter; +import jdplus.toolkit.base.api.information.InformationSet; +import jdplus.toolkit.base.api.modelling.highfreq.EasterSpec; + +/** + * + * @author PALATEJ + */ +@lombok.experimental.UtilityClass +public class EasterSpecMapping { + + final String TYPE = "type", PARAM = "param", TEST = "test", COEF = "coef"; + + public InformationSet write(EasterSpec spec, boolean verbose) { + if (!verbose && spec.isDefault()) { + return null; + } + InformationSet easterInfo = new InformationSet(); + writeProperties(easterInfo, spec, verbose); + Parameter coef = spec.getCoefficient(); + if (coef != null) { + easterInfo.set(COEF, coef); + } + return easterInfo; + } + + private void writeProperties(InformationSet easterInfo, EasterSpec spec, boolean verbose) { + easterInfo.add(TYPE, spec.getType().name()); + if (verbose || spec.getDuration() != 0) { + easterInfo.add(PARAM, spec.getDuration()); + } + if (verbose || !spec.isTest()) { + easterInfo.add(TEST, spec.isTest()); + } + } + + public EasterSpec read(InformationSet easterInfo) { + if (easterInfo == null) { + return EasterSpec.DEFAULT_UNUSED; + } + EasterSpec.Builder builder = EasterSpec.builder(); + readProperties(easterInfo, builder); + Parameter c = easterInfo.get(COEF, Parameter.class); + return builder.coefficient(c) + .build(); + } + + private void readProperties(InformationSet easterInfo, EasterSpec.Builder builder) { + String type = easterInfo.get(TYPE, String.class); + EasterSpec.Type mtype = EasterSpec.Type.UNUSED; + if (type != null) { + mtype = EasterSpec.Type.valueOf(type); + } + Integer w = easterInfo.get(PARAM, Integer.class); + Boolean test = easterInfo.get(TEST, Boolean.class); + boolean rtest = false; + if (test != null) { + rtest = test; + } + + builder.duration(w == null ? EasterSpec.DEF_IDUR : w) + .type(mtype) + .test(rtest); + } +} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/EstimateSpecMapping.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/EstimateSpecMapping.java new file mode 100644 index 00000000..06086d8d --- /dev/null +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/EstimateSpecMapping.java @@ -0,0 +1,72 @@ +/* + * Copyright 2020 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.sa.base.information.highfreq; + +import jdplus.toolkit.base.api.information.InformationSet; +import jdplus.toolkit.base.api.modelling.highfreq.EstimateSpec; +import jdplus.toolkit.base.api.timeseries.TimeSelector; + +/** + * + * @author PALATEJ + */ +@lombok.experimental.UtilityClass +public class EstimateSpecMapping { + + final String SPAN = "span", + TOL = "tol", HESSIAN ="hessian"; + + public InformationSet write(EstimateSpec spec, boolean verbose) { + if (!verbose && spec.isDefault()) { + return null; + } + InformationSet info = new InformationSet(); + if (verbose || spec.getSpan().getType() != TimeSelector.SelectionType.All) { + info.set(SPAN, spec.getSpan()); + } + if (verbose || spec.getPrecision() != EstimateSpec.EPS) { + info.set(TOL, spec.getPrecision()); + } + if (verbose || !spec.isApproximateHessian()){ + info.set(HESSIAN, spec.isApproximateHessian()); + } + return info; + } + + public EstimateSpec read(InformationSet info) { + if (info == null) { + return EstimateSpec.DEFAULT; + } + + EstimateSpec.Builder builder = EstimateSpec.builder(); + + TimeSelector span = info.get(SPAN, TimeSelector.class); + if (span != null) { + builder.span(span); + } + Double tol = info.get(TOL, Double.class); + if (tol != null) { + builder.precision(tol); + } + Boolean hessian = info.get(HESSIAN, Boolean.class); + if (hessian != null) { + builder.approximateHessian(hessian); + } + + return builder.build(); + } +} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/HolidaysSpecMapping.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/HolidaysSpecMapping.java new file mode 100644 index 00000000..a28f744c --- /dev/null +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/HolidaysSpecMapping.java @@ -0,0 +1,106 @@ +/* + * Copyright 2020 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.sa.base.information.highfreq; + +import java.util.Arrays; +import jdplus.toolkit.base.api.data.Parameter; +import jdplus.toolkit.base.api.information.InformationSet; +import jdplus.toolkit.base.api.modelling.highfreq.HolidaysSpec; +import jdplus.toolkit.base.api.timeseries.calendars.HolidaysOption; +import jdplus.toolkit.base.api.timeseries.regression.HolidaysVariable; + +/** + * + * @author PALATEJ + */ +@lombok.experimental.UtilityClass +public class HolidaysSpecMapping { + + final String HOLIDAYS = "holidays", OPTION = "option", + SINGLE = "single", NONWORKING = "nonworking", TEST = "test", + COEF = "coef"; + + public InformationSet write(HolidaysSpec spec, boolean verbose) { + if (!verbose && !spec.isUsed()) { + return null; + } + InformationSet hinfo = new InformationSet(); + + writeProperties(hinfo, spec, verbose, true); + + Parameter[] coef = spec.getCoefficients(); + if (coef != null) { + hinfo.set(COEF, coef); + } + return hinfo; + } + + public void writeProperties(InformationSet hinfo, HolidaysSpec spec, boolean verbose, boolean v3) { + if (spec.getHolidays() != null) { + hinfo.add(HOLIDAYS, spec.getHolidays()); + } + if (verbose || spec.getHolidaysOption() != HolidaysSpec.DEF_OPTION) { + hinfo.add(OPTION, spec.getHolidaysOption().name()); + } + if (verbose || spec.isSingle()) { + hinfo.add(SINGLE, spec.isSingle()); + } + if (verbose || !Arrays.equals(spec.getNonWorkingDays(), HolidaysVariable.NONWORKING_WE)) { + hinfo.add(NONWORKING, spec.getNonWorkingDays()); + } + if (verbose || spec.isTest()) { + hinfo.add(TEST, spec.isTest()); + } + } + + public HolidaysSpec read(InformationSet hinfo) { + if (hinfo == null) { + return HolidaysSpec.DEFAULT_UNUSED; + } + String holidays = hinfo.get(HOLIDAYS, String.class); + if (holidays == null) { + return HolidaysSpec.DEFAULT_UNUSED; + } + HolidaysSpec.Builder builder = HolidaysSpec.builder() + .holidays(holidays); + String option = hinfo.get(OPTION, String.class); + if (option != null){ + HolidaysOption o= HolidaysOption.valueOf(option); + builder.holidaysOption(o); + } + Boolean single = hinfo.get(SINGLE, Boolean.class); + if (single != null){ + builder.single(single); + } + int[] nwd=hinfo.get(NONWORKING, int[].class); + if (nwd != null){ + builder.nonWorkingDays(nwd); + } + Boolean test = hinfo.get(TEST, Boolean.class); + if (test != null && test) { + builder.test(true); + } else { + Parameter[] coef = hinfo.get(COEF, Parameter[].class); + if (coef != null) { + builder.coefficients(coef); + } + } + + return builder.build(); + } + +} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/OutlierSpecMapping.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/OutlierSpecMapping.java new file mode 100644 index 00000000..5a635dde --- /dev/null +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/OutlierSpecMapping.java @@ -0,0 +1,89 @@ +/* + * Copyright 2020 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.sa.base.information.highfreq; + +import jdplus.toolkit.base.api.information.InformationSet; +import jdplus.toolkit.base.api.modelling.highfreq.OutlierSpec; +import jdplus.toolkit.base.api.timeseries.TimeSelector; + +/** + * + * @author PALATEJ + */ +@lombok.experimental.UtilityClass +public class OutlierSpecMapping { + + final String SPAN = "span", + AO = "ao", LS = "ls", WO = "wo", + VA = "va"; + + public InformationSet write(OutlierSpec spec, boolean verbose) { + if (!verbose && spec.isDefault()) { + return null; + } + InformationSet info = new InformationSet(); + TimeSelector span = spec.getSpan(); + if (verbose || span.getType() != TimeSelector.SelectionType.All) { + info.add(SPAN, span); + } + if (spec.isAo() || verbose) { + info.add(AO, spec.isAo()); + } + if (spec.isLs() || verbose) { + info.add(LS, spec.isLs()); + } + if (spec.isWo() || verbose) { + info.add(WO, spec.isWo()); + } + double cv = spec.getCriticalValue(); + if (verbose || cv != 0) { + info.add(VA, cv); + } + return info; + } + + public OutlierSpec read(InformationSet info) { + if (info == null) { + return OutlierSpec.DEFAULT_DISABLED; + } + + OutlierSpec.Builder builder = OutlierSpec.builder(); + + TimeSelector span = info.get(SPAN, TimeSelector.class); + if (span != null) { + builder = builder.span(span); + } + Boolean ao = info.get(AO, Boolean.class); + if (ao != null) { + builder.ao(ao); + } + Boolean ls = info.get(LS, Boolean.class); + if (ls != null) { + builder.ls(ls); + } + Boolean wo = info.get(WO, Boolean.class); + if (wo != null) { + builder.wo(wo); + } + Double cv = info.get(VA, Double.class); + if (cv != null) { + builder = builder.criticalValue(cv); + } + return builder.build(); + } + +} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/RegressionSpecMapping.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/RegressionSpecMapping.java new file mode 100644 index 00000000..d4963159 --- /dev/null +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/RegressionSpecMapping.java @@ -0,0 +1,123 @@ +/* + * Copyright 2020 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.sa.base.information.highfreq; + +import jdplus.toolkit.base.api.information.Information; +import jdplus.toolkit.base.api.information.InformationSet; +import jdplus.toolkit.base.information.VariableMapping; +import jdplus.toolkit.base.api.modelling.highfreq.RegressionSpec; +import jdplus.toolkit.base.api.timeseries.TsDomain; +import jdplus.toolkit.base.api.timeseries.regression.IOutlier; +import jdplus.toolkit.base.api.timeseries.regression.InterventionVariable; +import jdplus.toolkit.base.api.timeseries.regression.TsContextVariable; +import jdplus.toolkit.base.api.timeseries.regression.Variable; +import java.util.List; +import jdplus.toolkit.base.api.modelling.highfreq.EasterSpec; +import jdplus.toolkit.base.api.modelling.highfreq.HolidaysSpec; + +/** + * + * @author PALATEJ + */ +@lombok.experimental.UtilityClass +public class RegressionSpecMapping { + + final String CAL = "calendar", EASTER = "easter", + OUTLIER = "outlier", OUTLIERS = "outlier*", + USER = "user", USERS = "user*", + INTERVENTION = "intervention", INTERVENTIONS = "intervention*"; + + public RegressionSpec read(InformationSet info) { + if (info == null) { + return RegressionSpec.DEFAULT; + } + RegressionSpec.Builder builder = RegressionSpec.builder(); + + HolidaysSpec hol = HolidaysSpecMapping.read(info.getSubSet(CAL)); + if (hol != null) { + builder.holidays(hol); + } + EasterSpec e=EasterSpecMapping.read(info.getSubSet(EASTER)); + if (e != null){ + builder.easter(e); + } + List> sel = info.select(OUTLIERS, InformationSet.class); + if (!sel.isEmpty()) { + for (Information sub : sel) { + Variable v = VariableMapping.readO(sub.getValue()); + builder.outlier(v); + } + } + sel = info.select(INTERVENTIONS, InformationSet.class); + if (!sel.isEmpty()) { + for (Information sub : sel) { + Variable v = VariableMapping.readIV(sub.getValue()); + builder.interventionVariable(v); + } + } + sel = info.select(USERS, InformationSet.class); + if (!sel.isEmpty()) { + for (Information sub : sel) { + Variable v = VariableMapping.readT(sub.getValue()); + builder.userDefinedVariable(v); + } + } + return builder.build(); + } + + public InformationSet write(RegressionSpec spec, TsDomain context, boolean verbose) { + if (!spec.isUsed()) { + return null; + } + InformationSet info = new InformationSet(); + + InformationSet hinfo = HolidaysSpecMapping.write(spec.getHolidays(), verbose); + if (hinfo != null) { + info.set(CAL, hinfo); + } + InformationSet einfo = EasterSpecMapping.write(spec.getEaster(), verbose); + if (einfo != null) { + info.set(EASTER, einfo); + } + List> voutliers = spec.getOutliers(); + if (!voutliers.isEmpty()) { + int idx = 1; + for (Variable v : voutliers) { + InformationSet w = VariableMapping.writeO(v, verbose); + info.set(OUTLIER + (idx++), w); + } + } + List> vusers = spec.getUserDefinedVariables(); + if (!vusers.isEmpty()) { + int idx = 1; + for (Variable v : vusers) { + InformationSet w = VariableMapping.writeT(v, verbose); + info.set(USER + (idx++), w); + } + } + List> viv = spec.getInterventionVariables(); + if (!viv.isEmpty()) { + int idx = 1; + for (Variable v : viv) { + InformationSet w = VariableMapping.writeIV(v, verbose); + info.set(INTERVENTION + (idx++), w); + } + } + return info; + } + +} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/SeriesSpecMapping.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/SeriesSpecMapping.java new file mode 100644 index 00000000..c6ededb0 --- /dev/null +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/SeriesSpecMapping.java @@ -0,0 +1,67 @@ +/* + * Copyright 2020 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.sa.base.information.highfreq; + +import jdplus.toolkit.base.api.information.InformationSet; +import jdplus.toolkit.base.api.modelling.highfreq.SeriesSpec; +import jdplus.toolkit.base.api.timeseries.TimeSelector; +import jdplus.toolkit.base.api.modelling.highfreq.DataCleaning; + +/** + * + * @author PALATEJ + */ +@lombok.experimental.UtilityClass +public class SeriesSpecMapping { + + final String SPAN = "span", CLEANING = "cleaning"; + + + public InformationSet write(SeriesSpec spec, boolean verbose) { + if (!verbose && spec.isDefault()) { + return null; + } + InformationSet info = new InformationSet(); + if (verbose || spec.getSpan().getType() != TimeSelector.SelectionType.All) { + info.add(SPAN, spec.getSpan()); + } + if (verbose || spec.getCleaning() != DataCleaning.NONE) { + info.add(CLEANING, spec.getCleaning().name()); + } + return info; + } + + public SeriesSpec read(InformationSet info) { + + if (info == null) { + return SeriesSpec.DEFAULT; + } + + SeriesSpec.Builder builder = SeriesSpec.builder(); + TimeSelector span = info.get(SPAN, TimeSelector.class); + if (span != null) { + builder.span(span); + } + String cleaning = info.get(CLEANING, String.class); + if (cleaning != null) { + DataCleaning dc=DataCleaning.valueOf(cleaning); + builder.cleaning(dc); + } + return builder.build(); + } + +} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/TransformSpecMapping.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/TransformSpecMapping.java new file mode 100644 index 00000000..bd9ce839 --- /dev/null +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/jdplus/sa/base/information/highfreq/TransformSpecMapping.java @@ -0,0 +1,61 @@ +/* + * Copyright 2020 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.sa.base.information.highfreq; + +import jdplus.toolkit.base.api.information.InformationSet; +import jdplus.toolkit.base.api.modelling.TransformationType; +import jdplus.toolkit.base.api.modelling.highfreq.TransformSpec; + +/** + * + * @author PALATEJ + */ +@lombok.experimental.UtilityClass +public class TransformSpecMapping { + + final String FN = "function", + AICDIFF = "aicdiff" + ; + + public InformationSet write(TransformSpec spec, boolean verbose) { + if (!verbose && spec.isDefault()) { + return null; + } + InformationSet info = new InformationSet(); + if (verbose || spec.getFunction() != TransformationType.None) { + info.add(FN, spec.getFunction().name()); + } + return info; + } + + public TransformSpec read(InformationSet info) { + if (info == null) { + return TransformSpec.DEFAULT; + } + TransformSpec.Builder builder = TransformSpec.builder(); + String fn = info.get(FN, String.class); + if (fn != null) { + builder = builder.function(TransformationType.valueOf(fn)); + } + Double aic = info.get(AICDIFF, Double.class); + if (aic != null) { + builder.aicDiff(aic); + } + return builder.build(); + } + +} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/module-info.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/module-info.java index 61655676..d697fdc3 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/module-info.java +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-information/src/main/java/module-info.java @@ -11,6 +11,7 @@ requires jdplus.toolkit.base.information; exports jdplus.sa.base.information; + exports jdplus.sa.base.information.highfreq; uses SaSpecificationMapping; } \ No newline at end of file diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-protobuf/pom.xml b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-protobuf/pom.xml index b06dac6a..5bb09539 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-protobuf/pom.xml +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-protobuf/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-sa-base-parent - 3.0.2 + 3.1.0 jdplus-sa-base-protobuf diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-r/pom.xml b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-r/pom.xml index fa73b0d0..1d5a9d4c 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-r/pom.xml +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-r/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-sa-base-parent - 3.0.2 + 3.1.0 jdplus-sa-base-r diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/pom.xml b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/pom.xml index 02667fb0..6b1e59aa 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/pom.xml +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-sa-base-parent - 3.0.2 + 3.1.0 jdplus-sa-base-workspace diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/MultiProcessing.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/MultiProcessing.java index fd131e03..0d1c4518 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/MultiProcessing.java +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/MultiProcessing.java @@ -16,6 +16,9 @@ */ package jdplus.sa.base.workspace; +import java.time.Clock; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import jdplus.sa.base.api.SaItem; import jdplus.sa.base.api.SaItems; import jdplus.sa.base.api.SaSpecification; @@ -26,6 +29,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import jdplus.sa.base.api.EstimationPolicy; +import jdplus.sa.base.api.EstimationPolicyType; +import jdplus.toolkit.base.api.timeseries.TsDomain; +import jdplus.toolkit.base.api.timeseries.TsInformationType; /** * @@ -33,7 +40,7 @@ */ @lombok.Data public class MultiProcessing { - + public static MultiProcessing of(String name, SaItems processing) { MultiProcessing p = new MultiProcessing(name); p.metaData.putAll(processing.getMeta()); @@ -44,18 +51,38 @@ public static MultiProcessing of(String name, SaItems processing) { public MultiProcessing(String name) { this.name = name; } - - public void compute(ModellingContext context) { + + private static final String TIMESTAMP="@timestamp"; + + public MultiProcessing refresh(String policy, TsDomain domain, String info){ + MultiProcessing p =new MultiProcessing(name); + for (SaItem cur : items) { + p.items.add(cur.refresh(new EstimationPolicy(EstimationPolicyType.valueOf(policy), domain), + TsInformationType.valueOf(info))); + } + p.metaData.putAll(metaData); + p.metaData.put(TIMESTAMP, LocalDateTime.now(Clock.systemDefaultZone()).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + return p; + } + + public void compute(ModellingContext context) { items.parallelStream().forEach(v -> v.compute(context, false)); } public void process(ModellingContext context) { items.parallelStream().forEach(v -> v.process(context, false)); } - - public void add(SaItem item){ + + public void add(SaItem item) { items.add(item); } + + public MultiProcessing makeCopy(){ + MultiProcessing mp=new MultiProcessing(name); + mp.metaData.putAll(metaData); + mp.items.addAll(items); // SaItem are immutable ! + return mp; + } public void add(String name, TsData s, SaSpecification spec) { Ts ts = Ts.of(name, s); @@ -71,19 +98,9 @@ public void set(int pos, SaItem newItem) { items.set(pos, newItem); } - public void setDomainSpecification(int pos, SaSpecification newspec){ - SaItem nitem=items.get(pos).withDomainSpecification(newspec); - items.set(pos, nitem); - } - - public void setSpecification(int pos, SaSpecification newspec){ - SaItem nitem=items.get(pos).withSpecification(newspec); - items.set(pos, nitem); - } - - public void setData(int pos, TsData ndata){ - SaItem item=items.get(pos); - Ts nts=Ts.of(item.getDefinition().getTs().getName(), ndata); + public void setData(int pos, TsData ndata) { + SaItem item = items.get(pos); + Ts nts = Ts.of(item.getDefinition().getTs().getName(), ndata); items.set(pos, item.withTs(nts)); } diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/Utility.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/Utility.java new file mode 100644 index 00000000..c1362da9 --- /dev/null +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/Utility.java @@ -0,0 +1,54 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.sa.base.workspace; + +import java.util.HashMap; +import jdplus.sa.base.api.SaDefinition; +import jdplus.sa.base.api.SaItem; +import jdplus.toolkit.base.api.timeseries.Ts; + +/** + * + * @author palatej + */ +@lombok.experimental.UtilityClass +public class Utility { + public SaItem withTsMetaData(SaItem item, String key, String value) { + SaDefinition definition = item.getDefinition(); + Ts cur = definition.getTs(); + HashMap map = new HashMap<>(cur.getMeta()); + map.put(key, value); + Ts ncur = cur.toBuilder().clearMeta() + .meta(map) + .build(); + SaDefinition ndef = definition.toBuilder() + .ts(ncur) + .build(); + return new SaItem(item.getName(), ndef, item.getMeta(), item.getPriority(), item.getEstimation(), item.isProcessed()); + } + + public String getSingleMetaData(SaItem item, String key) { + return item.getMeta().get(key); + } + + public String getSingleTsMetaData(SaItem item, String key) { + Ts cur = item.getDefinition().getTs(); + return cur.getMeta().get(key); + } + + +} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/Ws.java b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/Ws.java index d4845fa4..46735a21 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/Ws.java +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-workspace/src/main/java/jdplus/sa/base/workspace/Ws.java @@ -39,37 +39,41 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import jdplus.sa.base.api.EstimationPolicy; +import jdplus.sa.base.api.EstimationPolicyType; +import jdplus.toolkit.base.api.timeseries.TsDomain; +import jdplus.toolkit.base.api.timeseries.TsInformationType; /** * * @author PALATEJ */ public class Ws { - + private final String source; private ModellingContext context; private final List multiProcessing = new ArrayList<>(); - + public Ws() { this.source = null; this.context = new ModellingContext(); } - + public Ws(final String source, final ModellingContext context) { this.source = source; this.context = context; } - + public static Ws create(ModellingContext context) { return new Ws(null, context); } - + public static Ws open(String fileName) throws IOException { File file = new File(fileName); FileWorkspace fws = FileWorkspace.open(file.toPath(), DemetraVersion.JD3); ModellingContext context = WorkspaceUtility.context(fws, false); Ws ws = new Ws(fileName, context); - + List sa = WorkspaceUtility.select(fws, SaHandlers.SA_MULTI); for (WorkspaceItemDescriptor s : sa) { SaItems mp = (SaItems) fws.load(s.getKey()); @@ -77,9 +81,9 @@ public static Ws open(String fileName) throws IOException { } return ws; } - + @Deprecated - public ModellingContext context(){ + public ModellingContext context() { return context; } @@ -89,19 +93,19 @@ public boolean save(String v) { } return saveAs(source, v, false); } - + public boolean saveAs(String sfile, String v, boolean failIfExists) { DemetraVersion version = DemetraVersion.JD3; if (v != null && v.equalsIgnoreCase("jd2")) { version = DemetraVersion.JD2; } File file = new File(sfile); - + boolean exist = file.exists(); if (exist && failIfExists) { return false; } - try ( FileWorkspace storage = FileWorkspace.create(file.toPath(), version)) { + try (FileWorkspace storage = FileWorkspace.create(file.toPath(), version)) { storage.setName(Paths.changeExtension(file.getName(), null)); storeCalendar(storage, context.getCalendars()); // store variables @@ -122,7 +126,7 @@ public boolean saveAs(String sfile, String v, boolean failIfExists) { new WorkspaceItemDescriptor.Attributes(mp.getName(), false, null)); // build the multiProcessing Map meta = new HashMap<>(mp.getMetaData()); - meta.put("@timestamp", LocalDateTime.now(Clock.systemDefaultZone()).format(DateTimeFormatter.ISO_DATE)); + meta.put("@timestamp", LocalDateTime.now(Clock.systemDefaultZone()).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); meta.putAll(mp.getMetaData()); SaItems items = SaItems.builder() .meta(meta) @@ -131,13 +135,13 @@ public boolean saveAs(String sfile, String v, boolean failIfExists) { .build(); storage.store(cur, items); } - + } catch (IOException | InvalidPathException ex) { return false; } return true; } - + // public static Path getRootFolder(Path indexFile) throws IOException { // Path parent = indexFile.toAbsolutePath().getParent(); // if (parent == null) { @@ -150,62 +154,80 @@ public boolean saveAs(String sfile, String v, boolean failIfExists) { = new WorkspaceItemDescriptor( new WorkspaceItemDescriptor.Key(WorkspaceFamily.UTIL_CAL, "Calendars"), new WorkspaceItemDescriptor.Attributes("Calendars", false, null)); - + private static void storeCalendar(FileWorkspace storage, CalendarManager value) throws IOException { storage.store(CAL_ID, value); } - + public MultiProcessing getMultiProcessing(int idx) { return multiProcessing.get(idx); } - + public int getMultiProcessingCount() { return multiProcessing.size(); } - + public MultiProcessing newMultiProcessing(String name) { MultiProcessing n = new MultiProcessing(name); multiProcessing.add(n); return n; } - + public ModellingContext getContext() { return (this.context); } - + public void setContext(ModellingContext context) { - this.context=context; + this.context = context; } - - public void addVariable(String family, String name, TsData data){ + + public void addVariable(String family, String name, TsData data) { TsDataSuppliers tsfamily = context.getTsVariables(family); - if (tsfamily == null){ - tsfamily=new TsDataSuppliers(); + if (tsfamily == null) { + tsfamily = new TsDataSuppliers(); context.getTsVariableManagers().set(name, tsfamily); } tsfamily.set(name, new StaticTsDataSupplier(data)); } - - public void addCalendar(String name, CalendarDefinition calendar){ + + public void addCalendar(String name, CalendarDefinition calendar) { context.getCalendars().set(name, calendar); } public void computeAll() { multiProcessing.stream().forEach(p -> p.compute(context)); } - + public void compute(String name) { multiProcessing.stream().filter(p -> p.getName().equals(name)).forEach(q -> q.compute(context)); } - + public void processAll() { multiProcessing.stream().forEach(p -> p.process(context)); } - + public void process(String name) { multiProcessing.stream().filter(p -> p.getName().equals(name)).forEach(q -> q.process(context)); } + public void add(MultiProcessing sap) { + multiProcessing.add(sap); + } + + public void refreshAll(String policy, TsDomain domain, String info) { + multiProcessing.replaceAll(sap -> sap.refresh(policy, domain, info)); + } + + public Ws makeCopy(){ + Ws copy=new Ws(); + copy.context=context; // ? perhaps should it be changed + copy.multiProcessing + .addAll(multiProcessing.stream() + .map(p->p.makeCopy()) + .toList()); + return copy; + } + // public boolean save(String fileName) { // File file = new File(fileName); // try { diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-xml/pom.xml b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-xml/pom.xml index 261ee46b..d71b0215 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-xml/pom.xml +++ b/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-xml/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-sa-base-parent - 3.0.2 + 3.1.0 jdplus-sa-base-xml diff --git a/jdplus-main-base/jdplus-sa-base-parent/pom.xml b/jdplus-main-base/jdplus-sa-base-parent/pom.xml index b59cb5d4..17f804de 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/pom.xml +++ b/jdplus-main-base/jdplus-sa-base-parent/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-main-base - 3.0.2 + 3.1.0 jdplus-sa-base-parent diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/pom.xml b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/pom.xml index fbb6993a..0d81385b 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/pom.xml +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-spreadsheet-base-parent - 3.0.2 + 3.1.0 jdplus-spreadsheet-base-api @@ -23,6 +23,11 @@ jdplus-toolkit-base-tsp ${project.version} + + eu.europa.ec.joinup.sat + jdplus-sa-base-core + ${project.version} + com.github.nbbrd.spreadsheet4j spreadsheet-api diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/CachedSpreadSheetConnection.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/CachedSpreadSheetConnection.java index 4a2d7ddd..fedc5340 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/CachedSpreadSheetConnection.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/CachedSpreadSheetConnection.java @@ -17,19 +17,16 @@ package internal.spreadsheet.base.api; import jdplus.toolkit.base.api.timeseries.TsCollection; -import jdplus.toolkit.base.tsp.util.IOCache; -import jdplus.toolkit.base.tsp.util.IOCacheFactory; +import jdplus.toolkit.base.tsp.util.ShortLivedCache; +import jdplus.toolkit.base.tsp.util.ShortLivedCaching; import lombok.AccessLevel; -import nbbrd.io.Resource; -import nbbrd.io.function.IOSupplier; +import nbbrd.design.StaticFactoryMethod; import org.checkerframework.checker.nullness.qual.NonNull; import java.io.File; import java.io.IOException; import java.util.List; -import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; /** * @author Philippe Charles @@ -37,7 +34,8 @@ @lombok.AllArgsConstructor(access = AccessLevel.PACKAGE) public final class CachedSpreadSheetConnection implements SpreadSheetConnection { - public static @NonNull SpreadSheetConnection of(@NonNull SpreadSheetConnection delegate, @NonNull File target, @NonNull IOCacheFactory cacheFactory) { + @StaticFactoryMethod + public static @NonNull CachedSpreadSheetConnection of(@NonNull SpreadSheetConnection delegate, @NonNull File target, @NonNull ShortLivedCaching cacheFactory) { return new CachedSpreadSheetConnection(delegate, cacheFactory.ofFile(target)); } @@ -45,50 +43,65 @@ public final class CachedSpreadSheetConnection implements SpreadSheetConnection private final SpreadSheetConnection delegate; @lombok.NonNull - private final IOCache cache; + private final ShortLivedCache> cache; @Override - public Optional getSheetByName(String name) throws IOException { - Objects.requireNonNull(name); - - List all = peek("getSheets"); + public @lombok.NonNull Optional getSheetByName(@lombok.NonNull String name) throws IOException { + List all = peekAll(); if (all != null) { - return all.stream().filter(o -> o.getName().equals(name)).findFirst(); + return all.stream() + .filter(collection -> collection.getName().equals(name)) + .findFirst(); } - return load("getSheetByName/" + name, () -> delegate.getSheetByName(name)); + String key = "getSheetByName/" + name; + List cachedValue = cache.get(key); + if (cachedValue == null) { + Optional result = delegate.getSheetByName(name); + cache.put(key, result.stream().toList()); + return result; + } else { + return cachedValue.stream().findFirst(); + } } @Override - public List getSheetNames() throws IOException { - List all = peek("getSheets"); + public @lombok.NonNull List getSheetNames() throws IOException { + List all = peekAll(); if (all != null) { - return all.stream().map(TsCollection::getName).collect(Collectors.toList()); + return all.stream() + .map(TsCollection::getName) + .toList(); } - return load("getSheetNames", delegate::getSheetNames); + String key = "getSheetNames"; + List cachedValue = cache.get(key); + if (cachedValue == null) { + List result = delegate.getSheetNames(); + cache.put(key, result.stream().map(TsCollection::ofName).toList()); + return result; + } else { + return cachedValue.stream().map(TsCollection::getName).toList(); + } } @Override - public List getSheets() throws IOException { - return load("getSheets", delegate::getSheets); + public @lombok.NonNull List getSheets() throws IOException { + String key = "getSheets"; + List cachedValue = cache.get(key); + if (cachedValue == null) { + cachedValue = delegate.getSheets(); + cache.put(key, cachedValue); + } + return cachedValue; } @Override public void close() throws IOException { - Resource.closeBoth(cache, delegate); + delegate.close(); } - private T peek(String key) { - return (T) cache.get(key); - } - - private T load(String key, IOSupplier loader) throws IOException { - T result = peek(key); - if (result == null) { - result = loader.getWithIO(); - cache.put(key, result); - } - return result; + private List peekAll() { + return cache.get("getSheets"); } } diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadSheetDataDisplayName.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadSheetDataDisplayName.java index c61a24fc..6fcf5c9b 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadSheetDataDisplayName.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadSheetDataDisplayName.java @@ -24,6 +24,7 @@ import jdplus.toolkit.base.tsp.HasDataDisplayName; import jdplus.toolkit.base.tsp.util.DataSourcePreconditions; import jdplus.toolkit.base.api.util.MultiLineNameUtil; +import org.checkerframework.checker.nullness.qual.NonNull; import java.util.Locale; @@ -37,14 +38,14 @@ public final class SpreadSheetDataDisplayName implements HasDataDisplayName { private final SpreadSheetParam resource; @Override - public String getDisplayName(DataSource dataSource) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSource dataSource) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSource); SpreadSheetBean bean = resource.get(dataSource); return bean.getFile().getPath() + toString(bean.getGathering()); } @Override - public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSet); switch (dataSet.getKind()) { case COLLECTION: @@ -56,7 +57,7 @@ public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { } @Override - public String getDisplayNodeName(DataSet dataSet) { + public @NonNull String getDisplayNodeName(@NonNull DataSet dataSet) { DataSourcePreconditions.checkProvider(providerName, dataSet); switch (dataSet.getKind()) { case COLLECTION: diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadSheetSupport.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadSheetSupport.java index 87279adb..624e320a 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadSheetSupport.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadSheetSupport.java @@ -64,7 +64,7 @@ public final class SpreadSheetSupport implements HasDataHierarchy, HasTsStream { private final DataSetConversion seriesName; @Override - public List children(DataSource dataSource) throws IllegalArgumentException, IOException { + public @NonNull List children(@NonNull DataSource dataSource) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(providerName, dataSource); try (SpreadSheetConnection connection = spreadsheet.open(dataSource)) { @@ -79,7 +79,7 @@ public List children(DataSource dataSource) throws IllegalArgumentExcep } @Override - public List children(DataSet parent) throws IllegalArgumentException, IOException { + public @NonNull List children(@NonNull DataSet parent) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(providerName, parent); try (SpreadSheetConnection connection = spreadsheet.open(parent.getDataSource())) { @@ -96,7 +96,7 @@ public List children(DataSet parent) throws IllegalArgumentException, I } @Override - public Stream getData(DataSource dataSource, TsInformationType type) throws IOException { + public @NonNull Stream getData(@NonNull DataSource dataSource, @NonNull TsInformationType type) throws IOException { DataSourcePreconditions.checkProvider(providerName, dataSource); try (SpreadSheetConnection connection = spreadsheet.open(dataSource)) { @@ -113,7 +113,7 @@ public Stream getData(DataSource dataSource, TsInformationType type) } @Override - public Stream getData(DataSet dataSet, TsInformationType type) throws IllegalArgumentException, IOException { + public @NonNull Stream getData(@NonNull DataSet dataSet, @NonNull TsInformationType type) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(providerName, dataSet); try (SpreadSheetConnection connection = spreadsheet.open(dataSet.getDataSource())) { diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/BookSupplier.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadsheetManager.java similarity index 58% rename from jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/BookSupplier.java rename to jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadsheetManager.java index 07428539..eb34303d 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/BookSupplier.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/SpreadsheetManager.java @@ -18,32 +18,41 @@ import ec.util.spreadsheet.Book; import ec.util.spreadsheet.BookFactoryLoader; -import org.checkerframework.checker.nullness.qual.NonNull; +import lombok.NonNull; +import nbbrd.design.StaticFactoryMethod; import java.io.File; +import java.util.List; import java.util.Optional; /** * @author Philippe Charles */ -public interface BookSupplier { +//@MightBePromoted +@lombok.Builder +public final class SpreadsheetManager { - @NonNull Optional getFactory(@NonNull File file); - - default boolean hasFactory(@NonNull File file) { - return getFactory(file).isPresent(); + @StaticFactoryMethod + public static @NonNull SpreadsheetManager ofServiceLoader() { + return SpreadsheetManager.builder().factories(BookFactoryLoader.get()).build(); } - @NonNull - static BookSupplier usingServiceLoader() { - return BookSupplier::getLoaderByFile; - } + @lombok.Singular + private final List factories; - static Optional getLoaderByFile(File file) { - return BookFactoryLoader.get() + public @NonNull Optional getReader(@NonNull File file) { + return factories .stream() .filter(Book.Factory::canLoad) .filter(factory -> factory.accept(file)) .findFirst(); } + + public @NonNull Optional getWriter(@NonNull File file) { + return factories + .stream() + .filter(Book.Factory::canStore) + .filter(factory -> factory.accept(file)) + .findFirst(); + } } diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/grid/SheetGridOutput.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/grid/SheetGridOutput.java index cff49460..bfa65b88 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/grid/SheetGridOutput.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/grid/SheetGridOutput.java @@ -19,6 +19,8 @@ import jdplus.toolkit.base.tsp.grid.GridDataType; import ec.util.spreadsheet.helpers.ArraySheet; import jdplus.toolkit.base.tsp.grid.GridOutput; +import org.checkerframework.checker.nullness.qual.NonNull; + import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; @@ -38,7 +40,7 @@ public final class SheetGridOutput implements GridOutput { private ArraySheet result = null; @Override - public Set getDataTypes() { + public @NonNull Set getDataTypes() { EnumSet dataTypes = EnumSet.noneOf(GridDataType.class); if (isSupportedDataType.test(String.class)) { dataTypes.add(GridDataType.STRING); @@ -53,7 +55,7 @@ public Set getDataTypes() { } @Override - public Stream open(String name, int rows, int columns) { + public @NonNull Stream open(@NonNull String name, int rows, int columns) { return new SheetGridOutputStream(ArraySheet.builder(rows, columns).name(name)); } diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/legacy/LegacySpreadSheetMoniker.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/legacy/LegacySpreadSheetMoniker.java index ebfc4789..c0fb662b 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/legacy/LegacySpreadSheetMoniker.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/internal/spreadsheet/base/api/legacy/LegacySpreadSheetMoniker.java @@ -25,6 +25,7 @@ import jdplus.toolkit.base.tsp.HasDataMoniker; import jdplus.toolkit.base.tsp.legacy.LegacyFileId; import jdplus.toolkit.base.tsp.util.DataSourcePreconditions; +import org.checkerframework.checker.nullness.qual.NonNull; import java.io.File; import java.util.Optional; @@ -40,19 +41,19 @@ public final class LegacySpreadSheetMoniker implements HasDataMoniker { private final SpreadSheetParam param; @Override - public TsMoniker toMoniker(DataSource dataSource) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSource dataSource) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSource); throw new IllegalArgumentException("Not supported yet."); } @Override - public TsMoniker toMoniker(DataSet dataSet) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSet); throw new IllegalArgumentException("Not supported yet."); } @Override - public Optional toDataSource(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSource(@NonNull TsMoniker moniker) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, moniker); LegacyFileId id = LegacyFileId.parse(moniker.getId()); @@ -60,7 +61,7 @@ public Optional toDataSource(TsMoniker moniker) throws IllegalArgume } @Override - public Optional toDataSet(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSet(@NonNull TsMoniker moniker) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, moniker); LegacySpreadSheetId id = LegacySpreadSheetId.parse(moniker.getId()); diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/SpreadSheetProvider.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/SpreadSheetProvider.java index 4ade4bf3..fea5b0f2 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/SpreadSheetProvider.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/SpreadSheetProvider.java @@ -16,18 +16,18 @@ */ package jdplus.spreadsheet.base.api; +import ec.util.spreadsheet.Book; +import internal.spreadsheet.base.api.*; +import internal.spreadsheet.base.api.grid.SheetGrid; +import internal.spreadsheet.base.api.legacy.LegacySpreadSheetMoniker; import jdplus.toolkit.base.api.timeseries.TsProvider; import jdplus.toolkit.base.tsp.*; import jdplus.toolkit.base.tsp.grid.GridReader; import jdplus.toolkit.base.tsp.stream.HasTsStream; import jdplus.toolkit.base.tsp.stream.TsStreamAsProvider; import jdplus.toolkit.base.tsp.util.FallbackDataMoniker; -import jdplus.toolkit.base.tsp.util.IOCacheFactoryLoader; import jdplus.toolkit.base.tsp.util.ResourcePool; -import ec.util.spreadsheet.Book; -import internal.spreadsheet.base.api.*; -import internal.spreadsheet.base.api.grid.SheetGrid; -import internal.spreadsheet.base.api.legacy.LegacySpreadSheetMoniker; +import jdplus.toolkit.base.tsp.util.ShortLivedCachingLoader; import nbbrd.design.DirectImpl; import nbbrd.service.ServiceProvider; @@ -41,9 +41,9 @@ @ServiceProvider(TsProvider.class) public final class SpreadSheetProvider implements FileLoader { - private static final String NAME = "XCLPRVDR"; + public static final String NAME = "XCLPRVDR"; - private final BookSupplier bookSupplier; + private final SpreadsheetManager spreadsheetManager; @lombok.experimental.Delegate private final HasDataSourceMutableList mutableListSupport; @@ -67,7 +67,7 @@ public final class SpreadSheetProvider implements FileLoader { private final TsProvider tsSupport; public SpreadSheetProvider() { - this.bookSupplier = BookSupplier.usingServiceLoader(); + this.spreadsheetManager = SpreadsheetManager.ofServiceLoader(); ResourcePool pool = SpreadSheetSupport.newConnectionPool(); SpreadSheetParam param = new SpreadSheetParam.V1(); @@ -77,7 +77,7 @@ public SpreadSheetProvider() { this.beanSupport = HasDataSourceBean.of(NAME, param, param.getVersion()); this.filePathSupport = HasFilePaths.of(pool::clear); this.displayNameSupport = SpreadSheetDataDisplayName.of(NAME, param); - this.spreadSheetSupport = SpreadSheetSupport.of(NAME, pool.asFactory(dataSource -> openConnection(dataSource, filePathSupport, param, bookSupplier)), ignore -> param.getSheetParam(), ignore -> param.getSeriesParam()); + this.spreadSheetSupport = SpreadSheetSupport.of(NAME, pool.asFactory(dataSource -> openConnection(dataSource, filePathSupport, param, spreadsheetManager)), ignore -> param.getSheetParam(), ignore -> param.getSeriesParam()); this.tsSupport = TsStreamAsProvider.of(NAME, spreadSheetSupport, monikerSupport, pool::clear); } @@ -93,15 +93,15 @@ public String getFileDescription() { @Override public boolean accept(File pathname) { - return bookSupplier.hasFactory(pathname); + return spreadsheetManager.getReader(pathname).isPresent(); } - private static SpreadSheetConnection openConnection(DataSource key, HasFilePaths paths, SpreadSheetParam param, BookSupplier books) throws IOException { + private static SpreadSheetConnection openConnection(DataSource key, HasFilePaths paths, SpreadSheetParam param, SpreadsheetManager books) throws IOException { SpreadSheetBean bean = param.get(key); File file = paths.resolveFilePath(bean.getFile()); - Book.Factory factory = books.getFactory(file).orElseThrow(() -> new IOException("File type not supported")); + Book.Factory factory = books.getReader(file).orElseThrow(() -> new IOException("File type not supported")); SheetGrid result = SheetGrid.of(file, factory, getReader(bean)); - return CachedSpreadSheetConnection.of(result, file, IOCacheFactoryLoader.get()); + return CachedSpreadSheetConnection.of(result, file, ShortLivedCachingLoader.get()); } private static GridReader getReader(SpreadSheetBean bean) { diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutput.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutput.java new file mode 100644 index 00000000..02705bd3 --- /dev/null +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutput.java @@ -0,0 +1,232 @@ +/* + * Copyright 2013 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.1 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * http://ec.europa.eu/idabc/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.spreadsheet.base.api.sa; + + +import ec.util.spreadsheet.Book; +import ec.util.spreadsheet.helpers.ArrayBook; +import ec.util.spreadsheet.helpers.ArraySheet; +import internal.spreadsheet.base.api.SpreadsheetManager; +import jdplus.sa.base.api.SaDocument; +import jdplus.toolkit.base.api.information.Explorable; +import jdplus.toolkit.base.api.processing.Output; +import jdplus.toolkit.base.api.timeseries.TsData; +import jdplus.toolkit.base.api.timeseries.TsDataTable; +import jdplus.toolkit.base.api.timeseries.TsPeriod; +import jdplus.toolkit.base.api.util.MultiLineNameUtil; +import jdplus.toolkit.base.api.util.NamedObject; +import jdplus.toolkit.base.api.util.Paths; +import nbbrd.design.VisibleForTesting; + +import java.io.File; +import java.io.IOException; +import java.time.ZoneId; +import java.util.*; +import java.util.Map.Entry; + +/** + * @author Kristof Bayens + */ +public final class SpreadsheetOutput implements Output { + + private final SpreadsheetOutputConfiguration config; + private final SpreadsheetManager spreadsheetManager; + private final List summaries; + private File folder; + + public SpreadsheetOutput(SpreadsheetOutputConfiguration config) { + this(config, SpreadsheetManager.ofServiceLoader()); + } + + @VisibleForTesting + SpreadsheetOutput(SpreadsheetOutputConfiguration config, SpreadsheetManager spreadsheetManager) { + this.config = config.clone(); + this.spreadsheetManager = spreadsheetManager; + this.summaries = new ArrayList<>(); + } + + @Override + public void process(SaDocument document) { + Summary summary = Summary.of(document.getName(), document.getResults(), config.getSeries()); +// if (config_.isSaveModel()) { +// summary.setModel(document.getSpecification()); +// } + summaries.add(summary); + } + + @Override + public void start(Object context) { + summaries.clear(); + folder = Paths.folderFromContext(config.getFolder(), context); + } + + @Override + public void end(Object context) throws Exception { + File ssfile = getOutputFile(); + + Book.Factory factory = spreadsheetManager.getWriter(ssfile) + .orElseThrow(() -> new IOException("Cannot find spreadsheet writer for file '" + ssfile + "'")); + + ArrayBook.Builder workbook = ArrayBook.builder(); + + switch (config.getLayout()) { + case ByComponent: { + Map>> allData = new LinkedHashMap<>(); + for (Summary summary : summaries) { + String name = getDisplayName(summary); + summary.series().forEach((k, v) -> allData.computeIfAbsent(k, ignore -> new ArrayList<>()).add(new NamedObject<>(name, v))); + } + for (Entry>> keyValue : allData.entrySet()) { + String sheetName = keyValue.getKey(); + List firstHeader = new ArrayList<>(); + List secondHeader = new ArrayList<>(); + List table = new ArrayList<>(); + + firstHeader.add(keyValue.getKey()); + keyValue.getValue().forEach(data -> { + secondHeader.add(data.getName()); + table.add(nullToEmpty(data.getName(), data.getObject())); + }); + + workbook.sheet(toSheet(sheetName, firstHeader, secondHeader, table, config.isVerticalOrientation())); + } + break; + } + case BySeries: { + for (int sheetIndex = 0; sheetIndex < summaries.size(); sheetIndex++) { + Summary summary = summaries.get(sheetIndex); + + String sheetName = "Series" + sheetIndex; + List firstHeader = new ArrayList<>(); + List secondHeader = new ArrayList<>(); + List table = new ArrayList<>(); + + firstHeader.add(getDisplayName(summary)); + summary.series().forEach((k, v) -> { + secondHeader.add(k); + table.add(nullToEmpty(k, v)); + }); + + workbook.sheet(toSheet(sheetName, firstHeader, secondHeader, table, config.isVerticalOrientation())); + } + break; + } + case OneSheet: { + String sheetName = "Series"; + List firstHeader = new ArrayList<>(); + List secondHeader = new ArrayList<>(); + List table = new ArrayList<>(); + + for (Summary summary : summaries) { + firstHeader.add(getDisplayName(summary)); + for (int columnIndex = 1; columnIndex < summary.series().size(); columnIndex++) { + firstHeader.add(null); + } + summary.series().forEach((k, v) -> { + secondHeader.add(k); + table.add(nullToEmpty(k, v)); + }); + } + + workbook.sheet(toSheet(sheetName, firstHeader, secondHeader, table, config.isVerticalOrientation())); + break; + } + } + + factory.store(ssfile, workbook.build()); + } + + @Override + public String getName() { + return "Spreadsheet"; + } + + @Override + public boolean isAvailable() { + return true; + } + + private File getOutputFile() { + return new File(folder, config.getFileName()).getAbsoluteFile(); + } + + private String getDisplayName(Summary summary) { + return config.isFullName() ? MultiLineNameUtil.join(summary.name(), " * ") : MultiLineNameUtil.last(summary.name()); + } + + private static TsData nullToEmpty(String k, TsData v) { + return v != null ? v : TsData.empty("MISSING " + k); + } + + private static ArraySheet toSheet(String sheetName, List headers0, List headers1, List collection, boolean verticalOrientation) { + TsDataTable table = TsDataTable.of(collection); + ArraySheet.Builder result = ArraySheet.builder().name(sheetName); + if (verticalOrientation) { + //headers0 + result.row(0, 1, headers0); + //headers1 + result.row(1, 1, headers1); + //columnvalues & data + TsDataTable.Cursor cursor = table.cursor(TsDataTable.DistributionType.FIRST); + for (int p = 0; p < cursor.getPeriodCount(); p++) { + List data = new ArrayList<>(); + data.add(toDate(table.getDomain().get(p))); + for (int s = 0; s < cursor.getSeriesCount(); s++) { + TsDataTable.ValueStatus status = cursor.moveTo(p, s).getStatus(); + data.add(status == TsDataTable.ValueStatus.PRESENT ? cursor.getValue() : null); + } + result.row(2 + p, 0, data); + } + } else { + //headers0 + result.column(1, 0, headers0); + //headers1 + result.column(1, 1, headers1); + //columnvalues & data + TsDataTable.Cursor cursor = table.cursor(TsDataTable.DistributionType.FIRST); + for (int p = 0; p < cursor.getPeriodCount(); p++) { + List data = new ArrayList<>(); + data.add(toDate(table.getDomain().get(p))); + for (int s = 0; s < cursor.getSeriesCount(); s++) { + TsDataTable.ValueStatus status = cursor.moveTo(p, s).getStatus(); + data.add(status == TsDataTable.ValueStatus.PRESENT ? cursor.getValue() : null); + } + result.column(0, 2 + p, data); + } + } + return result.build(); + } + + private static Date toDate(TsPeriod period) { + return Date.from(period.start().atZone(ZoneId.systemDefault()).toInstant()); + } + + /** + * @author Kristof Bayens + */ + private record Summary(String name, LinkedHashMap series) { + + public static Summary of(String name, Explorable results, List items) { + LinkedHashMap series = new LinkedHashMap<>(); + for (String item : items) { + series.put(item, results != null ? results.getData(item, TsData.class) : null); + } + return new Summary(name, series); + } + + } +} diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutputConfiguration.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutputConfiguration.java new file mode 100644 index 00000000..10e3751a --- /dev/null +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutputConfiguration.java @@ -0,0 +1,55 @@ +/* + * Copyright 2013 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.1 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * http://ec.europa.eu/idabc/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +package jdplus.spreadsheet.base.api.sa; + +import java.io.File; +import java.util.List; + +/** + * @author Kristof Bayens + */ +@lombok.Data +public final class SpreadsheetOutputConfiguration implements Cloneable { + + public enum SpreadsheetLayout { + + BySeries, + ByComponent, + OneSheet + } + + private static final String DEFAULT_FILE_NAME = "demetra.xlsx"; + private static final List DEFAULT_SERIES = List.of("y", "t", "sa", "s", "i", "ycal"); + + private boolean saveModel = false; + private boolean verticalOrientation = true; + private SpreadsheetLayout layout = SpreadsheetLayout.BySeries; + private File folder; + private String fileName = DEFAULT_FILE_NAME; + private List series = DEFAULT_SERIES; + private boolean fullName = true; + + @Override + public SpreadsheetOutputConfiguration clone() { + try { + return (SpreadsheetOutputConfiguration) super.clone(); + } catch (CloneNotSupportedException ex) { + return null; + } + } +} diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutputFactory.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutputFactory.java new file mode 100644 index 00000000..c9628085 --- /dev/null +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutputFactory.java @@ -0,0 +1,66 @@ +/* + * Copyright 2013 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.1 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * http://ec.europa.eu/idabc/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +package jdplus.spreadsheet.base.api.sa; + +import jdplus.sa.base.api.SaOutputFactory; +import nbbrd.design.DirectImpl; +import nbbrd.service.ServiceProvider; + +/** + * @author Kristof Bayens + */ +@DirectImpl +@ServiceProvider +public final class SpreadsheetOutputFactory implements SaOutputFactory { + + public static final String NAME = "Excel"; + private final SpreadsheetOutputConfiguration configuration; + private boolean enabled = true; + + public SpreadsheetOutputFactory() { + configuration = new SpreadsheetOutputConfiguration(); + } + + public SpreadsheetOutputFactory(SpreadsheetOutputConfiguration config) { + configuration = config; + } + + public SpreadsheetOutputConfiguration getConfiguration() { + return configuration; + } + + @Override + public String getName() { + return NAME; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public SpreadsheetOutput create() { + return new SpreadsheetOutput(configuration); + } +} diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/module-info.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/module-info.java index 6573b437..06f76bf1 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/module-info.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/main/java/module-info.java @@ -1,4 +1,6 @@ +import jdplus.sa.base.api.SaOutputFactory; import jdplus.spreadsheet.base.api.SpreadSheetProvider; +import jdplus.spreadsheet.base.api.sa.SpreadsheetOutputFactory; import jdplus.toolkit.base.api.timeseries.TsProvider; module jdplus.spreadsheet.base.api { @@ -9,10 +11,15 @@ requires static org.checkerframework.checker.qual; requires jdplus.toolkit.base.tsp; + requires jdplus.sa.base.core; requires nbbrd.spreadsheet.api; requires nbbrd.io.base; exports jdplus.spreadsheet.base.api; + exports jdplus.spreadsheet.base.api.sa; + + provides SaOutputFactory + with SpreadsheetOutputFactory; provides TsProvider with SpreadSheetProvider; diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/_demo/SpreadSheetProviderDemo.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/_demo/SpreadSheetProviderDemo.java index 1305588a..6f3c2f4b 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/_demo/SpreadSheetProviderDemo.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/_demo/SpreadSheetProviderDemo.java @@ -26,6 +26,9 @@ import java.io.File; import java.io.IOException; +import java.util.List; +import jdplus.toolkit.base.api.timeseries.TsMoniker; +import jdplus.toolkit.base.tsp.DataSet; /** * @author Philippe Charles @@ -35,17 +38,20 @@ public class SpreadSheetProviderDemo { @Demo public static void main(String[] args) throws IOException { File file = Top5Browsers.getRefFile(); - // 1. create and configure the provider try (SpreadSheetProvider provider = new SpreadSheetProvider()) { // 2. create and configure a bean SpreadSheetBean bean = provider.newBean(); bean.setFile(file); - + + // 3. create and open a DataSource from the bean DataSource dataSource = provider.encodeBean(bean); + List children = provider.children(dataSource); + provider.open(dataSource); + TsMoniker toMoniker = provider.toMoniker(dataSource); // 4. run demos ProviderDemo.printTree(provider, dataSource); diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/internal/spreadsheet/base/api/SpreadSheetConnectionTest.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/internal/spreadsheet/base/api/SpreadSheetConnectionTest.java index 801e9dff..e774f32d 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/internal/spreadsheet/base/api/SpreadSheetConnectionTest.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/internal/spreadsheet/base/api/SpreadSheetConnectionTest.java @@ -17,16 +17,16 @@ package internal.spreadsheet.base.api; import _test.DataForTest; +import internal.toolkit.base.tsp.util.SimpleMapCache; +import internal.spreadsheet.base.api.grid.SheetGrid; import jdplus.toolkit.base.api.timeseries.TsCollection; import jdplus.toolkit.base.tsp.grid.GridReader; -import jdplus.toolkit.base.tsp.util.IOCache; -import internal.spreadsheet.base.api.grid.SheetGrid; import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; +import java.util.HashMap; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -38,50 +38,30 @@ public class SpreadSheetConnectionTest { @Test public void testWithCache() throws IOException { SheetGrid grid = SheetGrid.of(new File(""), DataForTest.FACTORY, GridReader.DEFAULT); - ConcurrentMap cache = new ConcurrentHashMap<>(); - SpreadSheetConnection accessor = new CachedSpreadSheetConnection(grid, new FakeCache<>(cache)); - - cache.clear(); - assertThat(accessor.getSheetByName("s1")).map(TsCollection::getName).contains("s1"); - assertThat(cache).containsKeys("getSheetByName/s1"); - - cache.clear(); - assertThat(accessor.getSheetByName("other")).isEmpty(); - assertThat(cache).containsKeys("getSheetByName/other"); - - cache.clear(); - assertThat(accessor.getSheetNames()).containsExactly("s1", "s2"); - assertThat(cache).containsKeys("getSheetNames"); + SimpleMapCache> cache = new SimpleMapCache<>(new HashMap<>()); + try (var conn = new CachedSpreadSheetConnection(grid, cache)) { - cache.clear(); - assertThat(accessor.getSheets()).extracting(o -> o.getName()).containsExactly("s1", "s2"); - assertThat(cache).containsKeys("getSheets"); + cache.getMap().clear(); + assertThat(conn.getSheetByName("s1")).map(TsCollection::getName).contains("s1"); + assertThat(cache.getMap()).containsKeys("getSheetByName/s1"); - cache.clear(); - assertThat(accessor.getSheets()).extracting(o -> o.getName()).containsExactly("s1", "s2"); - assertThat(accessor.getSheetByName("s1")).map(TsCollection::getName).contains("s1"); - assertThat(accessor.getSheetNames()).containsExactly("s1", "s2"); - assertThat(cache).containsKeys("getSheets"); - } - - @lombok.AllArgsConstructor - private static final class FakeCache implements IOCache { + cache.getMap().clear(); + assertThat(conn.getSheetByName("other")).isEmpty(); + assertThat(cache.getMap()).containsKeys("getSheetByName/other"); - @lombok.NonNull - private final ConcurrentMap delegate; + cache.getMap().clear(); + assertThat(conn.getSheetNames()).containsExactly("s1", "s2"); + assertThat(cache.getMap()).containsKeys("getSheetNames"); - @Override - public void put(K key, V value) { - delegate.put(key, value); - } - - @Override - public V get(K key) { - return delegate.get(key); - } + cache.getMap().clear(); + assertThat(conn.getSheets()).extracting(TsCollection::getName).containsExactly("s1", "s2"); + assertThat(cache.getMap()).containsKeys("getSheets"); - @Override - public void close() throws IOException { + cache.getMap().clear(); + assertThat(conn.getSheets()).extracting(TsCollection::getName).containsExactly("s1", "s2"); + assertThat(conn.getSheetByName("s1")).map(TsCollection::getName).contains("s1"); + assertThat(conn.getSheetNames()).containsExactly("s1", "s2"); + assertThat(cache.getMap()).containsKeys("getSheets"); } } } diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/internal/spreadsheet/base/api/SpreadSheetFactoryTest.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/internal/spreadsheet/base/api/SpreadSheetFactoryTest.java index 6f54169d..5f067540 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/internal/spreadsheet/base/api/SpreadSheetFactoryTest.java +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/internal/spreadsheet/base/api/SpreadSheetFactoryTest.java @@ -16,12 +16,12 @@ */ package internal.spreadsheet.base.api; +import ec.util.spreadsheet.Book; +import internal.spreadsheet.base.api.grid.SheetGrid; import jdplus.toolkit.base.api.timeseries.TsData; import jdplus.toolkit.base.api.timeseries.TsPeriod; import jdplus.toolkit.base.api.timeseries.TsUnit; import jdplus.toolkit.base.tsp.grid.GridReader; -import ec.util.spreadsheet.Book; -import internal.spreadsheet.base.api.grid.SheetGrid; import org.junit.jupiter.api.Test; import java.io.File; @@ -29,11 +29,11 @@ import java.util.NoSuchElementException; import static _test.Top5Browsers.getRefFile; +import static java.lang.Double.NaN; import static jdplus.toolkit.base.api.timeseries.TsUnit.MONTH; import static jdplus.toolkit.base.api.timeseries.TsUnit.QUARTER; import static jdplus.toolkit.base.tsp.grid.GridLayout.HORIZONTAL; import static jdplus.toolkit.base.tsp.grid.GridLayout.VERTICAL; -import static java.lang.Double.NaN; import static org.assertj.core.api.Assertions.assertThat; /** @@ -44,7 +44,7 @@ public class SpreadSheetFactoryTest { @Test public void test() throws IOException { File refFile = getRefFile(); - testFactory(BookSupplier.getLoaderByFile(refFile).orElseThrow(NoSuchElementException::new), refFile); + testFactory(SpreadsheetManager.ofServiceLoader().getReader(refFile).orElseThrow(NoSuchElementException::new), refFile); } private static void testFactory(Book.Factory bookFactory, File file) throws IOException { diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutputTest.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutputTest.java new file mode 100644 index 00000000..dc2de892 --- /dev/null +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-api/src/test/java/jdplus/spreadsheet/base/api/sa/SpreadsheetOutputTest.java @@ -0,0 +1,304 @@ +package jdplus.spreadsheet.base.api.sa; + +import ec.util.spreadsheet.Book; +import ec.util.spreadsheet.helpers.ArrayBook; +import ec.util.spreadsheet.helpers.ArraySheet; +import internal.spreadsheet.base.api.SpreadsheetManager; +import jdplus.sa.base.api.SaDocument; +import jdplus.toolkit.base.api.processing.GenericOutput; +import jdplus.toolkit.base.api.timeseries.Ts; +import jdplus.toolkit.base.api.timeseries.TsData; +import jdplus.toolkit.base.api.timeseries.TsPeriod; +import lombok.NonNull; +import nbbrd.design.MightBePromoted; +import org.assertj.core.util.DateUtil; +import org.junit.Test; +import tck.demetra.data.Data; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.AbstractList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import static jdplus.spreadsheet.base.api.sa.SpreadsheetOutputConfiguration.SpreadsheetLayout.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.atIndex; + +public class SpreadsheetOutputTest { + + @Test + public void testBySeriesNoKeys() throws Exception { + SpreadsheetOutputConfiguration config = new SpreadsheetOutputConfiguration(); + config.setLayout(BySeries); + config.setSeries(List.of()); + + assertThat(write(config)).isEmpty(); + + assertThat(write(config, DOC1, DOC2, DOC3)).extracting(ArraySheet::getName) + .containsExactly("Series0", "Series1", "Series2"); + + assertThat(write(config, DOC1, DOC2, DOC3)).extracting(SpreadsheetOutputTest::toTable) + .hasSize(3) + .contains( + new Object[][]{ + {null, D1__}, + }, atIndex(0)) + .contains( + new Object[][]{ + {null, D2__}, + }, atIndex(1)) + .contains( + new Object[][]{ + {null, D3__}, + }, atIndex(2)); + } + + @Test + public void testBySeriesAnyKeys() throws Exception { + SpreadsheetOutputConfiguration config = new SpreadsheetOutputConfiguration(); + config.setLayout(BySeries); + config.setSeries(List.of(__Q_, __M_)); + + assertThat(write(config)).isEmpty(); + + assertThat(write(config, DOC1, DOC2, DOC3)).extracting(ArraySheet::getName) + .containsExactly("Series0", "Series1", "Series2"); + + assertThat(write(config, DOC1, DOC2, DOC3)).extracting(SpreadsheetOutputTest::toTable) + .hasSize(3) + .contains( + new Object[][]{ + {null, D1__, null}, + {null, __Q_, __M_}, + {_JAN, D1Q1, D1M1}, + {_FEB, null, D1M2}, + {_MAR, null, null}, + }, atIndex(0)) + .contains( + new Object[][]{ + {null, D2__, null}, + {null, __Q_, __M_}, + {_FEB, null, D2M2}, + }, atIndex(1)) + .contains( + new Object[][]{ + {null, D3__, null}, + {null, __Q_, __M_}, + }, atIndex(2)); + } + + @Test + public void testByComponentNoKeys() throws Exception { + SpreadsheetOutputConfiguration config = new SpreadsheetOutputConfiguration(); + config.setLayout(ByComponent); + config.setSeries(List.of()); + + assertThat(write(config)).isEmpty(); + assertThat(write(config, DOC1, DOC2, DOC3)).isEmpty(); + } + + @Test + public void testByComponentAnyKeys() throws Exception { + SpreadsheetOutputConfiguration config = new SpreadsheetOutputConfiguration(); + config.setLayout(ByComponent); + config.setSeries(List.of(__Q_, __M_)); + + assertThat(write(config)).isEmpty(); + + assertThat(write(config, DOC1, DOC2, DOC3)).extracting(ArraySheet::getName) + .containsExactly(__Q_, __M_); + + assertThat(write(config, DOC1, DOC2, DOC3)).extracting(SpreadsheetOutputTest::toTable) + .hasSize(2) + .contains( + new Object[][]{ + {null, __Q_, null, null}, + {null, D1__, D2__, D3__}, + {_JAN, D1Q1, null, null}, + }, atIndex(0)) + .contains( + new Object[][]{ + {null, __M_, null, null}, + {null, D1__, D2__, D3__}, + {_JAN, D1M1, null, null}, + {_FEB, D1M2, D2M2, null}, + }, atIndex(1)); + } + + @Test + public void testOneSheetNoKeys() throws Exception { + SpreadsheetOutputConfiguration config = new SpreadsheetOutputConfiguration(); + config.setLayout(OneSheet); + config.setSeries(List.of()); + + assertThat(write(config)).extracting(ArraySheet::getName) + .containsExactly("Series"); + + assertThat(write(config)).extracting(SpreadsheetOutputTest::toTable) + .hasSize(1) + .contains(new Object[][]{ + }, atIndex(0)); + + assertThat(write(config, DOC1, DOC2, DOC3)).extracting(ArraySheet::getName) + .containsExactly("Series"); + + assertThat(write(config, DOC1, DOC2, DOC3)).extracting(SpreadsheetOutputTest::toTable) + .hasSize(1) + .contains(new Object[][]{ + {null, D1__, D2__, D3__}, + }, atIndex(0)); + } + + @Test + public void testOneSheetAnyKeys() throws Exception { + SpreadsheetOutputConfiguration config = new SpreadsheetOutputConfiguration(); + config.setLayout(OneSheet); + config.setSeries(List.of(__Q_, __M_)); + + assertThat(write(config)).extracting(ArraySheet::getName) + .containsExactly("Series"); + + assertThat(write(config)).extracting(SpreadsheetOutputTest::toTable) + .hasSize(1) + .contains(new Object[][]{ + }, atIndex(0)); + + assertThat(write(config, DOC1, DOC2, DOC3)).extracting(ArraySheet::getName) + .containsExactly("Series"); + + assertThat(write(config, DOC1, DOC2, DOC3)).extracting(SpreadsheetOutputTest::toTable) + .hasSize(1) + .contains(new Object[][]{ + {null, D1__, null, D2__, null, D3__, null}, + {null, __Q_, __M_, __Q_, __M_, __Q_, __M_}, + {_JAN, D1Q1, D1M1, null, null, null, null}, + {_FEB, null, D1M2, null, D2M2, null, null}, + {_MAR, null, null, null, null, null, null}, + }, atIndex(0)); + } + + private static List write(SpreadsheetOutputConfiguration config, SaDocument... docs) throws Exception { + AtomicReference storage = new AtomicReference<>(); + SpreadsheetManager manager = SpreadsheetManager.builder().factory(new MockedFactory(storage)).build(); + SpreadsheetOutput output = new SpreadsheetOutput(config, manager); + output.start(null); + for (SaDocument doc : docs) { + output.process(doc); + } + output.end(null); + return asList(storage.get()); + } + + @MightBePromoted + private static List asList(ArrayBook book) { + return new AbstractList<>() { + @Override + public ArraySheet get(int index) { + return book.getSheet(index); + } + + @Override + public int size() { + return book.getSheetCount2(); + } + }; + } + + @MightBePromoted + private static Object[][] toTable(ArraySheet sheet) { + Object[][] result = new Object[sheet.getRowCount()][]; + for (int i = 0; i < sheet.getRowCount(); i++) { + Object[] row = new Object[sheet.getColumnCount()]; + for (int j = 0; j < sheet.getColumnCount(); j++) { + row[j] = sheet.getCellValue(i, j); + } + result[i] = row; + } + return result; + } + + @lombok.AllArgsConstructor + private static class MockedFactory extends Book.Factory { + + private final @NonNull AtomicReference storage; + + @Override + public boolean accept(File pathname) { + return true; + } + + @Override + public @NonNull String getName() { + return "demo"; + } + + @Override + public @NonNull Book load(@NonNull InputStream stream) throws IOException { + ArrayBook result = storage.get(); + if (result == null) throw new IOException("Storage empty"); + return result; + } + + @Override + public void store(@NonNull OutputStream stream, @NonNull Book book) throws IOException { + storage.set(ArrayBook.copyOf(book)); + } + } + + private static final String D1__ = "full"; + private static final String D2__ = "partial"; + private static final String D3__ = "empty"; + private static final String __M_ = "monthly"; + private static final String __Q_ = "quarterly"; + private static final String __Y_ = "yearly"; + private static final Date _JAN = DateUtil.parse("2010-01-01"); + private static final Date _FEB = DateUtil.parse("2010-02-01"); + private static final Date _MAR = DateUtil.parse("2010-03-01"); + private static final double D1M1 = 9161; + private static final double D1M2 = 9162; + private static final double D1Q1 = 9171; + private static final double D2M2 = 9262; + private static final double D1Y1 = 9181; + private static final Ts TS = Ts.of(Data.TS_PROD); + + private static final SaDocument DOC1 = new SaDocument( + D1__, + TS, + null, + GenericOutput + .builder() + .entry(__M_, TsData.ofInternal(TsPeriod.monthly(2010, 1), new double[]{D1M1, D1M2})) + .entry(__Q_, TsData.ofInternal(TsPeriod.quarterly(2010, 1), new double[]{D1Q1})) + .entry(__Y_, TsData.ofInternal(TsPeriod.yearly(2010), new double[]{D1Y1})) + .build(), + null, + null + ); + + private static final SaDocument DOC2 = new SaDocument( + D2__, + TS, + null, + GenericOutput + .builder() + .entry(__M_, TsData.ofInternal(TsPeriod.monthly(2010, 2), new double[]{D2M2})) + .build(), + null, + null + ); + + private static final SaDocument DOC3 = new SaDocument( + D3__, + TS, + null, + GenericOutput + .builder() + .build(), + null, + null + ); +} diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/pom.xml b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/pom.xml new file mode 100644 index 00000000..14ea4146 --- /dev/null +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + + eu.europa.ec.joinup.sat + jdplus-spreadsheet-base-parent + 3.1.0 + + + jdplus-spreadsheet-base-r + jar + + ${project.artifactId} + ${project.parent.artifactId} - ${project.artifactId} + ${project.parent.url} + + + + + eu.europa.ec.joinup.sat + jdplus-spreadsheet-base-api + ${project.version} + + + eu.europa.ec.joinup.sat + jdplus-toolkit-base-r + ${project.version} + + + \ No newline at end of file diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/src/main/java/jdplus/spreadsheet/base/r/SpreadSheets.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/src/main/java/jdplus/spreadsheet/base/r/SpreadSheets.java new file mode 100644 index 00000000..0c7d13e9 --- /dev/null +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/src/main/java/jdplus/spreadsheet/base/r/SpreadSheets.java @@ -0,0 +1,222 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.spreadsheet.base.r; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import jdplus.spreadsheet.base.api.SpreadSheetBean; +import jdplus.spreadsheet.base.api.SpreadSheetProvider; +import jdplus.toolkit.base.api.timeseries.Ts; +import jdplus.toolkit.base.api.timeseries.TsCollection; +import jdplus.toolkit.base.api.timeseries.TsData; +import jdplus.toolkit.base.api.timeseries.TsFactory; +import jdplus.toolkit.base.api.timeseries.TsInformationType; +import jdplus.toolkit.base.api.timeseries.TsMoniker; +import jdplus.toolkit.base.api.timeseries.util.ObsGathering; +import jdplus.toolkit.base.r.util.Providers; +import jdplus.toolkit.base.tsp.DataSet; +import jdplus.toolkit.base.tsp.DataSource; +import jdplus.toolkit.base.tsp.util.ObsFormat; + +/** + * + * @author palatej + */ +@lombok.experimental.UtilityClass +public class SpreadSheets { + + private final SpreadSheetProvider PROVIDER = new SpreadSheetProvider(); + + private SpreadSheetProvider currentProvider() { + return (SpreadSheetProvider) TsFactory.getDefault().getProvider(SpreadSheetProvider.NAME).orElse(null); + } + + public String changeFile(String id, String nfile, String ofile) { + Optional set = PROVIDER.toDataSet(TsMoniker.of(SpreadSheetProvider.NAME, id)); + Optional m = set.map(d -> { + SpreadSheetBean bean = PROVIDER.decodeBean(d.getDataSource()); + if (ofile.isEmpty() || bean.getFile().getName().equals(ofile)) { + bean.setFile(new File(nfile)); + DataSource src = PROVIDER.encodeBean(bean); + DataSet nd = d.toBuilder() + .dataSource(src) + .build(); + return PROVIDER.toMoniker(nd).getId(); + } else { + return id; + } + }); + return m.orElse(id); + } + + public DataSource source(String file, ObsFormat obsFormat, ObsGathering obsGathering) { + SpreadSheetBean bean = new SpreadSheetBean(); + bean.setFile(new File(file)); + if (obsFormat != null) { + bean.setFormat(obsFormat); + } + if (obsGathering != null) { + bean.setGathering(obsGathering); + } + return PROVIDER.encodeBean(bean); + } + + public String[] sheets(DataSource source) throws IllegalArgumentException, IOException { + SpreadSheetProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new RuntimeException("SpreadSheetProvider is not available"); + } + try { + currentProvider.open(source); + List sheets = currentProvider.children(source); + return sheets.stream().map(s -> currentProvider.getDisplayNodeName(s)).toArray(String[]::new); + } finally { + currentProvider.close(source); + } + } + + public String[] series(DataSource source, int sheet) throws IllegalArgumentException, IOException { + SpreadSheetProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new RuntimeException("SpreadSheetProvider is not available"); + } + try { + currentProvider.open(source); + List sheets = currentProvider.children(source); + if (sheet > sheets.size()) { + throw new IllegalArgumentException("Invalid sheet"); + } + DataSet ds = sheets.get(sheet - 1); + List all = currentProvider.children(ds); + return all.stream().map(s -> currentProvider.getDisplayNodeName(s)).toArray(String[]::new); + } finally { + currentProvider.close(source); + } + } + + public Ts series(DataSource source, int sheet, int series, boolean fullName) throws IllegalArgumentException, IOException { + SpreadSheetProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new RuntimeException("SpreadSheetProvider is not available"); + } + try { + currentProvider.open(source); + List sheets = currentProvider.children(source); + if (sheet > sheets.size()) { + throw new IllegalArgumentException("Invalid sheet"); + } + DataSet ds = sheets.get(sheet - 1); + List all = currentProvider.children(ds); + if (series > all.size()) { + throw new IllegalArgumentException("Invalid sheet"); + } + DataSet s = all.get(series - 1); + TsMoniker moniker = currentProvider.toMoniker(s); + return currentProvider.getTs(moniker, TsInformationType.All).withName(fullName ? currentProvider.getDisplayName(s) : currentProvider.getDisplayNodeName(s)); + } finally { + currentProvider.close(source); + } + } + + private Ts of(SpreadSheetProvider provider, DataSet c) { + TsMoniker moniker = provider.toMoniker(c); + try { + return provider.getTs(moniker, TsInformationType.All) + .withName(provider.getDisplayNodeName(c)); + } catch (IOException ex) { + return Ts.builder() + .moniker(moniker) + .data(TsData.empty("Unavailable")) + .build(); + } + } + + public TsCollection collection(DataSource source, int sheet, boolean fullNames) throws IllegalArgumentException, IOException { + SpreadSheetProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new RuntimeException("SpreadSheetProvider is not available"); + } + try { + currentProvider.open(source); + List sheets = currentProvider.children(source); + if (sheet > sheets.size()) { + throw new IllegalArgumentException("Invalid sheet"); + } + DataSet ds = sheets.get(sheet - 1); + TsMoniker moniker = currentProvider.toMoniker(ds); + if (fullNames) { + return currentProvider.getTsCollection(moniker, TsInformationType.All).withName(currentProvider.getDisplayName(ds)); + } else { + List schildren = currentProvider.children(ds); + List all = schildren.stream().map(c -> of(currentProvider, c)).toList(); + return TsCollection.builder() + .name(currentProvider.getDisplayName(ds)) + .moniker(moniker) + .items(all) + .build(); + } + } finally { + currentProvider.close(source); + } + } + + public void setPaths(String[] paths) { + SpreadSheetProvider provider = currentProvider(); + if (provider == null) { + throw new RuntimeException("SpreadSheetProvider is not available"); + } + File[] files = Arrays.stream(paths).map(p -> new File(p)).toArray(n -> new File[n]); + provider.setPaths(files); + } + + public void updateTsFactory() { + SpreadSheetProvider currentProvider = currentProvider(); + if (currentProvider == null) { + Providers.updateTsFactory(new SpreadSheetProvider()); + } + } + + public DataSet decode(String id) { + Optional set = PROVIDER.toDataSet(TsMoniker.of(SpreadSheetProvider.NAME, id)); + return set.orElse(null); + } + + public String encode(DataSet set) { + return PROVIDER.toMoniker(set).getId(); + } + + public SpreadSheetBean sourceOf(DataSet set) { + return PROVIDER.decodeBean(set.getDataSource()); + } + + public DataSet seriesDataSet(DataSource source, String sheetName, String seriesName){ + return DataSet.builder(source, DataSet.Kind.SERIES) + .parameter("sheetName", sheetName) + .parameter("seriesName", seriesName) + .build(); + } + + public DataSet sheetDataSet(DataSource source, String sheetName){ + return DataSet.builder(source, DataSet.Kind.COLLECTION) + .parameter("sheetName", sheetName) + .build(); + } + +} diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/src/main/java/module-info.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/src/main/java/module-info.java new file mode 100644 index 00000000..ea2ea741 --- /dev/null +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/src/main/java/module-info.java @@ -0,0 +1,16 @@ + +module jdplus.spreadsheet.base.r { + + requires static lombok; + requires static nbbrd.design; + requires static nbbrd.service; + requires static org.checkerframework.checker.qual; + + requires jdplus.toolkit.base.api; + requires jdplus.toolkit.base.core; + requires jdplus.toolkit.base.tsp; + requires jdplus.spreadsheet.base.api; + requires jdplus.toolkit.base.r; + + exports jdplus.spreadsheet.base.r; +} \ No newline at end of file diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/src/main/javadoc/EmptyJavaDoc.java b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/src/main/javadoc/EmptyJavaDoc.java new file mode 100644 index 00000000..530579d4 --- /dev/null +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/jdplus-spreadsheet-base-r/src/main/javadoc/EmptyJavaDoc.java @@ -0,0 +1,6 @@ +/** + * Workaround for JavaDoc issues with Lombok. + */ +public class EmptyJavaDoc { + +} \ No newline at end of file diff --git a/jdplus-main-base/jdplus-spreadsheet-base-parent/pom.xml b/jdplus-main-base/jdplus-spreadsheet-base-parent/pom.xml index 2fe7a058..095291d0 100644 --- a/jdplus-main-base/jdplus-spreadsheet-base-parent/pom.xml +++ b/jdplus-main-base/jdplus-spreadsheet-base-parent/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-main-base - 3.0.2 + 3.1.0 jdplus-spreadsheet-base-parent @@ -17,5 +17,6 @@ jdplus-spreadsheet-base-api + jdplus-spreadsheet-base-r \ No newline at end of file diff --git a/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/pom.xml b/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/pom.xml index 2407fd0a..9ad9079b 100644 --- a/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/pom.xml +++ b/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-sql-base-parent - 3.0.2 + 3.1.0 jdplus-sql-base-api @@ -83,7 +83,7 @@ org.hsqldb hsqldb - 2.7.1 + 2.7.2 test diff --git a/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/internal/sql/base/api/odbc/legacy/LegacyOdbcMoniker.java b/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/internal/sql/base/api/odbc/legacy/LegacyOdbcMoniker.java index c11f3777..3fabba01 100644 --- a/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/internal/sql/base/api/odbc/legacy/LegacyOdbcMoniker.java +++ b/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/internal/sql/base/api/odbc/legacy/LegacyOdbcMoniker.java @@ -25,6 +25,7 @@ import jdplus.toolkit.base.tsp.HasDataMoniker; import jdplus.toolkit.base.tsp.cube.TableAsCube; import jdplus.toolkit.base.tsp.util.DataSourcePreconditions; +import org.checkerframework.checker.nullness.qual.NonNull; import java.util.Arrays; import java.util.Optional; @@ -40,19 +41,19 @@ public final class LegacyOdbcMoniker implements HasDataMoniker { private final OdbcParam param; @Override - public TsMoniker toMoniker(DataSource dataSource) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSource dataSource) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSource); throw new IllegalArgumentException("Not supported yet."); } @Override - public TsMoniker toMoniker(DataSet dataSet) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSet); throw new IllegalArgumentException("Not supported yet."); } @Override - public Optional toDataSource(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSource(@NonNull TsMoniker moniker) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, moniker); LegacyOdbcId id = LegacyOdbcId.parse(moniker.getId()); @@ -60,7 +61,7 @@ public Optional toDataSource(TsMoniker moniker) throws IllegalArgume } @Override - public Optional toDataSet(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSet(@NonNull TsMoniker moniker) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, moniker); LegacyOdbcId id = LegacyOdbcId.parse(moniker.getId()); diff --git a/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/SqlTableAsCubeResource.java b/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/SqlTableAsCubeResource.java index 37da4759..6856ae32 100644 --- a/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/SqlTableAsCubeResource.java +++ b/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/SqlTableAsCubeResource.java @@ -89,52 +89,52 @@ public Exception testConnection() { } @Override - public CubeId getRoot() throws Exception { + public @NonNull CubeId getRoot() throws Exception { return root; } @Override - public AllSeriesCursor getAllSeriesCursor(CubeId id) throws Exception { + public @NonNull AllSeriesCursor getAllSeriesCursor(@NonNull CubeId id) throws Exception { return new AllSeriesQuery(id, table, labelColumn).call(supplier, db); } @Override - public AllSeriesWithDataCursor getAllSeriesWithDataCursor(CubeId id) throws Exception { + public @NonNull AllSeriesWithDataCursor getAllSeriesWithDataCursor(@NonNull CubeId id) throws Exception { return new AllSeriesWithDataQuery(id, table, labelColumn, tdp).call(supplier, db); } @Override - public SeriesCursor getSeriesCursor(CubeId id) throws Exception { + public @NonNull SeriesCursor getSeriesCursor(@NonNull CubeId id) throws Exception { return new SeriesQuery(id, table, labelColumn).call(supplier, db); } @Override - public SeriesWithDataCursor getSeriesWithDataCursor(CubeId id) throws Exception { + public @NonNull SeriesWithDataCursor getSeriesWithDataCursor(@NonNull CubeId id) throws Exception { return new SeriesWithDataQuery(id, table, labelColumn, tdp).call(supplier, db); } @Override - public ChildrenCursor getChildrenCursor(CubeId id) throws Exception { + public @NonNull ChildrenCursor getChildrenCursor(@NonNull CubeId id) throws Exception { return new ChildrenQuery(id, table).call(supplier, db); } @Override - public TsDataBuilder newBuilder() { + public @NonNull TsDataBuilder newBuilder() { return TsDataBuilder.byCalendar(new GregorianCalendar(TimeZone.getDefault(), Locale.getDefault()), gathering, ObsCharacteristics.ORDERED); } @Override - public String getDisplayName() throws Exception { + public @NonNull String getDisplayName() throws Exception { return TableAsCubeUtil.getDisplayName(db, table, tdp.getValueColumn(), gathering); } @Override - public String getDisplayName(CubeId id) throws Exception { + public @NonNull String getDisplayName(@NonNull CubeId id) throws Exception { return TableAsCubeUtil.getDisplayName(id, LABEL_COLLECTOR); } @Override - public String getDisplayNodeName(CubeId id) throws Exception { + public @NonNull String getDisplayNodeName(@NonNull CubeId id) throws Exception { return TableAsCubeUtil.getDisplayNodeName(id); } diff --git a/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/jdbc/JdbcProvider.java b/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/jdbc/JdbcProvider.java index 787e0670..81ed7152 100644 --- a/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/jdbc/JdbcProvider.java +++ b/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/jdbc/JdbcProvider.java @@ -16,6 +16,7 @@ */ package jdplus.sql.base.api.jdbc; +import internal.sql.base.api.jdbc.JdbcParam; import jdplus.sql.base.api.HasSqlProperties; import jdplus.sql.base.api.SqlTableAsCubeResource; import jdplus.toolkit.base.api.timeseries.TsProvider; @@ -23,9 +24,8 @@ import jdplus.toolkit.base.tsp.cube.*; import jdplus.toolkit.base.tsp.stream.HasTsStream; import jdplus.toolkit.base.tsp.stream.TsStreamAsProvider; -import jdplus.toolkit.base.tsp.util.IOCacheFactoryLoader; import jdplus.toolkit.base.tsp.util.ResourcePool; -import internal.sql.base.api.jdbc.JdbcParam; +import jdplus.toolkit.base.tsp.util.ShortLivedCachingLoader; import nbbrd.design.DirectImpl; import nbbrd.service.ServiceProvider; import nbbrd.sql.jdbc.SqlConnectionSupplier; @@ -80,7 +80,7 @@ private static CubeConnection openConnection(DataSource key, HasSqlProperties pr SqlTableAsCubeResource sqlResource = SqlTableAsCubeResource.of(properties.getConnectionSupplier(), bean.getDatabase(), bean.getTable(), toRoot(bean), toDataParams(bean), bean.getCube().getGathering(), bean.getCube().getLabel()); CubeConnection result = TableAsCubeConnection.of(sqlResource); - return BulkCubeConnection.of(result, bean.getCache(), IOCacheFactoryLoader.get()); + return BulkCubeConnection.of(result, bean.getCache(), ShortLivedCachingLoader.get()); } private static CubeId toRoot(JdbcBean bean) { diff --git a/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/odbc/OdbcProvider.java b/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/odbc/OdbcProvider.java index 51cbe16d..4468142e 100644 --- a/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/odbc/OdbcProvider.java +++ b/jdplus-main-base/jdplus-sql-base-parent/jdplus-sql-base-api/src/main/java/jdplus/sql/base/api/odbc/OdbcProvider.java @@ -16,6 +16,8 @@ */ package jdplus.sql.base.api.odbc; +import internal.sql.base.api.odbc.OdbcParam; +import internal.sql.base.api.odbc.legacy.LegacyOdbcMoniker; import jdplus.sql.base.api.HasSqlProperties; import jdplus.sql.base.api.SqlTableAsCubeResource; import jdplus.toolkit.base.api.timeseries.TsProvider; @@ -24,10 +26,8 @@ import jdplus.toolkit.base.tsp.stream.HasTsStream; import jdplus.toolkit.base.tsp.stream.TsStreamAsProvider; import jdplus.toolkit.base.tsp.util.FallbackDataMoniker; -import jdplus.toolkit.base.tsp.util.IOCacheFactoryLoader; import jdplus.toolkit.base.tsp.util.ResourcePool; -import internal.sql.base.api.odbc.OdbcParam; -import internal.sql.base.api.odbc.legacy.LegacyOdbcMoniker; +import jdplus.toolkit.base.tsp.util.ShortLivedCachingLoader; import nbbrd.design.DirectImpl; import nbbrd.service.ServiceProvider; import nbbrd.sql.jdbc.SqlConnectionSupplier; @@ -89,7 +89,7 @@ private static CubeConnection openConnection(DataSource key, HasSqlProperties pr SqlTableAsCubeResource sqlResource = SqlTableAsCubeResource.of(properties.getConnectionSupplier(), bean.getDsn(), bean.getTable(), toRoot(bean), toDataParams(bean), bean.getCube().getGathering(), bean.getCube().getLabel()); CubeConnection result = TableAsCubeConnection.of(sqlResource); - return BulkCubeConnection.of(result, bean.getCache(), IOCacheFactoryLoader.get()); + return BulkCubeConnection.of(result, bean.getCache(), ShortLivedCachingLoader.get()); } private static CubeId toRoot(OdbcBean bean) { diff --git a/jdplus-main-base/jdplus-sql-base-parent/pom.xml b/jdplus-main-base/jdplus-sql-base-parent/pom.xml index 4a4441b7..3c060c5e 100644 --- a/jdplus-main-base/jdplus-sql-base-parent/pom.xml +++ b/jdplus-main-base/jdplus-sql-base-parent/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-main-base - 3.0.2 + 3.1.0 jdplus-sql-base-parent diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/pom.xml b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/pom.xml index aa489435..22d458ef 100644 --- a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/pom.xml +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-text-base-parent - 3.0.2 + 3.1.0 jdplus-text-base-api diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/TxtDataDisplayName.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/TxtDataDisplayName.java index 2a29cb48..ca8cd5cf 100644 --- a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/TxtDataDisplayName.java +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/TxtDataDisplayName.java @@ -24,6 +24,7 @@ import jdplus.toolkit.base.tsp.DataSource; import jdplus.toolkit.base.tsp.HasDataDisplayName; import jdplus.toolkit.base.tsp.util.DataSourcePreconditions; +import org.checkerframework.checker.nullness.qual.NonNull; import java.util.Locale; import java.util.function.Function; @@ -39,14 +40,14 @@ public final class TxtDataDisplayName implements HasDataDisplayName { private final Function data; @Override - public String getDisplayName(DataSource dataSource) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSource dataSource) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSource); TxtBean bean = param.get(dataSource); return bean.getFile().getPath() + toString(bean.getGathering()); } @Override - public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSet); Integer index = param.getSeriesParam().get(dataSet); @@ -55,7 +56,7 @@ public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { } @Override - public String getDisplayNodeName(DataSet dataSet) { + public @NonNull String getDisplayNodeName(@NonNull DataSet dataSet) { return getDisplayName(dataSet); } diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/TxtLegacyMoniker.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/TxtLegacyMoniker.java index 6bb7745a..6186040b 100644 --- a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/TxtLegacyMoniker.java +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/TxtLegacyMoniker.java @@ -24,6 +24,7 @@ import jdplus.toolkit.base.tsp.HasDataMoniker; import jdplus.toolkit.base.tsp.legacy.LegacyFileId; import jdplus.toolkit.base.tsp.util.DataSourcePreconditions; +import org.checkerframework.checker.nullness.qual.NonNull; import java.io.File; import java.util.Optional; @@ -39,19 +40,19 @@ public final class TxtLegacyMoniker implements HasDataMoniker { private final TxtParam param; @Override - public TsMoniker toMoniker(DataSource dataSource) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSource dataSource) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSource); throw new IllegalArgumentException("Not supported yet."); } @Override - public TsMoniker toMoniker(DataSet dataSet) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSet); throw new IllegalArgumentException("Not supported yet."); } @Override - public Optional toDataSource(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSource(@NonNull TsMoniker moniker) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, moniker); LegacyFileId id = LegacyFileId.parse(moniker.getId()); @@ -59,7 +60,7 @@ public Optional toDataSource(TsMoniker moniker) throws IllegalArgume } @Override - public Optional toDataSet(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSet(@NonNull TsMoniker moniker) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, moniker); TxtLegacyId id = TxtLegacyId.parse(moniker.getId()); diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/XmlDataDisplayName.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/XmlDataDisplayName.java index 1b1fb600..8e86dcb9 100644 --- a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/XmlDataDisplayName.java +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/XmlDataDisplayName.java @@ -22,6 +22,7 @@ import jdplus.toolkit.base.tsp.DataSource; import jdplus.toolkit.base.tsp.HasDataDisplayName; import jdplus.toolkit.base.tsp.util.DataSourcePreconditions; +import org.checkerframework.checker.nullness.qual.NonNull; import java.util.List; import java.util.function.Function; @@ -37,14 +38,14 @@ public final class XmlDataDisplayName implements HasDataDisplayName { private final Function> resources; @Override - public String getDisplayName(DataSource dataSource) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSource dataSource) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSource); XmlBean bean = param.get(dataSource); return bean.getFile().getPath(); } @Override - public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSet); Integer collectionIndex = param.getCollectionParam().get(dataSet); Integer seriesIndex = param.getSeriesParam().get(dataSet); @@ -70,7 +71,7 @@ public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { } @Override - public String getDisplayNodeName(DataSet dataSet) { + public @NonNull String getDisplayNodeName(@NonNull DataSet dataSet) { DataSourcePreconditions.checkProvider(providerName, dataSet); Integer collectionIndex = param.getCollectionParam().get(dataSet); Integer seriesIndex = param.getSeriesParam().get(dataSet); diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/XmlLegacyMoniker.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/XmlLegacyMoniker.java index f7d00b1f..45ffd527 100644 --- a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/XmlLegacyMoniker.java +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/internal/text/base/api/XmlLegacyMoniker.java @@ -24,6 +24,7 @@ import jdplus.toolkit.base.tsp.HasDataMoniker; import jdplus.toolkit.base.tsp.legacy.LegacyFileId; import jdplus.toolkit.base.tsp.util.DataSourcePreconditions; +import org.checkerframework.checker.nullness.qual.NonNull; import java.io.File; import java.util.Optional; @@ -39,19 +40,19 @@ public final class XmlLegacyMoniker implements HasDataMoniker { private final XmlParam param; @Override - public TsMoniker toMoniker(DataSource dataSource) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSource dataSource) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSource); throw new IllegalArgumentException("Not supported yet."); } @Override - public TsMoniker toMoniker(DataSet dataSet) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSet); throw new IllegalArgumentException("Not supported yet."); } @Override - public Optional toDataSource(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSource(@NonNull TsMoniker moniker) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, moniker); LegacyFileId id = LegacyFileId.parse(moniker.getId()); @@ -59,7 +60,7 @@ public Optional toDataSource(TsMoniker moniker) throws IllegalArgume } @Override - public Optional toDataSet(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSet(@NonNull TsMoniker moniker) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, moniker); XmlLegacyId id = XmlLegacyId.parse(moniker.getId()); diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/jdplus/text/base/api/TxtProvider.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/jdplus/text/base/api/TxtProvider.java index 1d6509f4..b052b6d9 100644 --- a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/jdplus/text/base/api/TxtProvider.java +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/jdplus/text/base/api/TxtProvider.java @@ -18,7 +18,7 @@ @ServiceProvider(TsProvider.class) public final class TxtProvider implements FileLoader { - private static final String NAME = "Txt"; + public static final String NAME = "Txt"; @lombok.experimental.Delegate private final HasDataSourceMutableList mutableListSupport; diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/jdplus/text/base/api/XmlProvider.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/jdplus/text/base/api/XmlProvider.java index bc467bba..751ed31d 100644 --- a/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/jdplus/text/base/api/XmlProvider.java +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-text-base-api/src/main/java/jdplus/text/base/api/XmlProvider.java @@ -18,7 +18,7 @@ @ServiceProvider(TsProvider.class) public final class XmlProvider implements FileLoader { - private static final String NAME = "Xml"; + public static final String NAME = "Xml"; @lombok.experimental.Delegate private final HasDataSourceMutableList mutableListSupport; diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/pom.xml b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/pom.xml new file mode 100644 index 00000000..d13f0837 --- /dev/null +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + + eu.europa.ec.joinup.sat + jdplus-text-base-parent + 3.1.0 + + + jdplus-text-base-r + jar + + ${project.artifactId} + ${project.parent.artifactId} - ${project.artifactId} + ${project.parent.url} + + + + + eu.europa.ec.joinup.sat + jdplus-text-base-api + ${project.version} + + + eu.europa.ec.joinup.sat + jdplus-toolkit-base-r + ${project.version} + + + \ No newline at end of file diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/jdplus/text/base/r/TxtFiles.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/jdplus/text/base/r/TxtFiles.java new file mode 100644 index 00000000..ee6a9229 --- /dev/null +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/jdplus/text/base/r/TxtFiles.java @@ -0,0 +1,170 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.text.base.r; + +import java.io.File; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import jdplus.text.base.api.TxtBean; +import jdplus.text.base.api.TxtProvider; +import jdplus.toolkit.base.api.timeseries.Ts; +import jdplus.toolkit.base.api.timeseries.TsCollection; +import jdplus.toolkit.base.api.timeseries.TsFactory; +import jdplus.toolkit.base.api.timeseries.TsInformationType; +import jdplus.toolkit.base.api.timeseries.TsMoniker; +import jdplus.toolkit.base.api.timeseries.util.ObsGathering; +import jdplus.toolkit.base.tsp.DataSet; +import jdplus.toolkit.base.tsp.DataSource; +import jdplus.toolkit.base.tsp.util.ObsFormat; + +/** + * + * @author palatej + */ +@lombok.experimental.UtilityClass +public class TxtFiles { + + private final TxtProvider PROVIDER = new TxtProvider(); + + TxtProvider currentProvider() { + return (TxtProvider) TsFactory.getDefault().getProvider(TxtProvider.NAME).orElse(null); + } + + public String changeFile(String id, String nfile, String ofile) { + Optional set = PROVIDER.toDataSet(TsMoniker.of(TxtProvider.NAME, id)); + Optional m = set.map(d -> { + TxtBean bean = PROVIDER.decodeBean(d.getDataSource()); + if (ofile.isBlank() || bean.getFile().getName().equals(ofile)) { + bean.setFile(new File(nfile)); + DataSource src = PROVIDER.encodeBean(bean); + DataSet nd = d.toBuilder() + .dataSource(src) + .build(); + return PROVIDER.toMoniker(nd).getId(); + } else { + return id; + } + }); + return m.orElse(id); + } + + public DataSource source(String file, ObsFormat obsFormat, ObsGathering obsGathering, String cs, String delimiter, String txtqualifier, boolean headers, int skiplines) { + TxtBean bean = new TxtBean(); + bean.setFile(new File(file)); + if (cs != null && cs.length() > 0) { + bean.setCharset(Charset.forName(cs)); + } + if (delimiter != null) { + bean.setDelimiter(TxtBean.Delimiter.valueOf(delimiter)); + } + if (txtqualifier != null) { + bean.setTextQualifier(TxtBean.TextQualifier.valueOf(txtqualifier)); + } + if (obsFormat != null) { + bean.setFormat(obsFormat); + } + if (obsGathering != null) { + bean.setGathering(obsGathering); + } + bean.setHeaders(headers); + bean.setSkipLines(skiplines); + return PROVIDER.encodeBean(bean); + } + + public String[] series(DataSource source) throws Exception { + TxtProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new Exception("TxtProvider is not available"); + } + try { + currentProvider.open(source); + List all = currentProvider.children(source); + return all.stream().map(s -> currentProvider.getDisplayNodeName(s)).toArray(String[]::new); + } finally { + currentProvider.close(source); + } + } + + public Ts series(DataSource source, int series) throws Exception { + TxtProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new Exception("TxtProvider is not available"); + } + try { + currentProvider.open(source); + List all = currentProvider.children(source); + if (series > all.size()) { + throw new IllegalArgumentException("Invalid sheet"); + } + DataSet s = all.get(series - 1); + TsMoniker moniker = currentProvider.toMoniker(s); + return currentProvider.getTs(moniker, TsInformationType.All); + } finally { + currentProvider.close(source); + } + } + + public TsCollection collection(DataSource source) throws Exception { + TxtProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new Exception("TxtProvider is not available"); + } + try { + currentProvider.open(source); + TsMoniker moniker = currentProvider.toMoniker(source); + return currentProvider.getTsCollection(moniker, TsInformationType.All); + } finally { + currentProvider.close(source); + } + } + + public void setPaths(String[] paths) throws Exception { + TxtProvider provider = currentProvider(); + if (provider == null) { + throw new Exception("TxtProvider is not available"); + } + File[] files = Arrays.stream(paths).map(p -> new File(p)).toArray(n -> new File[n]); + provider.setPaths(files); + } + + public DataSet decode(String id) { + Optional set = PROVIDER.toDataSet(TsMoniker.of(TxtProvider.NAME, id)); + return set.orElse(null); + } + + public String encode(DataSet set) { + return PROVIDER.toMoniker(set).getId(); + } + + public TxtBean sourceOf(DataSet set) { + return PROVIDER.decodeBean(set.getDataSource()); + } + + public DataSet sheetDataSet(DataSource source) { + return DataSet.builder(source, DataSet.Kind.COLLECTION) + .build(); + } + + public DataSet seriesDataSet(DataSource source, int series) { + return DataSet.builder(source, DataSet.Kind.SERIES) + .parameter("seriesIndex", Integer.toString(series-1)) + .build(); + } +} diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/jdplus/text/base/r/Utility.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/jdplus/text/base/r/Utility.java new file mode 100644 index 00000000..aa3b2f22 --- /dev/null +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/jdplus/text/base/r/Utility.java @@ -0,0 +1,63 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.text.base.r; + +import java.util.Locale; +import jdplus.text.base.api.TxtProvider; +import jdplus.text.base.api.XmlProvider; +import jdplus.toolkit.base.r.util.Providers; +import jdplus.toolkit.base.tsp.util.ObsFormat; + +/** + * + * @author palatej + */ +@lombok.experimental.UtilityClass +public class Utility { + + public void updateTsFactory() { + TxtProvider txtProvider = TxtFiles.currentProvider(); + XmlProvider xmlProvider = XmlFiles.currentProvider(); + if (txtProvider == null) { + if (xmlProvider == null) { + Providers.updateTsFactory(new TxtProvider(), new XmlProvider()); + } else { + Providers.updateTsFactory(new TxtProvider()); + } + } else { + if (xmlProvider == null) { + Providers.updateTsFactory(new XmlProvider()); + } + } + } + + public ObsFormat obsFormat(String locale, String dateFmt, String numberFmt, boolean ignoreNumberGrouping) { + ObsFormat.Builder builder = ObsFormat.builder().ignoreNumberGrouping(ignoreNumberGrouping); + if (locale.length()>0) { + builder.locale(Locale.forLanguageTag(locale)); + } + if (dateFmt.length()>0) { + builder.dateTimePattern(dateFmt); + } + if (numberFmt.length()>0) { + builder.numberPattern(numberFmt); + } + return builder.build(); + + } + +} diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/jdplus/text/base/r/XmlFiles.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/jdplus/text/base/r/XmlFiles.java new file mode 100644 index 00000000..000002fe --- /dev/null +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/jdplus/text/base/r/XmlFiles.java @@ -0,0 +1,212 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.text.base.r; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import jdplus.text.base.api.XmlBean; +import jdplus.text.base.api.XmlProvider; +import jdplus.toolkit.base.api.timeseries.Ts; +import jdplus.toolkit.base.api.timeseries.TsCollection; +import jdplus.toolkit.base.api.timeseries.TsData; +import jdplus.toolkit.base.api.timeseries.TsFactory; +import jdplus.toolkit.base.api.timeseries.TsInformationType; +import jdplus.toolkit.base.api.timeseries.TsMoniker; +import jdplus.toolkit.base.tsp.DataSet; +import jdplus.toolkit.base.tsp.DataSource; + +/** + * + * @author palatej + */ +@lombok.experimental.UtilityClass +public class XmlFiles { + + private final XmlProvider PROVIDER = new XmlProvider(); + + static XmlProvider currentProvider() { + return (XmlProvider) TsFactory.getDefault().getProvider(XmlProvider.NAME).orElse(null); + } + + public String changeFile(String id, String nfile, String ofile) { + Optional set = PROVIDER.toDataSet(TsMoniker.of(XmlProvider.NAME, id)); + Optional m = set.map(d -> { + XmlBean bean = PROVIDER.decodeBean(d.getDataSource()); + if (ofile.isBlank() || bean.getFile().getName().equals(ofile)) { + bean.setFile(new File(nfile)); + DataSource src = PROVIDER.encodeBean(bean); + DataSet nd = d.toBuilder() + .dataSource(src) + .build(); + return PROVIDER.toMoniker(nd).getId(); + } else { + return id; + } + }); + return m.orElse(id); + } + + public DataSource source(String file, String cs) { + XmlBean bean = new XmlBean(); + bean.setFile(new File(file)); + if (!cs.isEmpty()) { + Charset charset = Charset.forName(cs); + bean.setCharset(charset); + } + return PROVIDER.encodeBean(bean); + } + + public String[] sheets(DataSource source) throws Exception { + XmlProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new Exception("XmlProvider is not available"); + } + try { + currentProvider.open(source); + List sheets = currentProvider.children(source); + return sheets.stream().map(s -> currentProvider.getDisplayNodeName(s)).toArray(String[]::new); + } finally { + currentProvider.close(source); + } + } + + public String[] series(DataSource source, int sheet) throws Exception { + XmlProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new Exception("XmlProvider is not available"); + } + try { + currentProvider.open(source); + List sheets = currentProvider.children(source); + if (sheet > sheets.size()) { + throw new IllegalArgumentException("Invalid sheet"); + } + DataSet ds = sheets.get(sheet - 1); + List all = currentProvider.children(ds); + return all.stream().map(s -> currentProvider.getDisplayNodeName(s)).toArray(String[]::new); + } finally { + currentProvider.close(source); + } + } + + public Ts series(DataSource source, int sheet, int series, boolean fullName) throws Exception { + XmlProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new Exception("XmlProvider is not available"); + } + try { + currentProvider.open(source); + List sheets = currentProvider.children(source); + if (sheet > sheets.size()) { + throw new IllegalArgumentException("Invalid sheet"); + } + DataSet ds = sheets.get(sheet - 1); + List all = currentProvider.children(ds); + if (series > all.size()) { + throw new IllegalArgumentException("Invalid sheet"); + } + DataSet s = all.get(series - 1); + TsMoniker moniker = currentProvider.toMoniker(s); + return currentProvider.getTs(moniker, TsInformationType.All).withName(fullName ? currentProvider.getDisplayName(s) : currentProvider.getDisplayNodeName(s)); + } finally { + currentProvider.close(source); + } + } + + public TsCollection collection(DataSource source, int sheet, boolean fullNames) throws Exception { + XmlProvider currentProvider = currentProvider(); + if (currentProvider == null) { + throw new Exception("XmlProvider is not available"); + } + try { + currentProvider.open(source); + List sheets = currentProvider.children(source); + if (sheet > sheets.size()) { + throw new IllegalArgumentException("Invalid sheet"); + } + DataSet ds = sheets.get(sheet - 1); + TsMoniker moniker = currentProvider.toMoniker(ds); + if (fullNames) { + return currentProvider.getTsCollection(moniker, TsInformationType.All).withName(currentProvider.getDisplayName(ds)); + } else { + List schildren = currentProvider.children(ds); + List all = schildren.stream().map(c -> of(currentProvider, c)).toList(); + return TsCollection.builder() + .name(currentProvider.getDisplayName(ds)) + .moniker(moniker) + .items(all) + .build(); + } + } finally { + currentProvider.close(source); + } + } + + private Ts of(XmlProvider provider, DataSet c) { + TsMoniker moniker = provider.toMoniker(c); + try { + return provider.getTs(moniker, TsInformationType.All) + .withName(provider.getDisplayNodeName(c)); + } catch (IOException ex) { + return Ts.builder() + .moniker(moniker) + .data(TsData.empty("Unavailable")) + .build(); + + } + } + + public void setPaths(String[] paths) throws Exception { + XmlProvider provider = currentProvider(); + if (provider == null) { + throw new Exception("XmlProvider is not available"); + } + File[] files = Arrays.stream(paths).map(p -> new File(p)).toArray(n -> new File[n]); + provider.setPaths(files); + } + + public DataSet decode(String id) { + Optional set = PROVIDER.toDataSet(TsMoniker.of(XmlProvider.NAME, id)); + return set.orElse(null); + } + + public String encode(DataSet set) { + return PROVIDER.toMoniker(set).getId(); + } + + public XmlBean sourceOf(DataSet set) { + return PROVIDER.decodeBean(set.getDataSource()); + } + + public DataSet seriesDataSet(DataSource source, int collectionIndex, int seriesIndex) { + return DataSet.builder(source, DataSet.Kind.SERIES) + .parameter("collectionIndex", Integer.toString(collectionIndex - 1)) + .parameter("seriesIndex", Integer.toString(seriesIndex - 1)) + .build(); + } + + public DataSet sheetDataSet(DataSource source, String sheetName) { + return DataSet.builder(source, DataSet.Kind.COLLECTION) + .parameter("sheetName", sheetName) + .build(); + } +} diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/module-info.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/module-info.java new file mode 100644 index 00000000..26fdbc83 --- /dev/null +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/java/module-info.java @@ -0,0 +1,16 @@ + +module jdplus.text.base.r { + + requires static lombok; + requires static nbbrd.design; + requires static nbbrd.service; + requires static org.checkerframework.checker.qual; + + requires jdplus.toolkit.base.api; + requires jdplus.toolkit.base.core; + requires jdplus.toolkit.base.tsp; + requires jdplus.text.base.api; + requires jdplus.toolkit.base.r; + + exports jdplus.text.base.r; +} \ No newline at end of file diff --git a/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/javadoc/EmptyJavaDoc.java b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/javadoc/EmptyJavaDoc.java new file mode 100644 index 00000000..530579d4 --- /dev/null +++ b/jdplus-main-base/jdplus-text-base-parent/jdplus-txt-base-r/src/main/javadoc/EmptyJavaDoc.java @@ -0,0 +1,6 @@ +/** + * Workaround for JavaDoc issues with Lombok. + */ +public class EmptyJavaDoc { + +} \ No newline at end of file diff --git a/jdplus-main-base/jdplus-text-base-parent/pom.xml b/jdplus-main-base/jdplus-text-base-parent/pom.xml index 1b7019c0..1c5cbb25 100644 --- a/jdplus-main-base/jdplus-text-base-parent/pom.xml +++ b/jdplus-main-base/jdplus-text-base-parent/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-main-base - 3.0.2 + 3.1.0 jdplus-text-base-parent @@ -17,5 +17,6 @@ jdplus-text-base-api + jdplus-txt-base-r \ No newline at end of file diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/pom.xml b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/pom.xml index f5a03146..2ea24132 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/pom.xml +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-toolkit-base-parent - 3.0.2 + 3.1.0 jdplus-toolkit-base-api diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/ContinuousDistribution.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/ContinuousDistribution.java index b065e6e8..86c72bba 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/ContinuousDistribution.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/ContinuousDistribution.java @@ -28,6 +28,28 @@ @Development(status = Development.Status.Release) public interface ContinuousDistribution extends Distribution { + /** + * Returns the lower or upper tail probability of x + * + * @param x The value for which the probability is returned + * @param pt The type of requested probability: lower or upper tail + * @return The requested probability (double in [0, 1]). + * @throws DStatException + */ + double getProbability(double x, ProbabilityType pt) throws DStatException; + + /** + * Returns the value x that has probability p for the given distribution and + * probability type + * + * @param p The probability + * @param pt The probability type + * @return The value x such that P(X < x or X > x or X = x) = p + * @throws DStatException + */ + double getProbabilityInverse(double p, ProbabilityType pt) + throws DStatException; + /** * Returns the value of x for the density function describing the * distribution @@ -76,5 +98,13 @@ default double getProbabilityForInterval(double x, double y) throws DStatExcepti */ double getRightBound(); + /** + * Generates a random value from the given distribution + * + * @param rng the random number generator used to create the value + * @return The random number + * @throws DStatException + */ + double random(RandomNumberGenerator rng) throws DStatException; } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/DiscreteDistribution.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/DiscreteDistribution.java index 3e300c23..58beb833 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/DiscreteDistribution.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/DiscreteDistribution.java @@ -25,6 +25,15 @@ */ @Development(status = Development.Status.Release) public interface DiscreteDistribution extends Distribution { + + /** + * Returns the lower or upper tail probability of x + * + * @param x The value for which the probability is returned + * @return The requested probability (double in [0, 1]). + * @throws DStatException + */ + double getProbability(long x) throws DStatException; /** * Returns the left bound (if any). Throws an exception otherwise * @@ -38,4 +47,14 @@ public interface DiscreteDistribution extends Distribution { * @return */ long getRightBound(); + + /** + * Generates a random value from the given distribution + * + * @param rng the random number generator used to create the value + * @return The random number + * @throws DStatException + */ + long random(RandomNumberGenerator rng) throws DStatException; + } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/Distribution.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/Distribution.java index a2d8f0f9..5ef4e3b0 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/Distribution.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/dstats/Distribution.java @@ -16,7 +16,6 @@ */ package jdplus.toolkit.base.api.dstats; -import jdplus.toolkit.base.api.stats.ProbabilityType; import nbbrd.design.Development; /** @@ -47,28 +46,6 @@ public interface Distribution { */ double getExpectation() throws DStatException; - /** - * Returns the lower or upper tail probability of x - * - * @param x The value for which the probability is returned - * @param pt The type of requested probability: lower or upper tail - * @return The requested probability (double in [0, 1]). - * @throws DStatException - */ - double getProbability(double x, ProbabilityType pt) throws DStatException; - - /** - * Returns the value x that has probability p for the given distribution and - * probability type - * - * @param p The probability - * @param pt The probability type - * @return The value x such that P(X < x or X > x or X = x) = p - * @throws DStatException - */ - double getProbabilityInverse(double p, ProbabilityType pt) - throws DStatException; - /** * Returns the second moment of the distribution * @@ -99,14 +76,6 @@ public interface Distribution { */ boolean isSymmetrical(); - /** - * Generates a random value from the given distribution - * - * @param rng the random number generator used to create the value - * @return The random number - * @throws DStatException - */ - double random(RandomNumberGenerator rng) throws DStatException; } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/AsymmetricFilterOption.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/AsymmetricFilterOption.java new file mode 100644 index 00000000..0444ec4b --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/AsymmetricFilterOption.java @@ -0,0 +1,27 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.base.api.math.linearfilters; + +/** + * + * @author palatej + */ +public enum AsymmetricFilterOption { + Direct, + CutAndNormalize, + MMSRE +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/FilterSpec.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/FilterSpec.java new file mode 100644 index 00000000..aeaa0d53 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/FilterSpec.java @@ -0,0 +1,25 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.base.api.math.linearfilters; + +/** + * + * @author palatej + */ +public interface FilterSpec { + +} diff --git a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/jdplus/sa/base/api/modelling/SaRegArima.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/HendersonSpec.java similarity index 56% rename from jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/jdplus/sa/base/api/modelling/SaRegArima.java rename to jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/HendersonSpec.java index eb231faf..ee0d9b56 100644 --- a/jdplus-main-base/jdplus-sa-base-parent/jdplus-sa-base-api/src/main/java/jdplus/sa/base/api/modelling/SaRegArima.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/HendersonSpec.java @@ -1,40 +1,40 @@ /* - * Copyright 2020 National Bank of Belgium - * + * Copyright 2023 National Bank of Belgium + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved * by the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: - * + * * https://joinup.ec.europa.eu/software/page/eupl - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. */ -package jdplus.sa.base.api.modelling; - -import jdplus.toolkit.base.api.arima.SarimaSpec; -import jdplus.toolkit.base.api.timeseries.TsData; -import jdplus.toolkit.base.api.timeseries.calendars.LengthOfPeriodType; -import jdplus.toolkit.base.api.timeseries.regression.Variable; +package jdplus.toolkit.base.api.math.linearfilters; /** * * @author palatej */ @lombok.Value -public class SaRegArima { - - - private TsData series; - private boolean log; - private LengthOfPeriodType adjust; - - private Variable[] regression; - - private SarimaSpec stochasticComponent; +@lombok.AllArgsConstructor +public class HendersonSpec implements FilterSpec { + + int filterHorizon; + double leftIcRatio, rightIcRatio; + public HendersonSpec(int horizon, double icRatio){ + this.filterHorizon=horizon; + this.leftIcRatio=icRatio; + this.rightIcRatio=icRatio; + } + + public boolean isSymmetric() { + return leftIcRatio == rightIcRatio; + } + } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/KernelOption.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/KernelOption.java new file mode 100644 index 00000000..aad1a943 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/KernelOption.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 National Bank of Belgium. + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jdplus.toolkit.base.api.math.linearfilters; + +/** + * + * @author Jean Palate + */ +public enum KernelOption { + Uniform, + Triangular, + Epanechnikov, + BiWeight, + TriWeight, + Henderson, + TriCube +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/LocalPolynomialFilterSpec.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/LocalPolynomialFilterSpec.java new file mode 100644 index 00000000..8fe290e1 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/LocalPolynomialFilterSpec.java @@ -0,0 +1,121 @@ +package jdplus.toolkit.base.api.math.linearfilters; + +import java.util.Arrays; +import jdplus.toolkit.base.api.data.Doubles; + +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +/** + * + * @author Jean Palate + */ +@lombok.Value +@lombok.Builder(builderClassName = "Builder", toBuilder = true) +public class LocalPolynomialFilterSpec implements FilterSpec { + + public static final double DEF_SLOPE = 2 / (Math.sqrt(Math.PI) * 3.5); + + public static final LocalPolynomialFilterSpec DEF_TREND_SPEC = builder().build(); + public static final LocalPolynomialFilterSpec DEF_SEAS_SPEC = builder() + .filterHorizon(2) + .polynomialDegree(0) + .asymmetricPolynomialDegree(0) + .linearModelCoefficients(Doubles.EMPTYARRAY) + .build(); + + public static LocalPolynomialFilterSpec defaultSeasonalSpec(int horizon, KernelOption kernel) { + return builder() + .filterHorizon(horizon) + .kernel(kernel) + .polynomialDegree(0) + .asymmetricPolynomialDegree(0) + .linearModelCoefficients(Doubles.EMPTYARRAY) + .build(); + } + + /** + * Horizon of the symmetric filter (defined in [-filterHorizon, + * +filterHorizon] The full length of the filter is 1 + 2*filterHorizon + */ + private int filterHorizon; + /** + * Defines the kernel used in the filter + */ + private KernelOption kernel; + /** + * Degree of the local polynomial + */ + private int polynomialDegree; + /** + * Type of the asymmetric filter used to compute the extremities of the + * series + */ + private AsymmetricFilterOption asymmetricFilters; + /** + * Only used with MMSRE filters Max degree of the polynomials preserved by + * the asymmetric filters + */ + private int asymmetricPolynomialDegree; + /** + * Only used with MMSRE filters Coefficients of the extrapolating + * polynomial. See Luati-Proietti for more details + */ + private double[] leftLinearModelCoefficients; + /** + * Only used with MMSRE filters Coefficients of the extrapolating + * polynomial. See Luati-Proietti for more details + */ + private double[] rightLinearModelCoefficients; + /** + * Only used with MMSRE filters and with timeliness criterion + */ + private double timelinessWeight; + /** + * Only used with MMSRE filters and with timeliness criterion. Upper + * threshold of the periods considered in the timeliness criterion (in + * radians) Default is pi/8 (cycles of more than 4 years) + */ + private double passBand; + + public static Builder builder() { + return new Builder() + .filterHorizon(6) + .kernel(KernelOption.Henderson) + .polynomialDegree(2) + .asymmetricFilters(AsymmetricFilterOption.MMSRE) + .asymmetricPolynomialDegree(0) + .linearModelCoefficients(DEF_SLOPE) + .timelinessWeight(0) + .passBand(Math.PI / 8); + + } + + public static class Builder { + + public Builder linearModelCoefficients(double... coefs) { + leftLinearModelCoefficients = coefs; + rightLinearModelCoefficients = coefs; + return this; + } + + public Builder leftLinearModelCoefficients(double... coefs) { + leftLinearModelCoefficients = coefs; + return this; + } + + public Builder rightLinearModelCoefficients(double... coefs) { + rightLinearModelCoefficients = coefs; + return this; + } + } + + public boolean isSymmetric() { + return asymmetricFilters == AsymmetricFilterOption.CutAndNormalize + || asymmetricFilters == AsymmetricFilterOption.Direct + || Arrays.equals(leftLinearModelCoefficients, rightLinearModelCoefficients); + } + +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/UserDefinedFilterSpec.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/UserDefinedFilterSpec.java new file mode 100644 index 00000000..172de733 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/UserDefinedFilterSpec.java @@ -0,0 +1,30 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.base.api.math.linearfilters; + +import jdplus.toolkit.base.api.data.DoubleSeq; +import jdplus.toolkit.base.api.math.matrices.Matrix; + +/** + * + * @author palatej + */ +@lombok.Value +public class UserDefinedFilterSpec implements FilterSpec{ + DoubleSeq centralFilter; + Matrix lFilters, uFilters; +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/UserDefinedSymmetricFilterSpec.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/UserDefinedSymmetricFilterSpec.java new file mode 100644 index 00000000..4453edbc --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/math/linearfilters/UserDefinedSymmetricFilterSpec.java @@ -0,0 +1,30 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.base.api.math.linearfilters; + +import jdplus.toolkit.base.api.data.DoubleSeq; +import jdplus.toolkit.base.api.math.matrices.Matrix; + +/** + * + * @author palatej + */ +@lombok.Value +public class UserDefinedSymmetricFilterSpec implements FilterSpec{ + DoubleSeq centralFilter; + Matrix endPointsFilters; +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/EstimateSpec.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/EstimateSpec.java index adfae195..dd8e7a34 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/EstimateSpec.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/EstimateSpec.java @@ -45,5 +45,9 @@ public static Builder builder() { .precision(EPS) .approximateHessian(DEF_APP_HESSIAN); } + + public boolean isDefault(){ + return this.equals(DEFAULT); + } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/HolidaysSpec.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/HolidaysSpec.java index 5e5d670f..33f018b9 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/HolidaysSpec.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/HolidaysSpec.java @@ -31,12 +31,16 @@ @lombok.Builder(toBuilder = true) public final class HolidaysSpec { + public static HolidaysOption DEF_OPTION=HolidaysOption.Skip; + public final static HolidaysSpec DEFAULT_UNUSED = HolidaysSpec.builder().build(); private String holidays; private HolidaysOption holidaysOption; private boolean single; private int[] nonWorkingDays; + + private boolean test; private Parameter[] coefficients; @@ -50,7 +54,7 @@ public boolean hasFixedCoefficients() { public static Builder builder() { return new Builder() - .holidaysOption(HolidaysOption.Skip) + .holidaysOption(DEF_OPTION) .single(false) .nonWorkingDays(HolidaysVariable.NONWORKING_WE); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/SeriesSpec.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/SeriesSpec.java index 1112b3c1..6969b74c 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/SeriesSpec.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/SeriesSpec.java @@ -39,4 +39,8 @@ public static Builder builder(){ return new Builder().cleaning(DataCleaning.NONE).span(TimeSelector.all()); } + public boolean isDefault(){ + return this.equals(DEFAULT); + } + } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/TransformSpec.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/TransformSpec.java index d750f13f..a7f17d83 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/TransformSpec.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/modelling/highfreq/TransformSpec.java @@ -25,17 +25,24 @@ */ @Development(status = Development.Status.Beta) @lombok.Value -@lombok.Builder(toBuilder = true, builderClassName="Builder") +@lombok.Builder(toBuilder = true, builderClassName = "Builder") public class TransformSpec { - - public static final TransformSpec DEFAULT=builder().build(); + + public static final TransformSpec DEFAULT = builder().build(), + DEF_AUTO = TransformSpec.builder() + .function(TransformationType.Auto) + .build(); @lombok.NonNull private TransformationType function; private double aicDiff; - - public static Builder builder(){ + + public static Builder builder() { return new Builder().function(TransformationType.None); } - + + public boolean isDefault() { + return this.equals(DEFAULT); + } + } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/processing/Output.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/processing/Output.java index 47f9c347..3b082bff 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/processing/Output.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/processing/Output.java @@ -18,14 +18,16 @@ package jdplus.toolkit.base.api.processing; import nbbrd.design.Development; +import nbbrd.design.NotThreadSafe; /** * Generic interface that describes the making of output from a processing. * - * @author Jean Palate * @param + * @author Jean Palate */ +@NotThreadSafe @Development(status = Development.Status.Alpha) public interface Output { @@ -48,14 +50,14 @@ public interface Output { * * @param document The considered document */ - void process(D document)throws Exception; + void process(D document) throws Exception; /** * Starts the processing of the item identified by the given id; * * @param context */ - void start(Object context)throws Exception; + void start(Object context) throws Exception; /** * Finishes the processing of the item identified by the given id; @@ -63,5 +65,5 @@ public interface Output { * @param context * @throws java.lang.Exception */ - void end(Object context)throws Exception; + void end(Object context) throws Exception; } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/AbstractTsDocument.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/AbstractTsDocument.java index aea8e6c2..a3d2b75e 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/AbstractTsDocument.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/AbstractTsDocument.java @@ -39,6 +39,8 @@ public abstract class AbstractTsDocument, HasEmptyCause { @lombok.NonNull private TsInformationType type; + @lombok.With @lombok.NonNull private String name; @@ -80,6 +81,12 @@ public static Builder builder() { return builder().item(item).build(); } + @StaticFactoryMethod + public static @NonNull TsCollection ofName(@NonNull String name) { + Objects.requireNonNull(name); + return builder().name(name).build(); + } + public static @NonNull Collector toTsCollection() { return Collectors.collectingAndThen(Collectors.toList(), TsCollection::of); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsData.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsData.java index fd341b33..ef87f268 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsData.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsData.java @@ -516,6 +516,9 @@ public static TsData update(final TsData start, final TsData end) { if (end == null || end.isEmpty()) { return start; } + if (start == null || start.isEmpty()) { + return end; + } TsDomain ldom = start.getDomain(), rdom = end.getDomain(); TsDomain udom = ldom.union(rdom); if (udom == null) { @@ -524,10 +527,13 @@ public static TsData update(final TsData start, final TsData end) { TsPeriod pstart = start.getStart(), pend = end.getStart(), punion = udom.getStartPeriod(); int n = udom.getLength(); double[] data = new double[n]; - int l0 = pstart.until(punion), l1 = start.getEnd().until(punion), r0 = pend.until(punion); + int l0 = punion.until(pstart), l1 = punion.until(start.getEnd()), r0 = punion.until(pend), r1 = punion.until(end.getEnd()); for (int i = l1; i < r0; ++i) { data[i] = Double.NaN; } + for (int i = r1; i < l0; ++i) { + data[i] = Double.NaN; + } start.getValues().copyTo(data, l0); end.getValues().copyTo(data, r0); return TsData.ofInternal(punion, data); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsDataTable.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsDataTable.java index 30b718d8..060a5a90 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsDataTable.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsDataTable.java @@ -16,12 +16,14 @@ */ package jdplus.toolkit.base.api.timeseries; +import jdplus.toolkit.base.api.math.matrices.Matrix; import jdplus.toolkit.base.api.util.Collections2; -import jdplus.toolkit.base.api.util.List2; import jdplus.toolkit.base.api.util.function.BiIntPredicate; import lombok.AccessLevel; +import lombok.NonNull; +import nbbrd.design.StaticFactoryMethod; +import nbbrd.design.VisibleForTesting; import org.checkerframework.checker.index.qual.NonNegative; -import org.checkerframework.checker.nullness.qual.NonNull; import java.time.LocalDateTime; import java.util.Iterator; @@ -35,6 +37,7 @@ /** * @author Philippe Charles */ +@lombok.Getter @lombok.AllArgsConstructor(access = AccessLevel.PRIVATE) public final class TsDataTable { @@ -46,33 +49,27 @@ public enum ValueStatus { PRESENT, UNUSED, BEFORE, AFTER, EMPTY } - @NonNull - public static TsDataTable of(@NonNull Iterable col, @NonNull Function toData) { - TsDomain domain = computeDomain(Collections2.streamOf(col).map(toData).map(TsData::getDomain).filter(o -> !o.isEmpty()).iterator()); - return new TsDataTable(domain, Collections2.streamOf(col).map(toData).collect(List2.toUnmodifiableList())); + @StaticFactoryMethod + public static @NonNull TsDataTable of(@NonNull Iterable col, @NonNull Function toData) { + TsDomain domain = computeDomain(Collections2.streamOf(col).map(toData).filter(Objects::nonNull).map(TsData::getDomain).filter(o -> !o.isEmpty()).iterator()); + return new TsDataTable(domain, Collections2.streamOf(col).map(toData).toList()); } - @NonNull - public static TsDataTable of(@NonNull Iterable col) { + @StaticFactoryMethod + public static @NonNull TsDataTable of(@NonNull Iterable col) { return of(col, Function.identity()); } - @lombok.NonNull - @lombok.Getter - private final TsDomain domain; + private final @NonNull TsDomain domain; - @lombok.NonNull - @lombok.Getter - private final List data; + private final @NonNull List data; - @NonNull - public Cursor cursor(@NonNull DistributionType distribution) { + public @NonNull Cursor cursor(@NonNull DistributionType distribution) { Objects.requireNonNull(distribution); return cursor(i -> distribution); } - @NonNull - public Cursor cursor(@NonNull IntFunction distribution) { + public @NonNull Cursor cursor(@NonNull IntFunction distribution) { Objects.requireNonNull(distribution); return new Cursor(getDistributors(data, distribution)); } @@ -164,28 +161,24 @@ private static List getDistributors(List data, IntFuncti } private static BiIntPredicate getDistributor(DistributionType type) { - switch (type) { - case FIRST: - return (pos, size) -> pos % size == 0; - case LAST: - return (pos, size) -> pos % size == size - 1; - case MIDDLE: - return (pos, size) -> pos % size == size / 2; - default: - throw new RuntimeException(); - } + return switch (type) { + case FIRST -> (pos, size) -> pos % size == 0; + case LAST -> (pos, size) -> pos % size == size - 1; + case MIDDLE -> (pos, size) -> pos % size == size / 2; + }; } + @VisibleForTesting static TsDomain computeDomain(Iterator domains) { if (!domains.hasNext()) { return TsDomain.DEFAULT_EMPTY; } TsDomain o = domains.next(); - TsUnit lowestUnit = o.getTsUnit(); LocalDateTime minDate = o.start(); LocalDateTime maxDate = o.end(); + LocalDateTime epoch = o.getStartPeriod().getEpoch(); while (domains.hasNext()) { o = domains.next(); @@ -197,11 +190,16 @@ static TsDomain computeDomain(Iterator domains) { if (maxDate.isBefore(o.end())) { maxDate = o.end(); } + LocalDateTime cepoch = o.getStartPeriod().getEpoch(); + if (!cepoch.equals(epoch)) { + epoch = TsPeriod.DEFAULT_EPOCH; + } } - TsPeriod startPeriod = TsPeriod.of(lowestUnit, minDate); - TsPeriod endPeriod = TsPeriod.of(lowestUnit, maxDate); - // FIXME: default epoch? + TsPeriod startPeriod = TsPeriod.make(epoch, lowestUnit, minDate); + TsPeriod endPeriod = TsPeriod.make(epoch, lowestUnit, maxDate); + // default epoch if we can't find a common epoch. Should be improved + // FIXME return TsDomain.of(startPeriod, startPeriod.until(endPeriod)); } @@ -225,4 +223,27 @@ public String toString() { } return builder.toString(); } + + public Matrix toMatrix() { + return toMatrix(DistributionType.LAST); + } + + public Matrix toMatrix(DistributionType type) { + + int nr = domain.length(), nc = data.size(); + Cursor cursor = this.cursor(type); + double[] m = new double[nr * nc]; + for (int row = 0, j0 = 0; row < nr; ++row, ++j0) { + for (int col = 0, j = j0; col < nc; ++col, j += nr) { + cursor.moveTo(row, col); + if (cursor.getStatus() == ValueStatus.PRESENT) { + m[j] = cursor.getValue(); + } else { + m[j] = Double.NaN; + } + + } + } + return Matrix.of(m, nr, nc); + } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsDocument.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsDocument.java index 53edcec5..52364319 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsDocument.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsDocument.java @@ -30,6 +30,24 @@ public interface TsDocument e void setAll(S spec, Ts input, R result); + boolean isLocked(); + + void setLocked(boolean locked); + + default boolean isFrozen() { + synchronized (this) { + Ts s = getInput(); + if (s == null) { + return false; + } + return s.isFrozen(); + } + } + + void refreshTs(TsFactory factory, TsInformationType type); + + void freeze(); + @Override R getResult(); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsPeriod.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsPeriod.java index 5ea87fa1..6137171a 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsPeriod.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/timeseries/TsPeriod.java @@ -220,7 +220,7 @@ public static TsPeriod yearly(int year) { /** * Creates a quarterly period * - * @param year Year of the period + * @param year Year of the period * @param quarter Quarter of the period (in 1-4) * @return */ @@ -231,7 +231,7 @@ public static TsPeriod quarterly(int year, int quarter) { /** * Creates a monthly period * - * @param year Year of the period + * @param year Year of the period * @param month Month of the period (in 1-12) * @return */ @@ -242,8 +242,8 @@ public static TsPeriod monthly(int year, int month) { /** * Creates a period of one day * - * @param year Year of the day - * @param month Month of the day (in 1-12) + * @param year Year of the day + * @param month Month of the day (in 1-12) * @param dayOfMonth Day of month of the day (1-31) * @return */ @@ -254,8 +254,8 @@ public static TsPeriod daily(int year, int month, int dayOfMonth) { /** * Creates a period of seven days * - * @param year Year of the first day - * @param month Month of the first day (in 1-12) + * @param year Year of the first day + * @param month Month of the first day (in 1-12) * @param dayOfMonth Day of month of the first day (1-31) * @return */ @@ -293,7 +293,7 @@ private static TsPeriod make(LocalDateTime epoch, TsUnit unit, LocalDate date) { return new TsPeriod(epoch, unit, idAt(epoch, unit, date.atStartOfDay())); } - private static TsPeriod make(LocalDateTime epoch, TsUnit unit, LocalDateTime date) { + static TsPeriod make(LocalDateTime epoch, TsUnit unit, LocalDateTime date) { return new TsPeriod(epoch, unit, idAt(epoch, unit, date)); } @@ -332,8 +332,9 @@ public String display() { return Integer.toString(year()); } else { int pos = this.annualPosition() + 1; - if (freq < 12) + if (freq < 12) { pos *= 12 / freq; + } int year = this.year(); StringBuilder buffer = new StringBuilder(32); buffer.append(pos).append('-').append(year); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/util/List2.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/util/List2.java deleted file mode 100644 index 206d832e..00000000 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/util/List2.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2018 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved - * by the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * http://ec.europa.eu/idabc/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package jdplus.toolkit.base.api.util; - -import nbbrd.design.NextJdk; -import nbbrd.design.ReturnImmutable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.function.Supplier; -import java.util.stream.Collector; -import org.checkerframework.checker.nullness.qual.NonNull; - -/** - * - * @author Philippe Charles - */ -@lombok.experimental.UtilityClass -public class List2 { - - @NextJdk(NextJdk.JDK9) - @ReturnImmutable - @SafeVarargs - @NonNull - public static List of(@NonNull E... elements) { - switch (elements.length) { - case 0: - return Collections.emptyList(); - case 1: - return Collections.singletonList(Objects.requireNonNull(elements[0])); - default: - List result = new ArrayList<>(); - for (E element : elements) { - result.add(Objects.requireNonNull(element)); - } - return Collections.unmodifiableList(result); - } - } - - @NextJdk(NextJdk.JDK10) - @ReturnImmutable - @NonNull - public static List copyOf(@NonNull Collection coll) { - switch (coll.size()) { - case 0: - return Collections.emptyList(); - case 1: - return Collections.singletonList(Objects.requireNonNull(coll.iterator().next())); - default: - List result = new ArrayList<>(); - for (E element : coll) { - result.add(Objects.requireNonNull(element)); - } - return Collections.unmodifiableList(result); - } - } - - @NextJdk(NextJdk.JDK10) - @ReturnImmutable - @NonNull - public static Collector> toUnmodifiableList() { - return Collector.of((Supplier>) ArrayList::new, List2::accumulate, List2::combine, Collections::unmodifiableList); - } - - private static void accumulate(List r, T t) { - r.add(Objects.requireNonNull(t)); - } - - private static List combine(List l, List r) { - l.addAll(r); - return l; - } -} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/util/NamedObject.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/util/NamedObject.java index 93fd37b4..8071b2eb 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/util/NamedObject.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/jdplus/toolkit/base/api/util/NamedObject.java @@ -1,12 +1,15 @@ package jdplus.toolkit.base.api.util; +import lombok.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Objects; @lombok.Value -public final class NamedObject implements Comparable> { +public class NamedObject implements Comparable> { - private String name; - private T object; + @NonNull String name; + @Nullable T object; @Override public int compareTo(NamedObject o) { diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/module-info.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/module-info.java index 4714d74a..b09a9316 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/module-info.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/main/java/module-info.java @@ -29,6 +29,7 @@ exports jdplus.toolkit.base.api.information.formatters; exports jdplus.toolkit.base.api.math; exports jdplus.toolkit.base.api.math.functions; + exports jdplus.toolkit.base.api.math.linearfilters; exports jdplus.toolkit.base.api.math.matrices; exports jdplus.toolkit.base.api.modelling; exports jdplus.toolkit.base.api.modelling.highfreq; diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/math/ComplexTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/math/ComplexTest.java new file mode 100644 index 00000000..d68195a8 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/math/ComplexTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.base.api.math; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author palatej + */ +public class ComplexTest { + + public ComplexTest() { + } + + @Test + public void testInv() { + Complex c=Complex.cart(2,-.5); + assertEquals(1/c.abs(), c.inv().abs(), 1e-16); + } + +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsDataTableTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsDataTableTest.java index 7221b2bb..bd079d73 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsDataTableTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsDataTableTest.java @@ -94,6 +94,10 @@ public void testFactory() { .extracting(TsDataTable::getDomain, TsDataTable::getData) .containsExactly(p1m_jan2010.getDomain(), asList(p1m_jan2010, empty)); + assertThat(TsDataTable.of(asList(p1m_jan2010, null))) + .returns(p1m_jan2010.getDomain(), TsDataTable::getDomain) + .returns(asList(p1m_jan2010, null), TsDataTable::getData); + assertThat(TsDataTable.of(asList(empty, p1m_jan2010))) .extracting(TsDataTable::getDomain, TsDataTable::getData) .containsExactly(p1m_jan2010.getDomain(), asList(empty, p1m_jan2010)); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsDataTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsDataTest.java index 4a03cfd1..2c07bb57 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsDataTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsDataTest.java @@ -222,6 +222,94 @@ public void testAggregationByPosition() { assertThat(ts.aggregateByPosition(YEAR, 11)).hasSize(5); assertThat(ts.aggregateByPosition(YEAR, 1)).hasSize(6); } + + @Test + public void testUpdateStartAndEndIntersecting() { + TsData start = TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{0, 1, 2}); + TsData end = TsData.ofInternal(TsPeriod.monthly(1999, 3), new double[]{3, 4, 5}); + TsData update = TsData.update(start, end); + assertThat(update.equals(TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{0, 1, 3, 4, 5}))); + } + + @Test + public void testUpdateStartAndEndIntersecting2() { + TsData start = TsData.ofInternal(TsPeriod.monthly(1999, 3), new double[]{0, 1, 2}); + TsData end = TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{3, 4, 5}); + TsData update = TsData.update(start, end); + assertThat(update.equals(TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{3, 4, 5, 1, 2}))); + } + + @Test + public void testUpdateEndContainedInStart() { + TsData start = TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{0, 1, 2, 3, 4}); + TsData end = TsData.ofInternal(TsPeriod.monthly(1999, 2), new double[]{3, 4, 5}); + TsData update = TsData.update(start, end); + assertThat(update.equals(TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{0, 3, 4, 5, 4}))); + } + + @Test + public void testUpdateStartContainedInEnd() { + TsData start = TsData.ofInternal(TsPeriod.monthly(1999, 2), new double[]{0, 1, 2}); + TsData end = TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{3, 4, 5, 6, 7}); + TsData update = TsData.update(start, end); + assertThat(update.equals(TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{3, 4, 5, 6, 7}))); + } + + @Test + public void testUpdateEndAfterStartConnecting() { + TsData start = TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{0, 1, 2}); + TsData end = TsData.ofInternal(TsPeriod.monthly(1999, 4), new double[]{3, 4, 5}); + TsData update = TsData.update(start, end); + assertThat(update.equals(TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{0, 1, 2, 3, 4, 5}))); + } + + @Test + public void testUpdateStartAfterEndConnecting() { + TsData start = TsData.ofInternal(TsPeriod.monthly(1999, 4), new double[]{0, 1, 2}); + TsData end = TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{3, 4, 5}); + TsData update = TsData.update(start, end); + assertThat(update.equals(TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{3, 4, 5, 0, 1, 2}))); + } + + @Test + public void testUpdateEndAfterStartSeparate() { + TsData start = TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{0, 1, 2}); + TsData end = TsData.ofInternal(TsPeriod.monthly(1999, 5), new double[]{3, 4, 5}); + TsData update = TsData.update(start, end); + assertThat(update.equals(TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{0, 1, 2, Double.NaN, 3, 4, 5}))); + } + + @Test + public void testUpdateStartAfterEndSeparate() { + TsData start = TsData.ofInternal(TsPeriod.monthly(1999, 5), new double[]{0, 1, 2}); + TsData end = TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{3, 4, 5}); + TsData update = TsData.update(start, end); + assertThat(update.equals(TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{3, 4, 5, Double.NaN, 0, 1, 2}))); + } + + @Test + public void testUpdatStartNull() { + TsData start = null; + TsData end = TsData.ofInternal(TsPeriod.monthly(1999, 5), new double[]{3, 4, 5}); + TsData update = TsData.update(start, end); + assertThat(update.equals(TsData.ofInternal(TsPeriod.monthly(1999, 5), new double[]{3, 4, 5}))); + } + + @Test + public void testUpdateEndNull() { + TsData start = TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{0, 1, 2}); + TsData end = null; + TsData update = TsData.update(start, end); + assertThat(update.equals(TsData.ofInternal(TsPeriod.monthly(1999, 1), new double[]{0, 1, 2}))); + } + + @Test + public void testUpdateStartAndEndDifferentFrequency() { + TsData start = TsData.ofInternal(TsPeriod.monthly(1999, 5), new double[]{0, 1, 2}); + TsData end = TsData.ofInternal(TsPeriod.quarterly(1999, 1), new double[]{0, 1, 2}); + assertThatThrownBy(() -> TsData.update(start, end)).isInstanceOf(TsException.class).hasMessageContaining("Incompatible frequencies"); + } + private static TsData monthlyTs(LocalDateTime start, int count) { return TsData.of(TsPeriod.of(TsUnit.MONTH, start), DoubleSeq.onMapping(count, i -> i + start.getMonthValue())); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsTestProvider.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsTestProvider.java index ab63e7d9..b5808fda 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsTestProvider.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/timeseries/TsTestProvider.java @@ -22,6 +22,7 @@ import jdplus.toolkit.base.api.timeseries.*; import nbbrd.service.ServiceProvider; +import org.checkerframework.checker.nullness.qual.NonNull; /** * @@ -41,12 +42,12 @@ public void close() { } @Override - public TsCollection getTsCollection(TsMoniker moniker, TsInformationType type) throws IOException, IllegalArgumentException { + public @NonNull TsCollection getTsCollection(@NonNull TsMoniker moniker, @NonNull TsInformationType type) throws IOException, IllegalArgumentException { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override - public Ts getTs(TsMoniker moniker, TsInformationType type) throws IOException, IllegalArgumentException { + public @NonNull Ts getTs(@NonNull TsMoniker moniker, @NonNull TsInformationType type) throws IOException, IllegalArgumentException { String[] split = moniker.getId().split(":"); if (split.length != 2) throw new IllegalArgumentException(); @@ -61,7 +62,7 @@ public Ts getTs(TsMoniker moniker, TsInformationType type) throws IOException, I } @Override - public String getSource() { + public @NonNull String getSource() { return "test"; } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/util/List2Test.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/util/List2Test.java deleted file mode 100644 index 231c800c..00000000 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/util/List2Test.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2018 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved - * by the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * http://ec.europa.eu/idabc/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package jdplus.toolkit.base.api.util; - -import java.util.Arrays; -import java.util.List; -import java.util.function.Supplier; -import java.util.stream.Stream; -import static org.assertj.core.api.Assertions.*; -import org.junit.jupiter.api.Test; - -/** - * - * @author Philippe Charles - */ -public class List2Test { - - @Test - public void testOf() { - assertThatNullPointerException().isThrownBy(() -> List2.of((Object[]) null)); - - String[] empty = {}; - assertThat(List2.of(empty)).isEmpty(); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.of(empty).add("other")); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.of(empty).set(0, "other")); - - String[] single = {"hello"}; - assertThat(List2.of(single)).containsExactly("hello"); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.of(single).add("other")); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.of(single).set(0, "other")); - assertThatNullPointerException().isThrownBy(() -> List2.of(new Object[]{null})); - - String[] multi = {"hello", "world"}; - assertThat(List2.of(multi)).containsExactly("hello", "world"); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.of(multi).add("other")); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.of(multi).set(0, "other")); - assertThatNullPointerException().isThrownBy(() -> List2.of(new Object[]{null, null})); - } - - @Test - @SuppressWarnings("null") - public void testCopyOf() { - assertThatNullPointerException().isThrownBy(() -> List2.copyOf(null)); - - List empty = Arrays.asList(); - assertThat(List2.copyOf(empty)).isEmpty(); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.copyOf(empty).add("other")); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.copyOf(empty).set(0, "other")); - - List single = Arrays.asList("hello"); - assertThat(List2.copyOf(single)).containsExactly("hello"); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.copyOf(single).add("other")); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.copyOf(single).set(0, "other")); - assertThatNullPointerException().isThrownBy(() -> List2.copyOf(Arrays.asList((Object) null))); - - List multi = Arrays.asList("hello", "world"); - assertThat(List2.copyOf(multi)).containsExactly("hello", "world"); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.copyOf(multi).add("other")); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> List2.copyOf(multi).set(0, "other")); - assertThatNullPointerException().isThrownBy(() -> List2.copyOf(Arrays.asList(null, null))); - } - - @Test - public void testToUnmodifiableList() { - Supplier> empty = () -> Stream.of(); - assertThat(empty.get().collect(List2.toUnmodifiableList())).isEmpty(); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> empty.get().collect(List2.toUnmodifiableList()).add("other")); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> empty.get().collect(List2.toUnmodifiableList()).set(0, "other")); - - Supplier> single = () -> Stream.of("hello"); - assertThat(single.get().collect(List2.toUnmodifiableList())).containsExactly("hello"); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> single.get().collect(List2.toUnmodifiableList()).add("other")); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> single.get().collect(List2.toUnmodifiableList()).set(0, "other")); - assertThatNullPointerException().isThrownBy(() -> Stream.of((Object) null).collect(List2.toUnmodifiableList())); - - Supplier> multi = () -> Stream.of("hello", "world"); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> multi.get().collect(List2.toUnmodifiableList()).add("other")); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> multi.get().collect(List2.toUnmodifiableList()).set(0, "other")); - assertThatNullPointerException().isThrownBy(() -> Stream.of(null, null).collect(List2.toUnmodifiableList())); - } -} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/util/NamedObjectTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/util/NamedObjectTest.java new file mode 100644 index 00000000..ed2701bb --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/jdplus/toolkit/base/api/util/NamedObjectTest.java @@ -0,0 +1,25 @@ +package jdplus.toolkit.base.api.util; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +public class NamedObjectTest { + + @Test + public void test() { + assertThat(new NamedObject<>("a", "b")) + .isEqualTo(new NamedObject<>("a", "b")) + .isNotEqualTo(new NamedObject<>("a", "c")) + .isNotEqualTo(new NamedObject<>("c", "b")); + + assertThat(new NamedObject<>("a", null)) + .isEqualTo(new NamedObject<>("a", null)) + .isNotEqualTo(new NamedObject<>("a", "c")) + .isNotEqualTo(new NamedObject<>("c", null)); + + assertThatNullPointerException() + .isThrownBy(() -> new NamedObject<>(null, "b").compareTo(new NamedObject<>("a", "b"))); + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/tck/demetra/data/Data.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/tck/demetra/data/Data.java index 4de0ca2c..06640298 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/tck/demetra/data/Data.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-api/src/test/java/tck/demetra/data/Data.java @@ -342,40 +342,40 @@ public class Data { }; public static final double[] IPI_SP_CN = { - 88.7034588, 89.55128158, 91.56486069, 86.47792399, 87.85563601, 92.20072778, 95.27408537, 61.36117401, 89.97519297, 92.09474993, - 87.53770247, 78.63556323, 81.17903159, 82.55674361, 90.08117082, 81.92087652, 86.37194614, 88.59748095, 92.51866133, 63.16279742, - 94.95615183, 90.61106006, 92.94257272, 89.02139234, 87.00781323, 90.50508221, 97.18168664, 89.86921512, 94.63821829, 98.34744297, - 95.80397461, 69.83940185, 99.72515499, 98.55939866, 102.0566676, 89.65725943, 92.73061702, 90.50508221, 100.1490664, 83.82847779, - 97.71157588, 100.8909113, 92.94257272, 69.83940185, 96.54581955, 98.02950942, 101.6327563, 85.6301012, 88.2795474, 87.85563601, - 90.61106006, 82.34478791, 93.15452841, 92.30670563, 98.45342081, 67.93180058, 91.352905, 100.9968892, 94.42626259, 83.93445564, - 92.30670563, 93.57843981, 92.73061702, 99.83113284, 95.16810753, 98.45342081, 103.9642689, 70.05135754, 98.77135436, 107.6734936, - 95.48604107, 91.88279424, 95.80397461, 99.61917714, 102.0566676, 93.7903955, 97.81755373, 103.8582911, 110.0050062, 75.2442721, - 102.5865569, 104.8120917, 101.7387341, 95.90995246, 96.4398417, 96.22788601, 103.8582911, 99.3012436, 99.3012436, 106.0838259, - 107.2495822, 80.96707589, 104.2822025, 103.5403575, 108.2033828, 103.9642689, 97.39364233, 99.51319929, 111.1707626, 93.26050626, - 105.2360031, 107.0376265, 107.6734936, 82.87467716, 105.3419809, 105.2360031, 112.5484746, 91.56486069, 99.93711069, 99.40722145, - 109.3691392, 94.32028474, 108.3093607, 105.7658923, 107.2495822, 84.14641133, 100.2550442, 109.2631613, 109.8990284, 92.30670563, - 101.102867, 100.7849335, 98.24146512, 108.4153385, 109.7930506, 103.1164461, 115.6218322, 85.10021196, 105.6599145, 120.6027911, - 112.6544524, 95.80397461, 101.9506898, 101.844712, 106.719693, 103.1164461, 107.35556, 108.9452278, 118.8011676, 82.55674361, - 109.2631613, 119.225079, 108.8392499, 98.24146512, 96.54581955, 101.2088449, 115.72781, 100.7849335, 107.0376265, 111.7006518, - 113.3962974, 86.26596829, 111.594674, 107.8854493, 114.8799873, 100.6789556, 97.18168664, 99.61917714, 108.5213164, 109.8990284, - 107.7794714, 113.5022752, 110.852829, 90.71703791, 112.972386, 107.9914271, 114.350098, 98.34744297, 105.2360031, 105.1300252, - 119.0131233, 95.80397461, 111.8066297, 112.6544524, 109.5810949, 90.39910436, 109.1571835, 112.3365189, 114.7740094, 97.49962018, - 112.8664081, 106.9316487, 119.1191012, 98.66537651, 114.7740094, 111.4886961, 115.6218322, 93.57843981, 105.4479588, 117.6354113, - 113.8202088, 99.51319929, 117.9533449, 113.9261866, 101.4208006, 113.9261866, 106.8256708, 102.9044904, 120.4968132, 84.14641133, - 106.5077373, 112.6544524, 103.4343797, 96.33386385, 100.4669999, 101.5267784, 103.8582911, 94.63821829, 97.60559803, 103.5403575, - 111.8066297, 81.70892083, 104.600136, 105.2360031, 107.1436044, 98.13548727, 97.39364233, 99.61917714, 114.350098, 100.4669999, - 102.2686233, 105.2360031, 108.7332721, 86.26596829, 105.4479588, 103.3284018, 109.8990284, 100.3610221, 99.54633311, 99.31252881, - 109.3211626, 93.23836296, 104.5627508, 105.4837409, 106.1895734, 92.42161891, 105.8644099, 100.9710735, 105.6885269, 99.48319213, - 99.96037098, 97.45580324, 103.1085147, 90.17245513, 104.7433711, 102.0032963, 103.9375354, 88.74264403, 94.81037777, 105.2366934, - 100.0656214, 84.65166751, 96.78952669, 92.20691161, 92.02866425, 98.87170454, 101.4932582, 94.07688328, 105.1977643, 86.28861557, - 98.16952261, 105.6337917, 99.80001644, 89.76024534, 98.7203617, 95.10705155, 100.4154905, 95.5847514, 102.4348302, 98.06607824, - 108.7851413, 83.90838773, 104.2196133, 107.1134055, 98.47206038, 93.74891507, 91.37958239, 93.75585804, 105.9493013, 95.84913273, - 99.5210825, 102.0311248, 111.0702987, 87.94272386, 106.3112411, 105.1785491, 105.0951232, 95.9159823, 97.81288538, 100.8850216, - 101.382522, 104.0208205, 103.0578086, 105.3132905, 103.165843, 91.84163835, 107.0267044, 101.0879984, 107.0681031, 93.8922896, - 98.4297055, 97.57717744, 113.2340702, 89.96904701, 110.7055436, 105.7219296, 102.691538, 92.98347938, 102.6046611, 107.0948276, - 109.2221505, 90.82100724, 103.064813, 97.03783367, 106.1992543, 100.1613846, 107.4356334, 101.8908914, 104.6637239, 91.77526338, - 99.79907237, 112.0743344, 105.8777757, 91.30469737, 106.113481, 100.4384983, 104.6556639, 99.93669306, 115.1511623, 98.74494604, - 110.6449474, 91.92416107, 103.1638624, 114.3294308, 104.6039953, 92.67536734, 101.6571692, 98.41981297, 101.7175677, 79.989433, + 88.7034588, 89.55128158, 91.56486069, 86.47792399, 87.85563601, 92.20072778, 95.27408537, 61.36117401, 89.97519297, 92.09474993, + 87.53770247, 78.63556323, 81.17903159, 82.55674361, 90.08117082, 81.92087652, 86.37194614, 88.59748095, 92.51866133, 63.16279742, + 94.95615183, 90.61106006, 92.94257272, 89.02139234, 87.00781323, 90.50508221, 97.18168664, 89.86921512, 94.63821829, 98.34744297, + 95.80397461, 69.83940185, 99.72515499, 98.55939866, 102.0566676, 89.65725943, 92.73061702, 90.50508221, 100.1490664, 83.82847779, + 97.71157588, 100.8909113, 92.94257272, 69.83940185, 96.54581955, 98.02950942, 101.6327563, 85.6301012, 88.2795474, 87.85563601, + 90.61106006, 82.34478791, 93.15452841, 92.30670563, 98.45342081, 67.93180058, 91.352905, 100.9968892, 94.42626259, 83.93445564, + 92.30670563, 93.57843981, 92.73061702, 99.83113284, 95.16810753, 98.45342081, 103.9642689, 70.05135754, 98.77135436, 107.6734936, + 95.48604107, 91.88279424, 95.80397461, 99.61917714, 102.0566676, 93.7903955, 97.81755373, 103.8582911, 110.0050062, 75.2442721, + 102.5865569, 104.8120917, 101.7387341, 95.90995246, 96.4398417, 96.22788601, 103.8582911, 99.3012436, 99.3012436, 106.0838259, + 107.2495822, 80.96707589, 104.2822025, 103.5403575, 108.2033828, 103.9642689, 97.39364233, 99.51319929, 111.1707626, 93.26050626, + 105.2360031, 107.0376265, 107.6734936, 82.87467716, 105.3419809, 105.2360031, 112.5484746, 91.56486069, 99.93711069, 99.40722145, + 109.3691392, 94.32028474, 108.3093607, 105.7658923, 107.2495822, 84.14641133, 100.2550442, 109.2631613, 109.8990284, 92.30670563, + 101.102867, 100.7849335, 98.24146512, 108.4153385, 109.7930506, 103.1164461, 115.6218322, 85.10021196, 105.6599145, 120.6027911, + 112.6544524, 95.80397461, 101.9506898, 101.844712, 106.719693, 103.1164461, 107.35556, 108.9452278, 118.8011676, 82.55674361, + 109.2631613, 119.225079, 108.8392499, 98.24146512, 96.54581955, 101.2088449, 115.72781, 100.7849335, 107.0376265, 111.7006518, + 113.3962974, 86.26596829, 111.594674, 107.8854493, 114.8799873, 100.6789556, 97.18168664, 99.61917714, 108.5213164, 109.8990284, + 107.7794714, 113.5022752, 110.852829, 90.71703791, 112.972386, 107.9914271, 114.350098, 98.34744297, 105.2360031, 105.1300252, + 119.0131233, 95.80397461, 111.8066297, 112.6544524, 109.5810949, 90.39910436, 109.1571835, 112.3365189, 114.7740094, 97.49962018, + 112.8664081, 106.9316487, 119.1191012, 98.66537651, 114.7740094, 111.4886961, 115.6218322, 93.57843981, 105.4479588, 117.6354113, + 113.8202088, 99.51319929, 117.9533449, 113.9261866, 101.4208006, 113.9261866, 106.8256708, 102.9044904, 120.4968132, 84.14641133, + 106.5077373, 112.6544524, 103.4343797, 96.33386385, 100.4669999, 101.5267784, 103.8582911, 94.63821829, 97.60559803, 103.5403575, + 111.8066297, 81.70892083, 104.600136, 105.2360031, 107.1436044, 98.13548727, 97.39364233, 99.61917714, 114.350098, 100.4669999, + 102.2686233, 105.2360031, 108.7332721, 86.26596829, 105.4479588, 103.3284018, 109.8990284, 100.3610221, 99.54633311, 99.31252881, + 109.3211626, 93.23836296, 104.5627508, 105.4837409, 106.1895734, 92.42161891, 105.8644099, 100.9710735, 105.6885269, 99.48319213, + 99.96037098, 97.45580324, 103.1085147, 90.17245513, 104.7433711, 102.0032963, 103.9375354, 88.74264403, 94.81037777, 105.2366934, + 100.0656214, 84.65166751, 96.78952669, 92.20691161, 92.02866425, 98.87170454, 101.4932582, 94.07688328, 105.1977643, 86.28861557, + 98.16952261, 105.6337917, 99.80001644, 89.76024534, 98.7203617, 95.10705155, 100.4154905, 95.5847514, 102.4348302, 98.06607824, + 108.7851413, 83.90838773, 104.2196133, 107.1134055, 98.47206038, 93.74891507, 91.37958239, 93.75585804, 105.9493013, 95.84913273, + 99.5210825, 102.0311248, 111.0702987, 87.94272386, 106.3112411, 105.1785491, 105.0951232, 95.9159823, 97.81288538, 100.8850216, + 101.382522, 104.0208205, 103.0578086, 105.3132905, 103.165843, 91.84163835, 107.0267044, 101.0879984, 107.0681031, 93.8922896, + 98.4297055, 97.57717744, 113.2340702, 89.96904701, 110.7055436, 105.7219296, 102.691538, 92.98347938, 102.6046611, 107.0948276, + 109.2221505, 90.82100724, 103.064813, 97.03783367, 106.1992543, 100.1613846, 107.4356334, 101.8908914, 104.6637239, 91.77526338, + 99.79907237, 112.0743344, 105.8777757, 91.30469737, 106.113481, 100.4384983, 104.6556639, 99.93669306, 115.1511623, 98.74494604, + 110.6449474, 91.92416107, 103.1638624, 114.3294308, 104.6039953, 92.67536734, 101.6571692, 98.41981297, 101.7175677, 79.989433, 88.61492379, 95.60591745, 106.623183, 84.15746848, 104.7553421, 104.7803893, 102.1591388, 93.04002761, 89.58254096 }; @@ -664,38 +664,32 @@ public class Data { }; public static final double[] ABS_RETAIL2 = { - 3396.4, 3497.9, 3357.8, 3486.8, 3355.9, 3454.3, 3551.5, 3830.5, 5179.7, 3384.5, 3369.8, 3805.3, 3665.1, 3760, - 3630.8, 3686.5, 3816.3, 3823.4, 3878.7, 4211.5, 5684.3, 3698.5, 3733.2, 4010.9, 3788.4, 4242.3, 3872.1, 3978, - 4096.1, 3901.4, 4274, 4557.1, 5847.5, 4130, 3856.8, 4196.9, 4228.9, 4739.1, 4190.3, 4514.6, 4566.3, 4380.3, - 4857.7, 5105, 6628.2, 4674.9, 4294.1, 4528, 4729, 5261.9, 4637.8, 4989.5, 4923.8, 4962.2, 5305.1, 5303.5, 7340, - 5065.3, 4679.8, 4993, 5166, 5386.3, 5118.9, 5494.6, 5236.7, 5395.1, 5744.4, 5745, 8022.4, 5304.4, 5226.8, 5729.7, - 5527.3, 5787.8, 5739.2, 5722.7, 5787.3, 5946.3, 6065.8, 6470.9, 8885.8, 5980.3, 5574.1, 6299, 6075.7, 6437.8, 6377.4, - 6287.5, 6436.4, 6565.5, 6605.4, 7154.3, 9394.4, 6511.6, 6031, 6749.3, 6476.1, 6947.9, 6758.9, 6573.5, 6911.2, 6589.3, - 7002.9, 7402.3, 9414.4, 6837.2, 6284.6, 6837.9, 6709.5, 7191.7, 6674.9, 7147, 7262.7, 6898.1, 7624.4, 7804.4, 9813.7, - 7305.3, 6848.2, 7164.6, 7435.5, 7551.4, 7180.7, 7487, 7119.3, 7406, 7946.1, 7887, 10379.6, 7455.9, 6833, 7497.4, 7539.8, - 7675.2, 7507.9, 7674.2, 7361.4, 7765.5, 8063.3, 8369.3, 11130.8, 7730.6, 7295.2, 8240.1, 7775.5, 8061.2, 8057.1, 8076.6, - 8222.7, 8410.6, 8638.4, 8906.7, 11684.1, 8268.3, 7750.3, 8656.9, 8514.5, 8860.4, 8767.9, 8762.1, 8964.4, 8996.2, 9214.9, - 9727.5, 12525, 9084.7, 8632.1, 9074.2, 8946.5, 9435.2, 9003.1, 9291.1, 9386.1, 8956.8, 9675.6, 9930.1, 12523.5, 9516.5, - 8636, 9325, 9221.1, 9819.1, 9116.7, 9719.3, 9524.8, 9596.6, 10237, 10340.9, 13318.2, 10042.7, 8872.4, 9575.7, 9756.6, - 10000.6, 9556.1, 10225.4, 9835.4, 10059.8, 10773.4, 10642.7, 13837.5, 10537.1, 9430.1, 10540, 10390.7, 10581, 10264.8, - 10824.9, 10555.3, 10908.9, 11336.8, 11584, 15016.9, 10794.2, 10114.8, 10930.1, 10609.9, 11052.7, 11675.2, 10605.2, - 11190.6, 11447.4, 11664.4, 12127.8, 15567.3, 11612.2, 10625.2, 11940.5, 11576.8, 12075.8, 11749.3, 12038.9, 12204.9, - 11949.3, 12797.9, 13359, 16743.5, 12836, 11392.4, 12728.5, 12455.8, 13217.9, 12550.6, 12943.3, 13261.7, 12888.3, 13798.9, - 14418.4, 17801.4, 13636.3, 12067.5, 13289.7, 13347.9, 13897.3, 13284, 14005.4, 13933.3, 14055.9, 15188.7, 15455, - 19384.4, 14934.7, 13588.5, 14600.9, 14552, 14685.1, 14679, 15154.9, 14731.7, 15204.1, 15769.1, 16017.9, 20298.1, - 15066.7, 13693.5, 15128.9, 14742.6, 15000.6, 15159.8, 15339.3, 15299, 15436, 16002.8, 16520.8, 20955, 15614.7, 14231, - 15868.7, 15619.2, 15959, 16106.6, 16214.5, 16401.9, 16348.7, 17155.7, 17800.4, 22142.8, 16855.2, 15331.4, 17317.7, - 16514.4, 17100.4, 17184.1, 17437, 17801.5, 17603.5, 18530.4, 19307.1, 23833.7, 18201, 16791.4, 17807.9, 17543, 18183.5, - 17477.9, 18391.2, 18198.2, 17885.2, 19144.5, 19478.5, 25184.3, 19384.5, 16853.8, 18927.9, 18849.3, 19397.5, 18902.9, - 19360.6, 19156.7, 19030.3, 20294.6, 20840.1, 25958.5, 19792, 17431.5, 19490.3, 19032, 19533.6, 19339.1, 20231.6, 19860.8, - 19916.3, 20575.4, 21163.7, 26599.2, 20063.7, 18079.3, 19933.8, 19833, 19888.1, 19738.3, 20419.6, 20388.3, 20475.9, - 21183.4, 21864.2, 27425.4, 20529.6, 19071.2, 20868.1, 20028.9, 20873.1, 20878.1, 20964.6, 21352, 21040.2, 21850.4, - 22680.2, 27676.4, 21510.6, 19299.8, 21410.5, 20601.1, 21481, 20984.5, 21474.2, 22024, 21551.9, 22853.7, 23771.3, - 29137.6, 22960.6, 20295, 22386.2, 21975.8, 22620.1, 22061.3, 22917.2, 22898.2, 23057.2, 24332.7, 24793.5, 30425.9, - 23924.6, 21239.9, 23584.2, 22812.9, 23532.6, 23293.5, 24015.9, 23824.2, 24008.9, 25447.3, 25783.5, 31923, 24753.1, - 22734.9, 24517.3, 23975.9, 24143.5, 24165.3, 24563.7, 24591.3, 25063.6, 25974.6, 26781.1, 33100.2, 25306.2, 22615, - 25113.5, 24583.1, 25133.2, 25167.5, 25278.6, 25275.4 - }; + 79.6, 80.8, 77.3, 80.4, 81.6, 81.4, 90.8, 92.3, 111, 91.7, 82, 91.4, 86.4, 85, 83.7, 85.9, 88.5, 89.6, 93.1, 95.4, 123.2, + 94.8, 90.5, 93.5, 88.8, 89.9, 89.6, 85.2, 92, 91.7, 95.6, 102.3, 129.7, 106, 95.3, 102.1, 98.1, 99.9, 93.8, 96, + 102.1, 101, 107.4, 113.5, 143.9, 114.9, 104.6, 113.8, 106.5, 106.6, 100.1, 101.1, 108.7, 107.5, 117.2, 117.4, + 150.5, 126.2, 114.2, 117.7, 116.2, 113.1, 107.8, 117.1, 116.6, 121.3, 130.2, 130, 170.4, 139.6, 124.5, 133.3, + 127.6, 120.2, 118.4, 117.6, 113.5, 124.9, 129.5, 135.7, 216.5, 112.2, 114.1, 138.9, 131.4, 134.8, 131.9, 134.9, + 139.9, 149.5, 149.2, 161.6, 258.4, 147, 136.8, 150.6, 144.3, 143.7, 138.7, 130.7, 137.1, 130.5, 137.9, 155.2, + 233.3, 139.9, 127.1, 139.9, 133.8, 139.8, 126.9, 128.6, 140.4, 133.8, 145.1, 155.1, 226.9, 150, 135.2, 145.4, + 148.2, 138.1, 132.2, 139.3, 140.1, 144.3, 155.1, 153.9, 245.4, 156.6, 138.6, 144, 154.3, 142.9, 133.9, 148.7, + 146.5, 147.5, 157.6, 164.2, 256.1, 154.9, 141.3, 158.5, 149.3, 144.4, 144.3, 153.1, 149.3, 161.9, 168.4, 182, + 281.3, 170.8, 156.5, 170.2, 166, 158.7, 162.8, 164, 169.3, 177.1, 173, 195, 294.7, 170.4, 169.2, 183.1, 180.3, + 180.5, 172.3, 178.3, 190.7, 184.7, 200.1, 216.7, 313.5, 191.3, 183.7, 205.1, 192.2, 206.3, 191.7, 193.9, 200.6, + 194.6, 215.6, 230.3, 352.9, 216.5, 201.7, 214.3, 215.1, 220.4, 206.4, 220.5, 219.3, 227, 247.4, 259.5, 399, 240.6, + 224.7, 251, 244, 239.4, 230.2, 252.7, 242.5, 258.2, 276.9, 283.7, 443.6, 251.1, 249.5, 263.4, 266.9, 253.8, 276.1, + 254.6, 277.1, 287.9, 291.9, 313.8, 481, 294.4, 267.4, 304.3, 289, 292.7, 279.5, 275.2, 283.5, 288.8, 318.1, 338, + 506.3, 328.9, 296.6, 340.2, 307.4, 313.2, 297.6, 331.2, 338.5, 337.2, 375.7, 400.9, 557.8, 384.8, 336.4, 365.1, + 378.8, 366.8, 356.7, 373.2, 368.2, 377.6, 408.2, 426.7, 621.8, 406, 368.7, 399.7, 406.6, 378.8, 382.8, 406.3, 402, + 409.9, 442.4, 446.3, 699.1, 404.1, 389.4, 442.6, 430.7, 409, 416.2, 435.3, 446.2, 459.7, 469.5, 504.1, 744.6, 462.2, + 432.8, 486.3, 480.6, 479.8, 482.6, 508, 525.4, 538.8, 551.9, 591, 869.3, 550.1, 519.6, 577.1, 557.7, 540.4, 522.9, + 547.8, 564.4, 598.8, 612.8, 638.1, 905.9, 627.2, 543.7, 617.6, 564.1, 567, 552.5, 565.7, 564.5, 584.5, 688.9, 704.9, + 1004.6, 738, 621.8, 676.4, 670.2, 665.5, 646.7, 657.3, 672, 678.4, 716.4, 752.2, 1029, 737.4, 626.7, 709, 698.2, + 673.4, 657.7, 687.3, 690.8, 722.6, 757.4, 790.1, 1138.4, 774.7, 673.8, 743.5, 756.8, 703.7, 684.9, 740.9, 753.1, + 769.8, 800.4, 852, 1235.5, 806.7, 735.2, 800.4, 773.4, 755.1, 738.3, 746.2, 776.7, 785.7, 806.4, 865.7, 1254.8, + 824.9, 714.1, 843.8, 761.3, 751.9, 732.5, 766.3, 798.8, 789.1, 830.9, 870.8, 1258.8, 867, 732.7, 824.8, 821.5, + 810, 765.9, 808.1, 819.9, 842.4, 911, 926.3, 1353, 893.1, 771.8, 882.5, 826.8, 824.5, 788.4, 836.2, 847.7, 865.2, + 926.9, 939.8, 1400.5, 916.2, 825.7, 947.7, 859.7, 852.5, 831.9, 871.2, 884.5, 926.7, 940, 993.4, 1478.4, 943.6, + 831.7, 941.8, 932.5, 877.6, 868.6, 913.3, 922.8}; public static final TsData TS_PROD; public static final TsData DAILY_CONTINUOUS; diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/pom.xml b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/pom.xml index 0b1404ef..1ebb2275 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/pom.xml +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-toolkit-base-parent - 3.0.2 + 3.1.0 jdplus-toolkit-base-core @@ -38,23 +38,5 @@ ${jd2.version} test - - org.junit.jupiter - junit-jupiter-api - 5.9.2 - test - - - org.junit.jupiter - junit-jupiter-params - 5.9.2 - test - - - org.junit.jupiter - junit-jupiter-engine - 5.9.2 - test - \ No newline at end of file diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/arima/ArimaSeriesGenerator.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/arima/ArimaSeriesGenerator.java index c1e5f286..a0fca4cf 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/arima/ArimaSeriesGenerator.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/arima/ArimaSeriesGenerator.java @@ -16,6 +16,7 @@ */ package jdplus.toolkit.base.core.arima; +import jdplus.toolkit.base.api.dstats.ContinuousDistribution; import jdplus.toolkit.base.core.data.DataBlock; import jdplus.toolkit.base.core.dstats.Normal; import jdplus.toolkit.base.core.math.matrices.FastMatrix; @@ -45,7 +46,7 @@ public static class Builder { private double startMean = 100; private double startStdev = 10; private final RandomNumberGenerator rng; - private Distribution dist = new Normal(); + private ContinuousDistribution dist = new Normal(); private Builder() { rng = XorshiftRNG.fromSystemNanoTime(); @@ -72,7 +73,7 @@ public Builder initialWarmUp(int n) { * @param distribution * @return */ - public Builder distribution(Distribution distribution) { + public Builder distribution(ContinuousDistribution distribution) { dist = distribution; return this; } @@ -104,7 +105,7 @@ public static Builder builder(@NonNull RandomNumberGenerator rng) { private final double startMean; private final double startStdev; private final RandomNumberGenerator rng; - private final Distribution distribution; + private final ContinuousDistribution distribution; public ArimaSeriesGenerator() { this(new Builder()); @@ -265,7 +266,7 @@ public double[] generateStationary(final IArimaModel starima, final double mean, return z; } - public static double[] generate(IArimaModel model, int n, double[] initial, Distribution distribution, int warmup) { + public static double[] generate(IArimaModel model, int n, double[] initial, ContinuousDistribution distribution, int warmup) { Polynomial phi = model.getAr().asPolynomial(); int p = phi.degree(); if (initial.length < p) { diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/dstats/Poisson.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/dstats/Poisson.java new file mode 100644 index 00000000..8eb3791e --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/dstats/Poisson.java @@ -0,0 +1,98 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.base.core.dstats; + +import jdplus.toolkit.base.api.dstats.BoundaryType; +import jdplus.toolkit.base.api.dstats.DStatException; +import jdplus.toolkit.base.api.dstats.DiscreteDistribution; +import jdplus.toolkit.base.api.dstats.RandomNumberGenerator; +import jdplus.toolkit.base.api.stats.ProbabilityType; +import jdplus.toolkit.base.core.stats.Combinatorics; + +/** + * + * @author palatej + */ +public class Poisson implements DiscreteDistribution { + + private final double mu, emu; + + public Poisson(double mu) { + this.mu = mu; + this.emu = Math.exp(-mu); + } + + @Override + public long getLeftBound() { + return 0; + } + + @Override + public long getRightBound() { + return Long.MAX_VALUE; + } + + @Override + public String getDescription() { + return "Poisson - " + Double.toString(mu); + } + + @Override + public double getExpectation() throws DStatException { + return mu; + } + + @Override + public double getProbability(long x) throws DStatException { + double p; + double lf = Combinatorics.logFactorial(x); + p = Math.exp(Math.log(mu) * x - lf - mu); + return p; + } + + @Override + public double getVariance() throws DStatException { + return mu; + } + + @Override + public BoundaryType hasLeftBound() { + return BoundaryType.Finite; + } + + @Override + public BoundaryType hasRightBound() { + return BoundaryType.None; + } + + @Override + public boolean isSymmetrical() { + return false; + } + + @Override + public long random(RandomNumberGenerator rng) throws DStatException { + int rndPoisson = -1; + double p = 1; + do { + p *= rng.nextDouble(); + ++rndPoisson; + } while (p > emu); + return rndPoisson; + } + +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/AsymmetricFiltersFactory.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/AsymmetricFiltersFactory.java index 0e68d91c..28bd5e1a 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/AsymmetricFiltersFactory.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/AsymmetricFiltersFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 National Bank of Belgium. + * Copyright 2023 National Bank of Belgium. * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved * by the European Commission - subsequent versions of the EUPL (the "Licence"); @@ -35,12 +35,6 @@ @lombok.experimental.UtilityClass public class AsymmetricFiltersFactory { - public static enum Option { - Direct, - CutAndNormalize, - MMSRE - } - /** * * @param s @@ -49,13 +43,13 @@ public static enum Option { * @return */ public IFiniteFilter musgraveFilter(final SymmetricFilter s, final int q, double ic) { - double r = 4 / (Math.PI * ic * ic); double[] h = s.weightsToArray(); int n = s.length(); int l = (n - 1) / 2; int m = l + q + 1; double[] c = new double[m]; + double r = Math.PI * ic * ic / 4; for (int i = 0; i < m; i++) { c[i] = h[i]; double p1 = 0.0, p2 = 0.0; @@ -64,9 +58,8 @@ public IFiniteFilter musgraveFilter(final SymmetricFilter s, final int q, double p2 += h[j] * ((j + 1) - (m + 1) / 2.0); } p1 /= m; - p2 *= (((i + 1) - (m + 1) / 2.0) * r / (1 + (m * (m - 1) * (m + 1) - * r * (1.0 / 12.0)))); - c[i] += (p1 + p2); + p2 *= ((i + 1) - (m + 1) / 2.0) / (r + m * (m - 1) * (m + 1) / 12.0); + c[i] += p1 + p2; } return FiniteFilter.ofInternal(c, -l); } @@ -201,10 +194,8 @@ public IFiniteFilter mmsreFilter(SymmetricFilter sw, int q, int u, double[] dz, /** * Extension of the usual asymmetric filters that introduces a timeliness - * criterion, - * "à la Guggemos". - * See Grun-Rehomme, Guggemos and Ladiray, "Asymmetric Moving Averages - * Minimizing Phase-Shift" + * criterion, "à la Guggemos". See Grun-Rehomme, Guggemos and Ladiray, + * "Asymmetric Moving Averages Minimizing Phase-Shift" * * @param sw * @param q diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/CrossValidation.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/CrossValidation.java index 8db34b20..b1e57ae5 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/CrossValidation.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/CrossValidation.java @@ -1,11 +1,24 @@ /* - * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license - * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + * Copyright 2023 National Bank of Belgium. + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package jdplus.toolkit.base.core.math.linearfilters; import jdplus.toolkit.base.api.data.DoubleSeq; import java.util.function.IntFunction; +import jdplus.toolkit.base.core.math.linearfilters.SymmetricFilter; /** * diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/FilterUtility.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/FilterUtility.java index d24de3f5..73237257 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/FilterUtility.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/FilterUtility.java @@ -36,20 +36,20 @@ public class FilterUtility { final double EPS = 1e-9; /** - * Checks that the absolute values of all the given roots are higher - * than the given limit. + * Checks that the absolute values of all the inverse of the given roots are + * lower than the given limit. * * @param roots The roots - * @param amin The limit (positive number) + * @param rmin The limit (positive number) * @return */ - public boolean checkRoots(final Complex[] roots, final double amin) { - if (roots == null || amin < 0) { + public boolean checkRoots(final Complex[] roots, final double rmin) { + if (roots == null || rmin < 0) { return true; } for (int i = 0; i < roots.length; ++i) { double n = (roots[i].abs()); - if (n <= amin) { + if (1 / n >= rmin) { return false; } } @@ -57,49 +57,52 @@ public boolean checkRoots(final Complex[] roots, final double amin) { } /** - * Checks that the norm of the roots of a given polynomial + * Checks that the norm of the inverse of the roots of a given polynomial * are higher than rmin * * @param c The coefficients of the polynomial (excluding the constant, - * which is considered as 1). - * The polynomial is 1+c(0)x+... - * @param rmin The limit of the roots + * which is considered as 1). The polynomial is 1+c(0)x+... + * @param rmin The limit of the inverse of the roots * @return */ public boolean checkRoots(final DoubleSeq c, final double rmin) { int nc = c.length(); switch (nc) { - case 0: + case 0 -> { return true; - case 1: + } + case 1 -> { double cabs = Math.abs(c.get(0)); - return (1 / cabs) > rmin; - case 2: + return cabs < rmin; + } + case 2 -> { double a = c.get(0), - b = c.get(1); + b = c.get(1); double ro = a * a - 4 * b; if (ro > 0) { // Roots are (-a+-sqrt(ro))/(2b) double sro = Math.sqrt(ro); double x0 = (-a + sro) / (2 * b), x1 = (-a - sro) / (2 * b); - return Math.abs(x0) > rmin && Math.abs(x1) > rmin; + return 1 / Math.abs(x0) < rmin && 1 / Math.abs(x1) < rmin; } else // Roots are (-a+-isqrt(-ro))/(2b). Abs(roots) = (1/2b)*sqrt((a*a - a*a+4*b))=1/sqr(b) // b is necessary positive { - return (1 / Math.sqrt(b)) > rmin; + return Math.sqrt(b) < rmin; } - default: + } + default -> { double[] ctmp = new double[nc + 1]; ctmp[0] = 1; c.copyTo(ctmp, 1); Polynomial p = Polynomial.ofInternal(ctmp); return checkRoots(p.roots(), rmin); + } } } /** - * Checks that the polynomial corresponding to the given coefficients - * has all its roots outside the unit circle. Same as checkRoots(c, 1), but - * more efficient. + * Checks that the polynomial corresponding to the given coefficients has + * all its roots outside the unit circle. Same as checkRoots(c, 1), but more + * efficient. * * @param c The coefficients of the polynomial. The polynomial is * 1+c(0)x+... @@ -162,13 +165,13 @@ public boolean checkStability(final Polynomial p) { /** * /** - * Stabilize a given polynomial (all its roots will be > 1/rmin) + * Stabilize a given polynomial (all its roots will be >= 1/rmin) * * @param c The coefficients of the polynomial (excluding the constant, - * which is considered as 1). - * The polynomial is 1+c(0)x+... - * @param rmin The inverse of the limit of the roots - * @return true if some coefficients where changed , false otherwise + * which is considered as 1). The polynomial is 1+c(0)x+... + * @param rmin The limit of the inverse of the roots (all abs of the roots + * will be >= 1/rmin) + * @return true if some coefficients where changed, false otherwise */ public boolean stabilize(DoubleSeq.Mutable c, double rmin) { int nc = c.length(); @@ -177,15 +180,16 @@ public boolean stabilize(DoubleSeq.Mutable c, double rmin) { } if (nc == 1) { double c0 = c.get(0); - double cabs = Math.abs(c0); - if (cabs < rmin) { + double rabs = Math.abs(c0); + if (rabs < rmin) { return false; } - - if (rmin < 1) { - c.set(0, c0 > 0 ? rmin : -rmin); - } else { + if (rabs > 1 / rmin) { c.set(0, 1 / c0); + } else { + // in [rmin, 1/rmin] + // we put it nearly on the boundary + c.set(0, c0 > 0 ? rmin - EPS : -rmin + EPS); } return true; } @@ -201,6 +205,7 @@ public boolean stabilize(DoubleSeq.Mutable c, double rmin) { } return true; } + return false; } @@ -210,8 +215,7 @@ public boolean stabilize(DoubleSeq.Mutable c, double rmin) { * @param p * @param rmin * @return A new polynomial is returned if the initial polynomial was not - * stable - * (= some roots were higher than rmin + * stable (= some roots were lower than 1/rmin) */ public Polynomial stabilize(Polynomial p, double rmin) { if (p == null) { @@ -222,14 +226,15 @@ public Polynomial stabilize(Polynomial p, double rmin) { boolean changed = false; for (int i = 0; i < roots.length; ++i) { Complex root = roots[i]; - double n = 1 / roots[i].abs(); - if (n > rmin) { - if (rmin < 1) { - roots[i] = root.times(n / rmin); - } else if (n > 1) { - roots[i] = root.inv(); - + double n = roots[i].abs(); + if (n < 1 / rmin) { + if (n < 1) { + root = root.inv(); } + if (n > rmin) { + root = root.div(rmin - EPS); + } + roots[i] = root; changed = true; } } @@ -263,7 +268,8 @@ public double[] compact(final double[] data) { } /** - * Computes the frequency response (f(w)=sum(w(t)e(iwt))=sum(w(t)(cos(wt)+i*sin(wt))) + * Computes the frequency response + * (f(w)=sum(w(t)e(iwt))=sum(w(t)(cos(wt)+i*sin(wt))) * * @param c * @param lb Lower bound (included) @@ -365,6 +371,25 @@ public DoubleSeq filter(DoubleSeq input, final SymmetricFilter filter, final IFi return DoubleSeq.of(x); } + public void inPlaceFilter(DoubleSeq input, DataBlock output, final SymmetricFilter filter, final IFiniteFilter[] afilters) { + int h = filter.getUpperBound(), ilen = input.length(); + DataBlock out = output.drop(h, h); + filter.apply(input, out); + + // apply the endpoints filters + if (afilters != null) { + for (int i = 0, j = h - 1, k = ilen - h, len = 2 * h; i < h; ++i, --len, --j, ++k) { + output.set(j, afilters[i].apply(input.extract(0, len).reverse())); + output.set(k, afilters[i].apply(input.extract(ilen - len, len))); + } + } else { + for (int i = 0; i < h; ++i) { + output.set(i, Double.NaN); + output.set(ilen - i - 1, Double.NaN); + } + } + } + /** * Applies the given central filter on a sequence of input. The end-points * are handled using given asymmetric filters or set to NaN. @@ -410,4 +435,33 @@ public DoubleSeq filter(DoubleSeq input, final IFiniteFilter filter, final IFini } return DoubleSeq.of(x); } + + public void inPlaceFilter(DoubleSeq input, DataBlock output, final IFiniteFilter filter, final IFiniteFilter[] leftFilters, final IFiniteFilter[] rightFilters) { + int l = -filter.getLowerBound(), u = filter.getUpperBound(), ilen = input.length(); + DataBlock out = output.drop(l, u); + filter.apply(input, out); + + // apply the endpoints filters + if (leftFilters != null) { + for (int i = 0, j = l - 1; i < l; ++i, --j) { + IFiniteFilter cur = leftFilters[i]; + output.set(j, cur.apply(input.extract(j + cur.getLowerBound(), cur.length()))); + } + } else { + for (int i = 0; i < l; ++i) { + output.set(i, Double.NaN); + } + } + if (rightFilters != null) { + for (int i = 0, j = ilen - u; i < u; ++i, ++j) { + IFiniteFilter cur = rightFilters[i]; + output.set(j, cur.apply(input.extract(j + cur.getLowerBound(), cur.length()))); + } + } else { + for (int i = 0; i < l; ++i) { + output.set(ilen - i - 1, Double.NaN); + } + } + } + } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/Filtering.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/Filtering.java new file mode 100644 index 00000000..67f0c8d0 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/Filtering.java @@ -0,0 +1,113 @@ +/* + * Copyright 2023 National Bank of Belgium. + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jdplus.toolkit.base.core.math.linearfilters; + +import jdplus.toolkit.base.api.data.DoubleSeq; +import jdplus.toolkit.base.core.math.polynomials.Polynomial; +import jdplus.toolkit.base.api.math.matrices.Matrix; +import jdplus.toolkit.base.core.data.DataBlock; + +/** + * + * @author PALATEJ + */ +public class Filtering implements IFiltering { + + private final IFiniteFilter cf; + private final IFiniteFilter[] lf; + private final IFiniteFilter[] rf; + + public Filtering(IFiniteFilter cf, IFiniteFilter[] lf, IFiniteFilter[] rf) { + this.cf = cf; + this.lf = lf.clone(); + this.rf = rf.clone(); + } + + public static Filtering of(DoubleSeq cf, Matrix lf, Matrix rf) { + int lb = lf.getColumnsCount(), rb = rf.getColumnsCount(); + if (cf.length() != lb + rb + 1) { + throw new IllegalArgumentException(); + } + FiniteFilter fcf = new FiniteFilter(Polynomial.of(cf.toArray()), -lb); + IFiniteFilter[] flf = new IFiniteFilter[lb]; + for (int i = 0; i < lb; ++i) { + flf[i] = new FiniteFilter(lfilter(lf.column(i)), i - lb + 1); + } + IFiniteFilter[] frf = new IFiniteFilter[rb]; + for (int i = 0; i < rb; ++i) { + Polynomial r = rfilter(rf.column(i)); + frf[i] = new FiniteFilter(r, rb-i-r.degree()-1); + } + return new Filtering(fcf, flf, frf); + } + + public static Filtering of(DoubleSeq cf, Matrix lf) { + int l = lf.getColumnsCount(); + if (cf.length() != 2 * l + 1) { + throw new IllegalArgumentException(); + } + FiniteFilter fcf = new FiniteFilter(Polynomial.of(cf.toArray()), -l); + IFiniteFilter[] flf = new IFiniteFilter[l]; + IFiniteFilter[] frf = new IFiniteFilter[l]; + for (int i = 0; i < l; ++i) { + FiniteFilter f = new FiniteFilter(lfilter(lf.column(i)), i - l + 1); + flf[i] = f; + frf[i] = f.mirror(); + } + return new Filtering(fcf, flf, frf); + } + + private static Polynomial lfilter(DoubleSeq col) { + int n = col.length(), pos = n - 1; + while (pos > 0) { + double cur = col.get(pos); + if (cur != 0) { + break; + } + --pos; + } + return Polynomial.raw(col.extract(0, pos + 1).toArray()); + } + + private static Polynomial rfilter(DoubleSeq col) { + int n = col.length(), pos = 0; + while (pos < n) { + double cur = col.get(pos); + if (cur != 0) { + break; + } + ++pos; + } + return Polynomial.raw(col.range(pos, n).toArray()); + } + + @Override + public IFiniteFilter centralFilter() { + return cf; + } + + @Override + public IFiniteFilter[] leftEndPointsFilters() { + return lf.clone(); + } + + @Override + public IFiniteFilter[] rightEndPointsFilters() { + return rf.clone(); + } + +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/FiltersToolkit.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/FiltersToolkit.java new file mode 100644 index 00000000..8a8be06b --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/FiltersToolkit.java @@ -0,0 +1,198 @@ +/* + * Copyright 2023 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.base.core.math.linearfilters; + +import java.util.HashMap; +import jdplus.toolkit.base.api.information.InformationMapping; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.DoubleUnaryOperator; +import java.util.function.Function; +import java.util.function.IntToDoubleFunction; +import jdplus.toolkit.base.api.information.GenericExplorable; +import jdplus.toolkit.base.api.math.linearfilters.FilterSpec; +import jdplus.toolkit.base.api.math.linearfilters.HendersonSpec; +import jdplus.toolkit.base.api.math.linearfilters.LocalPolynomialFilterSpec; +import jdplus.toolkit.base.api.math.linearfilters.UserDefinedFilterSpec; +import jdplus.toolkit.base.api.math.linearfilters.UserDefinedSymmetricFilterSpec; + +/** + * + * @author Jean Palate + */ +@lombok.experimental.UtilityClass +public class FiltersToolkit { + + private final Map< Class, Function> map = new HashMap<>(); + + static { + map.put(HendersonSpec.class, spec -> HendersonFilters.of((HendersonSpec) spec)); + map.put(LocalPolynomialFilterSpec.class, spec -> LocalPolynomialFilters.of((LocalPolynomialFilterSpec) spec)); + map.put(UserDefinedSymmetricFilterSpec.class, spec ->{ + if (spec instanceof UserDefinedSymmetricFilterSpec uspec){ + return Filtering.of(uspec.getCentralFilter(), uspec.getEndPointsFilters()); + }else + return null; + } ); + map.put(UserDefinedFilterSpec.class, spec ->{ + if (spec instanceof UserDefinedFilterSpec uspec){ + return Filtering.of(uspec.getCentralFilter(), uspec.getLFilters(), uspec.getUFilters()); + }else + return null; + } ); + } + + public void register(Class spec, Function fn) { + synchronized (map) { + map.put(spec, (Function) fn); + } + } + + public void unregister(Class spec) { + synchronized (map) { + map.remove(spec); + } + } + + public IFiltering of(FilterSpec spec){ + synchronized(map){ + Function fn=map.get(spec.getClass()); + if (fn == null) + throw new LinearFilterException("Filter spec not registered"); + return fn.apply(spec); + } + } + + @lombok.Value + @lombok.AllArgsConstructor + @lombok.Builder + public static class FiniteFilters implements GenericExplorable { + + private SymmetricFilter filter; + private IFiniteFilter[] afilters; + + private static final InformationMapping MAPPING = new InformationMapping() { + @Override + public Class getSourceClass() { + return FiniteFilters.class; + } + }; + + public static final InformationMapping getMapping() { + return MAPPING; + } + + @Override + public boolean contains(String id) { + return MAPPING.contains(id); + } + + @Override + public Map getDictionary() { + Map dic = new LinkedHashMap<>(); + MAPPING.fillDictionary(null, dic, true); + return dic; + } + + @Override + public T getData(String id, Class tclass) { + return MAPPING.getData(this, id, tclass); + } + + static { + MAPPING.set("svariancereduction", Double.class, source -> varianceReduction(source.filter)); + MAPPING.setArray("avariancereduction", 0, Double.class, (source, i) + -> i < source.afilters[i].length() ? varianceReduction(source.afilters[i]) : Double.NaN); + MAPPING.set("sbias2", Double.class, source -> bias2(source.filter)); + MAPPING.setArray("abias0", 0, Double.class, (source, i) + -> i < source.afilters[i].length() ? bias0(source.afilters[i]) : Double.NaN); + MAPPING.setArray("abias1", 0, Double.class, (source, i) + -> i < source.afilters[i].length() ? bias1(source.afilters[i]) : Double.NaN); + MAPPING.setArray("abias2", 0, Double.class, (source, i) + -> i < source.afilters[i].length() ? bias2(source.afilters[i]) : Double.NaN); + MAPPING.set("sweights", double[].class, source -> source.filter.weightsToArray()); + MAPPING.setArray("aweights", 0, double[].class, (source, i) -> i < source.afilters[i].length() ? source.afilters[i].weightsToArray() : null); + MAPPING.set("sgain", double[].class, source -> gain(source.filter)); + MAPPING.setArray("again", 0, double[].class, (source, i) -> i < source.afilters[i].length() ? gain(source.afilters[i]) : null); + MAPPING.setArray("aphase", 0, double[].class, (source, i) -> i < source.afilters[i].length() ? phase(source.afilters[i]) : null); + } + } + + public double[] gain(IFilter filter) { + DoubleUnaryOperator gainFunction = filter.gainFunction(); + int RES = 600; + double[] g = new double[RES + 1]; + for (int i = 0; i <= RES; ++i) { + g[i] = gainFunction.applyAsDouble(i * Math.PI / 600); + } + return g; + } + + public double varianceReduction(IFiniteFilter filter) { + double s = 0; + int l = filter.getLowerBound(), u = filter.getUpperBound(); + IntToDoubleFunction weights = filter.weights(); + for (int i = l; i <= u; ++i) { + double w = weights.applyAsDouble(i); + s += w * w; + } + return s; + } + + public double bias0(IFiniteFilter filter) { + double s = 0; + int l = filter.getLowerBound(), u = filter.getUpperBound(); + IntToDoubleFunction weights = filter.weights(); + for (int i = l; i <= u; ++i) { + double w = weights.applyAsDouble(i); + s += w; + } + return s; + } + + public double bias1(IFiniteFilter filter) { + double s = 0; + int l = filter.getLowerBound(), u = filter.getUpperBound(); + IntToDoubleFunction weights = filter.weights(); + for (int i = l; i <= u; ++i) { + double w = i * weights.applyAsDouble(i); + s += w; + } + return s; + } + + public double bias2(IFiniteFilter filter) { + double s = 0; + int l = filter.getLowerBound(), u = filter.getUpperBound(); + IntToDoubleFunction weights = filter.weights(); + for (int i = l; i <= u; ++i) { + double w = i * i * weights.applyAsDouble(i); + s += w; + } + return s; + } + + public double[] phase(IFilter filter) { + DoubleUnaryOperator phaseFunction = filter.phaseFunction(); + int RES = 600; + double[] g = new double[RES + 1]; + for (int i = 0; i <= RES; ++i) { + g[i] = phaseFunction.applyAsDouble(i * Math.PI / 600); + } + return g; + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/HendersonFilters.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/HendersonFilters.java index 088deb5a..da95117b 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/HendersonFilters.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/HendersonFilters.java @@ -19,6 +19,7 @@ import nbbrd.design.Development; import java.util.HashMap; import java.util.Map; +import jdplus.toolkit.base.api.math.linearfilters.HendersonSpec; /** * @@ -64,4 +65,12 @@ public synchronized SymmetricFilter ofLength(int length) { FILTERSTORE.put(length, filter); return filter; } + + public IQuasiSymmetricFiltering of(HendersonSpec spec){ + + SymmetricFilter sf=ofLength(1+2*spec.getFilterHorizon()); + IFiniteFilter[] rf = AsymmetricFiltersFactory.musgraveFilters(sf, spec.getRightIcRatio()); + IFiniteFilter[] lf = ISymmetricFiltering.mirror(spec.isSymmetric() ? rf :AsymmetricFiltersFactory.musgraveFilters(sf, spec.getLeftIcRatio())); + return new QuasiSymmetricFiltering(sf, lf, rf); + } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/IFiltering.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/IFiltering.java new file mode 100644 index 00000000..1503233e --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/IFiltering.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023 National Bank of Belgium. + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jdplus.toolkit.base.core.math.linearfilters; + +import jdplus.toolkit.base.api.data.DoubleSeq; +import jdplus.toolkit.base.core.data.DataBlock; + +/** + * + * @author Jean Palate + */ +public interface IFiltering { + /** + * Applies a filter on an input to produce an output. + * The input and the output must have the same length + * @param in + * @return + */ + default DoubleSeq process(DoubleSeq in) { + return FilterUtility.filter(in, centralFilter(), leftEndPointsFilters(), rightEndPointsFilters()); + } + + default void inPlaceProcess(DoubleSeq in, DataBlock out) { + FilterUtility.inPlaceFilter(in, out, centralFilter(), leftEndPointsFilters(), rightEndPointsFilters()); + } + + IFiniteFilter centralFilter(); + + IFiniteFilter[] leftEndPointsFilters(); + IFiniteFilter[] rightEndPointsFilters(); +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/IQuasiSymmetricFiltering.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/IQuasiSymmetricFiltering.java new file mode 100644 index 00000000..d4f0c4b3 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/IQuasiSymmetricFiltering.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023 National Bank of Belgium. + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jdplus.toolkit.base.core.math.linearfilters; + +/** + * + * @author Jean Palate + */ +public interface IQuasiSymmetricFiltering extends IFiltering{ + + @Override + SymmetricFilter centralFilter(); + + +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/ISymmetricFiltering.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/ISymmetricFiltering.java new file mode 100644 index 00000000..36a72581 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/ISymmetricFiltering.java @@ -0,0 +1,60 @@ +/* + * Copyright 2023 National Bank of Belgium. + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jdplus.toolkit.base.core.math.linearfilters; + +import jdplus.toolkit.base.api.data.DoubleSeq; +import jdplus.toolkit.base.core.data.DataBlock; + +/** + * + * Same (mirror) end points filters + * @author Jean Palate + */ +public interface ISymmetricFiltering extends IQuasiSymmetricFiltering{ + + @Override + default DoubleSeq process(DoubleSeq in) { + return FilterUtility.filter(in, centralFilter(), endPointsFilters()); + } + + + @Override + default void inPlaceProcess(DoubleSeq in, DataBlock out) { + FilterUtility.inPlaceFilter(in, out, centralFilter(), endPointsFilters()); + } + + IFiniteFilter[] endPointsFilters(); + + @Override + default IFiniteFilter[] leftEndPointsFilters(){ + return mirror(endPointsFilters()); + } + + @Override + default IFiniteFilter[] rightEndPointsFilters(){ + return endPointsFilters(); + } + + public static IFiniteFilter[] mirror(IFiniteFilter[] rightEndPoints){ + IFiniteFilter[] lf=rightEndPoints.clone(); + for (int i=0; i + DiscreteKernel.biweight(len); + case TriWeight -> + DiscreteKernel.triweight(len); + case Uniform -> + DiscreteKernel.uniform(len); + case Triangular -> + DiscreteKernel.triangular(len); + case Epanechnikov -> + DiscreteKernel.epanechnikov(len); + case Henderson -> + DiscreteKernel.henderson(len); + default -> + null; + }; + } + + private static class SFilter implements ISymmetricFiltering { + + private final SymmetricFilter symmetricFilter; + private final IFiniteFilter[] asymmetricFilters; + + private SFilter(LocalPolynomialFilterSpec spec) { + int len = spec.getFilterHorizon(); + symmetricFilter = ofDefault(len, spec.getPolynomialDegree(), kernel(spec)); + asymmetricFilters = switch (spec.getAsymmetricFilters()) { + case CutAndNormalize -> + AsymmetricFiltersFactory.cutAndNormalizeFilters(symmetricFilter); + case MMSRE -> + AsymmetricFiltersFactory.mmsreFilters(symmetricFilter, + spec.getAsymmetricPolynomialDegree(), spec.getRightLinearModelCoefficients(), null, + spec.getPassBand(), spec.getTimelinessWeight()); + default -> + directAsymmetricFilters(len, spec.getPolynomialDegree(), kernel(spec)); + }; + } + + @Override + public DoubleSeq process(DoubleSeq in) { + return FilterUtility.filter(in, symmetricFilter, asymmetricFilters); + } + + @Override + public SymmetricFilter centralFilter() { + return symmetricFilter; + } + + @Override + public IFiniteFilter[] endPointsFilters() { + return asymmetricFilters; + } + } + + private static class Filter implements IQuasiSymmetricFiltering { + + private final SymmetricFilter symmetricFilter; + private final IFiniteFilter[] leftAsymmetricFilters, rightAsymmetricFilters; + + private Filter(LocalPolynomialFilterSpec spec) { + int len = spec.getFilterHorizon(); + symmetricFilter = ofDefault(len, spec.getPolynomialDegree(), kernel(spec)); + rightAsymmetricFilters = switch (spec.getAsymmetricFilters()) { + case CutAndNormalize -> + AsymmetricFiltersFactory.cutAndNormalizeFilters(symmetricFilter); + case MMSRE -> + AsymmetricFiltersFactory.mmsreFilters(symmetricFilter, + spec.getAsymmetricPolynomialDegree(), spec.getRightLinearModelCoefficients(), null, + spec.getPassBand(), spec.getTimelinessWeight()); + default -> + directAsymmetricFilters(len, spec.getPolynomialDegree(), kernel(spec)); + }; + leftAsymmetricFilters = ISymmetricFiltering.mirror(switch (spec.getAsymmetricFilters()) { + case MMSRE -> + AsymmetricFiltersFactory.mmsreFilters(symmetricFilter, + spec.getAsymmetricPolynomialDegree(), spec.getLeftLinearModelCoefficients(), null, + spec.getPassBand(), spec.getTimelinessWeight()); + default -> + rightAsymmetricFilters; + }); + } + + @Override + public DoubleSeq process(DoubleSeq in) { + return FilterUtility.filter(in, symmetricFilter, leftAsymmetricFilters, rightAsymmetricFilters); + } + + @Override + public SymmetricFilter centralFilter() { + return symmetricFilter; + } + + @Override + public IFiniteFilter[] leftEndPointsFilters() { + return leftAsymmetricFilters; + } + + @Override + public IFiniteFilter[] rightEndPointsFilters() { + return rightAsymmetricFilters; + } + } + /** * * @param h the number of lags (-> length of the filter is 2*h+1) @@ -46,9 +165,12 @@ public class LocalPolynomialFilters { */ public SymmetricFilter of(final int h, final int d, final IntToDoubleFunction k) { return switch (d) { - case 0, 1 -> of0_1(h, k); - case 2, 3 -> of2_3(h, k); - default -> ofDefault(h, d, k); + case 0, 1 -> + of0_1(h, k); + case 2, 3 -> + of2_3(h, k); + default -> + ofDefault(h, d, k); }; } @@ -77,9 +199,7 @@ public FiniteFilter directAsymmetricFilter(final int h, final int q, final int d } double[] u = new double[d + 1]; u[0] = 1; -// Householder hous = new Householder(xkx); -// hous.solve(DataBlock.of(u)); - LinearSystemSolver.fastSolver().solve(xkx, DataBlock.of(u)); + LinearSystemSolver.robustSolver().solve(xkx, DataBlock.of(u)); double[] w = new double[h + q + 1]; w[h] = u[0] * k.applyAsDouble(0); for (int i = 1; i <= q; ++i) { @@ -107,8 +227,8 @@ public FiniteFilter directAsymmetricFilter(final int h, final int q, final int d public FiniteFilter[] directAsymmetricFilters(int h, final int d, final IntToDoubleFunction k) { FiniteFilter[] ff = new FiniteFilter[h]; - for (int i = 0; i < h; ++i) { - ff[i] = directAsymmetricFilter(h, i, d, k); + for (int i = 0, j = h - 1; i < h; ++i, --j) { + ff[i] = directAsymmetricFilter(h, j, d, k); } return ff; } @@ -149,7 +269,7 @@ private static SymmetricFilter of2_3(int h, IntToDoubleFunction k) { // SymmetricFilter ofDefault2(int h, int d, IntToDoubleFunction k) { // // w = KX (X'K X)^-1 e1 // // (X'K X)^-1 e1 = u <-> (X'K X) u = e1 -// CanonicalMatrix xkx = CanonicalMatrix.square(d + 1); +// FastMatrix xkx = FastMatrix.square(d + 1); // for (int i = 0; i <= d; ++i) { // xkx.set(i, i, S_hd(h, 2 * i, k)); // for (int j = 0; j < i; ++j) { @@ -184,7 +304,7 @@ private static SymmetricFilter of2_3(int h, IntToDoubleFunction k) { * @param k The kernel (a uniform kernel is used if k is null) * @return */ - SymmetricFilter ofDefault(int h, int d, IntToDoubleFunction k) { + public SymmetricFilter ofDefault(int h, int d, IntToDoubleFunction k) { double[] sk = new double[h + 1]; if (k == null) { for (int i = 0; i < sk.length; ++i) { @@ -197,6 +317,7 @@ SymmetricFilter ofDefault(int h, int d, IntToDoubleFunction k) { sk[i] = Math.sqrt(ki); } } + } FastMatrix Z = createZ(h, d); DataBlockIterator rows = Z.rowsIterator(); @@ -205,8 +326,7 @@ SymmetricFilter ofDefault(int h, int d, IntToDoubleFunction k) { rows.next().mul(sk[Math.abs(pos++)]); } - Householder2 hous = new Householder2(); - QRDecomposition qr = hous.decompose(Z); + QRDecomposition qr = new Householder2().decompose(Z); double[] z = new double[Z.getRowsCount()]; z[0] = 1; UpperTriangularMatrix.solvexU(qr.rawR(), DataBlock.of(z, 0, d + 1, 1)); @@ -226,6 +346,50 @@ private double S_h0(int h, IntToDoubleFunction k) { return 2 * s + k.applyAsDouble(0); } +// private double S_h2(int h, IntToDoubleFunction k) { +// double s = 0; +// for (int i = 1; i <= h; ++i) { +// double j = i * i; +// s += j * k.applyAsDouble(i); +// } +// return 2 * s; +// } +// +// private double S_h4(int h, IntToDoubleFunction k) { +// double s = 0; +// for (int i = 1; i <= h; ++i) { +// double j = i * i; +// j *= j; +// s += j * k.applyAsDouble(i); +// } +// return 2 * s; +// } +// +// private double S_hd(int h, int d, IntToDoubleFunction k) { +// switch (d) { +// case 0: +// return S_h0(h, k); +// case 2: +// return S_h2(h, k); +// case 4: +// return S_h4(h, k); +// } +// if (d % 2 != 0) { +// return 0; +// } +// int hd = d / 2; +// double s = 0; +// for (int i = 1; i <= h; ++i) { +// double ii = i * i; +// double j = ii; +// for (int l = 2; l <= hd; ++l) { +// j *= ii; +// } +// s += j * k.applyAsDouble(i); +// } +// return 2 * s; +// } +// private double S_hqd(int h, int q, long d, IntToDoubleFunction k) { if (d == 0) { return S_hq0(h, q, k); @@ -276,9 +440,9 @@ private double S_hq0(int h, int q, IntToDoubleFunction k) { */ public FastMatrix z(FastMatrix Z, int l, int u, int d0, int d1) { int nh = Math.max(Math.abs(l), Math.abs(u)); -// if (Z == null || Z.getRowsCount() / 2 < nh || Z.getColumnsCount() < d1 + 1) { -// Z = createZ(nh, d1); -// } + if (Z == null || Z.getRowsCount() / 2 < nh || Z.getColumnsCount() < d1 + 1) { + Z = createZ(nh, d1); + } return Z.extract(l + nh, u - l + 1, d0, d1 - d0 + 1); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/QuasiSymmetricFiltering.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/QuasiSymmetricFiltering.java new file mode 100644 index 00000000..edd70eab --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/QuasiSymmetricFiltering.java @@ -0,0 +1,51 @@ +/* + * Copyright 2023 National Bank of Belgium. + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jdplus.toolkit.base.core.math.linearfilters; + +/** + * + * @author PALATEJ + */ +public class QuasiSymmetricFiltering implements IQuasiSymmetricFiltering { + + private final SymmetricFilter cf; + private final IFiniteFilter[] lf; + private final IFiniteFilter[] rf; + + public QuasiSymmetricFiltering(SymmetricFilter cf, IFiniteFilter[] lf, IFiniteFilter[] rf) { + this.cf = cf; + this.lf = lf.clone(); + this.rf = rf.clone(); + } + + @Override + public SymmetricFilter centralFilter() { + return cf; + } + + @Override + public IFiniteFilter[] leftEndPointsFilters() { + return lf.clone(); + } + + @Override + public IFiniteFilter[] rightEndPointsFilters() { + return rf.clone(); + } + + +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/SymmetricFiltering.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/SymmetricFiltering.java new file mode 100644 index 00000000..ed8707f1 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/linearfilters/SymmetricFiltering.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023 National Bank of Belgium. + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jdplus.toolkit.base.core.math.linearfilters; + +import jdplus.toolkit.base.api.data.DoubleSeq; +import jdplus.toolkit.base.core.data.DataBlock; + +/** + * + * @author PALATEJ + */ +public class SymmetricFiltering implements ISymmetricFiltering { + + private final SymmetricFilter cf; + private final IFiniteFilter[] ff; + + public SymmetricFiltering(SymmetricFilter cf, IFiniteFilter[] endPoints) { + this.cf = cf; + this.ff = endPoints.clone(); + } + + @Override + public SymmetricFilter centralFilter() { + return cf; + } + + @Override + public IFiniteFilter[] endPointsFilters() { + return ff; + } + + +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/matrices/FastMatrix.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/matrices/FastMatrix.java index 3d26cc00..9cc201dc 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/matrices/FastMatrix.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/math/matrices/FastMatrix.java @@ -1079,6 +1079,10 @@ public DataBlock column(int r0, int c0, int n) { return DataBlock.of(storage, beg, end, 1); } + /** + * + * @return An array containing the sum of each rows (size=number of rows) + */ public DataBlock rowSums() { if (isEmpty()) { return DataBlock.EMPTY; @@ -1091,6 +1095,10 @@ public DataBlock rowSums() { return x; } + /** + * + * @return An array containing the sum of each columns (size=number of columns) + */ public DataBlock columnSums() { if (isEmpty()) { return DataBlock.EMPTY; diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/RegSarimaComputer.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/RegSarimaComputer.java index ee58cb66..b4fbca80 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/RegSarimaComputer.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/RegSarimaComputer.java @@ -35,7 +35,7 @@ import jdplus.toolkit.base.core.regsarima.internal.HannanRissanenInitializer; import jdplus.toolkit.base.core.sarima.SarimaModel; import jdplus.toolkit.base.core.sarima.estimation.SarimaFixedMapping; -import jdplus.toolkit.base.core.sarima.estimation.SarimaMapping; +import jdplus.toolkit.base.core.sarima.estimation.SarimaMapping2; import jdplus.toolkit.base.core.stats.likelihood.ConcentratedLikelihoodWithMissing; import jdplus.toolkit.base.core.stats.likelihood.LogLikelihoodFunction; import nbbrd.design.BuilderPattern; @@ -149,7 +149,7 @@ public RegSarimaComputer(SsqFunctionMinimizer.Builder min, final double eps, fin public RegArimaEstimation process(RegArimaModel regs, IArimaMapping mapping) { SarimaModel current = regs.arima(); if (mapping == null) { - mapping = SarimaMapping.of(current.orders()); + mapping = SarimaMapping2.of(current.orders()); } SarimaOrders curSpec = current.orders(); if (curSpec.getParametersCount() == 0 || (mapping != null && mapping.getDim() == 0)) { @@ -206,7 +206,7 @@ public RegArimaEstimation process(RegArimaModel regs, public RegArimaEstimation optimize(RegArimaModel regs, IArimaMapping mapping) { SarimaModel arima = regs.arima(); if (mapping == null) { - mapping = SarimaMapping.of(arima.orders()); + mapping = SarimaMapping2.of(arima.orders()); } return estimate(regs, mapping, (SarimaModel) arima.stationaryTransformation().getStationaryModel(), eps); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/regular/ModelDescription.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/regular/ModelDescription.java index 53764da5..d76a6e01 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/regular/ModelDescription.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/regular/ModelDescription.java @@ -54,6 +54,7 @@ import jdplus.toolkit.base.core.sarima.SarimaModel; import jdplus.toolkit.base.core.sarima.estimation.SarimaFixedMapping; import jdplus.toolkit.base.core.sarima.estimation.SarimaMapping; +import jdplus.toolkit.base.core.sarima.estimation.SarimaMapping2; import jdplus.toolkit.base.core.stats.likelihood.ConcentratedLikelihoodWithMissing; import jdplus.toolkit.base.core.stats.likelihood.LogLikelihoodFunction; import jdplus.toolkit.base.core.timeseries.simplets.Transformations; @@ -741,7 +742,7 @@ public IArimaMapping mapping() { } return new SarimaFixedMapping(specification(), DoubleSeq.of(p), b); } else { - return SarimaMapping.of(specification()); + return SarimaMapping2.of(specification()); } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/regular/TradingDaysRegressionComparator.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/regular/TradingDaysRegressionComparator.java index 72f5587a..fc98d994 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/regular/TradingDaysRegressionComparator.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/regsarima/regular/TradingDaysRegressionComparator.java @@ -91,7 +91,6 @@ public RegArimaEstimation[] test(ModelDescription description, ITra cdesc.addVariable(Variable.variable("td", td[i])); rslt[i + 2] = cdesc.estimate(processor); } - return rslt; } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/sarima/estimation/SarimaMapping2.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/sarima/estimation/SarimaMapping2.java index b3e44cf0..c4f7b5a7 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/sarima/estimation/SarimaMapping2.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/sarima/estimation/SarimaMapping2.java @@ -34,7 +34,7 @@ @lombok.Builder( toBuilder = true) public class SarimaMapping2 implements IArimaMapping { - public static final double ARMAX = 0.99999; + public static final double ARMAX = 0.99; public static final double MAMAX = 1; public static final double STEP = Math.sqrt(2.220446e-16); private double arLimit; @@ -71,7 +71,7 @@ public static SarimaModel stabilize(SarimaModel m) { public static SarimaMapping2 of(SarimaOrders spec) { return SarimaMapping2 .builder(spec) - .arLimit(1) + .arLimit(ARMAX) .maLimit(1) .build(); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/ssf/likelihood/DiffuseLikelihood.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/ssf/likelihood/DiffuseLikelihood.java index 7dcedd0e..01e1779f 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/ssf/likelihood/DiffuseLikelihood.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/ssf/likelihood/DiffuseLikelihood.java @@ -82,7 +82,7 @@ public Builder residuals(DoubleSeq residuals) { return this; } if (ssqerr == 0) { - this.ssqerr = residuals.ssq(); + this.ssqerr = residuals.ssqWithMissing(); } this.res = residuals.toArray(); return this; @@ -204,6 +204,18 @@ public int dim() { public DoubleSeq e() { return res == null ? null : DoubleSeq.of(res); } + + @Override + public DoubleSeq deviances(){ + double f = factor(); + DoubleSeq e = e().select(x->Double.isFinite(x)); + if (f == 1) { + return e; + } else { + final double sf = Math.sqrt(f); + return e.map(x -> x * sf); + } + } @Override public double logDeterminant() { diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/stats/Combinatorics.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/stats/Combinatorics.java index b631d2e8..da600cc4 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/stats/Combinatorics.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/stats/Combinatorics.java @@ -5,15 +5,17 @@ */ package jdplus.toolkit.base.core.stats; +import jdplus.toolkit.base.api.math.MathException; import jdplus.toolkit.base.core.math.Arithmetics; /** * * @author Jean Palate */ +@lombok.experimental.UtilityClass public class Combinatorics { - public static long binomialCoefficient(final int n, final int k) { + public long binomialCoefficient(final int n, final int k) { if (k > n || n <= 0 || k < 0) { throw new IllegalArgumentException(); } @@ -52,4 +54,187 @@ public static long binomialCoefficient(final int n, final int k) { return result; } + public long factorial(long x) { + if (x < l_fac.length) { + return l_fac[(int) x]; + } else { + throw new MathException(MathException.OVERFLOW); + } + } + + public double dfactorial(long x) { + if (x < d_fac.length) { + return d_fac[(int) x]; + } else { + throw new MathException(MathException.OVERFLOW); + } + } + + public double logFactorial(long x) { + if (x < d_fac.length) { + return Math.log(d_fac[(int) x]); + } else { + double s=LFAC_MAX; + for (long l=d_fac.length; l<=x; ++l) + s+=Math.log(l); + return s; + } + } + + private final long[] l_fac = new long[]{1L, 1L, 2L, 6L, 24L, 120L, 720L, 5040L, 40320L, 362880L, 3628800L, 39916800L, 479001600L, + 6227020800L, 87178291200L, 1307674368000L, 20922789888000L, 355687428096000L, 6402373705728000L, + 121645100408832000L, 2432902008176640000L + }; + + private final double[] d_fac = new double[]{ + 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0, 3628800.0, + 39916800.0, 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, + 20922789888000.0, 355687428096000.0, 6402373705728000.0, 121645100408832000.0, + 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, 25852016738884976640000.0, + 620448401733239439360000.0, 15511210043330985984000000.0, 403291461126605635584000000.0, + 10888869450418352160768000000.0, 304888344611713860501504000000.0, 8841761993739701954543616000000.0, 265252859812191058636308480000000.0, + 8222838654177922817725562880000000.0, + 263130836933693530167218012160000000.0, + 8683317618811886495518194401280000000.0, + 2.95232799039604140847618609644e38, + 1.03331479663861449296666513375e40, + 3.71993326789901217467999448151e41, + 1.37637530912263450463159795816e43, + 5.23022617466601111760007224100e44, + 2.03978820811974433586402817399e46, + 8.15915283247897734345611269600e47, + 3.34525266131638071081700620534e49, + 1.40500611775287989854314260624e51, + 6.04152630633738356373551320685e52, + 2.65827157478844876804362581101e54, + 1.19622220865480194561963161496e56, + 5.50262215981208894985030542880e57, + 2.58623241511168180642964355154e59, + 1.24139155925360726708622890474e61, + 6.08281864034267560872252163321e62, + 3.04140932017133780436126081661e64, + 1.55111875328738228022424301647e66, + 8.06581751709438785716606368564e67, + 4.27488328406002556429801375339e69, + 2.30843697339241380472092742683e71, + 1.26964033536582759259651008476e73, + 7.10998587804863451854045647464e74, + 4.05269195048772167556806019054e76, + 2.35056133128287857182947491052e78, + 1.38683118545689835737939019720e80, + 8.32098711274139014427634118320e81, + 5.07580213877224798800856812177e83, + 3.14699732603879375256531223550e85, + 1.982608315404440064116146708360e87, + 1.268869321858841641034333893350e89, + 8.247650592082470666723170306800e90, + 5.443449390774430640037292402480e92, + 3.647111091818868528824985909660e94, + 2.480035542436830599600990418570e96, + 1.711224524281413113724683388810e98, + 1.197857166996989179607278372170e100, + 8.504785885678623175211676442400e101, + 6.123445837688608686152407038530e103, + 4.470115461512684340891257138130e105, + 3.307885441519386412259530282210e107, + 2.480914081139539809194647711660e109, + 1.885494701666050254987932260860e111, + 1.451830920282858696340707840860e113, + 1.132428117820629783145752115870e115, + 8.946182130782975286851441715400e116, + 7.156945704626380229481153372320e118, + 5.797126020747367985879734231580e120, + 4.753643337012841748421382069890e122, + 3.945523969720658651189747118010e124, + 3.314240134565353266999387579130e126, + 2.817104114380550276949479442260e128, + 2.422709538367273238176552320340e130, + 2.107757298379527717213600518700e132, + 1.854826422573984391147968456460e134, + 1.650795516090846108121691926250e136, + 1.485715964481761497309522733620e138, + 1.352001527678402962551665687590e140, + 1.243841405464130725547532432590e142, + 1.156772507081641574759205162310e144, + 1.087366156656743080273652852570e146, + 1.032997848823905926259970209940e148, + 9.916779348709496892095714015400e149, + 9.619275968248211985332842594960e151, + 9.426890448883247745626185743100e153, + 9.332621544394415268169923885600e155, + 9.33262154439441526816992388563e157, + 9.42594775983835942085162312450e159, + 9.61446671503512660926865558700e161, + 9.90290071648618040754671525458e163, + 1.02990167451456276238485838648e166, + 1.08139675824029090050410130580e168, + 1.146280563734708354534347384148e170, + 1.226520203196137939351751701040e172, + 1.324641819451828974499891837120e174, + 1.443859583202493582204882102460e176, + 1.588245541522742940425370312710e178, + 1.762952551090244663872161047110e180, + 1.974506857221074023536820372760e182, + 2.231192748659813646596607021220e184, + 2.543559733472187557120132004190e186, + 2.925093693493015690688151804820e188, + 3.393108684451898201198256093590e190, + 3.96993716080872089540195962950e192, + 4.68452584975429065657431236281e194, + 5.57458576120760588132343171174e196, + 6.68950291344912705758811805409e198, + 8.09429852527344373968162284545e200, + 9.87504420083360136241157987140e202, + 1.21463043670253296757662432419e205, + 1.50614174151114087979501416199e207, + 1.88267717688892609974376770249e209, + 2.37217324288004688567714730514e211, + 3.01266001845765954480997707753e213, + 3.85620482362580421735677065923e215, + 4.97450422247728744039023415041e217, + 6.46685548922047367250730439554e219, + 8.47158069087882051098456875820e221, + 1.11824865119600430744996307608e224, + 1.48727070609068572890845089118e226, + 1.99294274616151887673732419418e228, + 2.69047270731805048359538766215e230, + 3.65904288195254865768972722052e232, + 5.01288874827499166103492629211e234, + 6.91778647261948849222819828311e236, + 9.61572319694108900419719561353e238, + 1.34620124757175246058760738589e241, + 1.89814375907617096942852641411e243, + 2.69536413788816277658850750804e245, + 3.85437071718007277052156573649e247, + 5.55029383273930478955105466055e249, + 8.04792605747199194484902925780e251, + 1.17499720439091082394795827164e254, + 1.72724589045463891120349865931e256, + 2.55632391787286558858117801578e258, + 3.80892263763056972698595524351e260, + 5.71338395644585459047893286526e262, + 8.62720977423324043162318862650e264, + 1.31133588568345254560672467123e267, + 2.00634390509568239477828874699e269, + 3.08976961384735088795856467036e271, + 4.78914290146339387633577523906e273, + 7.47106292628289444708380937294e275, + 1.17295687942641442819215807155e278, + 1.85327186949373479654360975305e280, + 2.94670227249503832650433950735e282, + 4.71472363599206132240694321176e284, + 7.59070505394721872907517857094e286, + 1.22969421873944943411017892849e289, + 2.00440157654530257759959165344e291, + 3.28721858553429622726333031164e293, + 5.42391066613158877498449501421e295, + 9.00369170577843736647426172359e297, + 1.50361651486499904020120170784e300, + 2.52607574497319838753801886917e302, + 4.26906800900470527493925188890e304, + 7.25741561530799896739672821113e306 + }; + + private final double LFAC_MAX=Math.log(7.25741561530799896739672821113e306); + } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/stats/likelihood/Likelihood.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/stats/likelihood/Likelihood.java index 82c057ff..cb6d5562 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/stats/likelihood/Likelihood.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/stats/likelihood/Likelihood.java @@ -209,7 +209,7 @@ default double factor() { */ default DoubleSeq deviances() { double f = factor(); - DoubleSeq e = e(); + DoubleSeq e = e().select(x->Double.isFinite(x)); if (f == 1) { return e; } else { diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/timeseries/simplets/analysis/RevisionHistory.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/timeseries/simplets/analysis/RevisionHistory.java index d1b6cd2a..74752108 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/timeseries/simplets/analysis/RevisionHistory.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/java/jdplus/toolkit/base/core/timeseries/simplets/analysis/RevisionHistory.java @@ -146,7 +146,7 @@ public TsData referenceSeries(Function extractor) { } /** - * + * * @param start * @param extractor * @return @@ -261,20 +261,12 @@ public T tsInfo(TsDomain domain) { } } - // / - // / Returns the value of the time series identified by "item" at a given - // point ("period"), - // / starting from a given date (start). - // / In a formal way: - // / - // / Y = { Info([p0, p1])(period)}, p1 >= start - // / - // / The identifier of the series - // / The period of interest - // / The first period - // / /** - * + * Returns the values of the time series generated by the given extractor at the given period. + * So, the results always refer to the same information (point in a timeseries, computed at successive moments + * We start to compute those values at the processing corresponding to "start. + * More formally, we get the series + * Y = { fn(P}[period] }, P = procssinge(p), p >= start * @param period * @param start * @param extractor @@ -282,8 +274,10 @@ public T tsInfo(TsDomain domain) { */ public TsData tsRevision(TsPeriod period, TsPeriod start, Function extractor) { TsPeriod p0 = m_domainT.getStartPeriod(); - int pos = p0.until(period); - double[] x = new double[start.until(m_domainT.getEndPeriod())]; + int n = start.until(m_domainT.getEndPeriod()); + if (n <= 0) + return null; + double[] x = new double[n]; int len = p0.until(start) + 1; for (int i = 0; i < x.length; ++i, ++len) { TsDomain rdom = TsDomain.of(p0, len); @@ -291,7 +285,7 @@ public TsData tsRevision(TsPeriod period, TsPeriod start, Function ex if (output != null) { TsData t = extractor.apply(output); if (t != null) { - x[i] = t.getValue(pos); + x[i] = t.getDoubleValue(period); } else { x[i] = Double.NaN; } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/resources/bematrix.txt b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/resources/bematrix.txt deleted file mode 100644 index bdc8c0ad..00000000 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/resources/bematrix.txt +++ /dev/null @@ -1,93 +0,0 @@ -9.673 -1.071 0.285 0.311 11.900 24.300 1.409 71527.163 11.178 1.933 n -9.588 -1.108 0.491 0.194 -0.028 2.700 22.800 0.398 71870.248 11.183 -4.767 0.479657767 -9.673 -0.892 0.385 0.307 -0.310 0.600 23.400 -0.408 72400.798 11.190 -9.333 0.738205509 -9.832 -1.045 0.286 0.324 0.654 -4.633 22.900 -0.715 72666.355 11.194 -11.533 0.366787039 -9.866 -1.757 0.401 0.685 -0.497 -10.000 10.100 0.686 72520.090 11.192 14.474 0.900 -13.533 -0.201282792 -9.661 -1.525 0.340 0.645 0.932 -7.167 11.000 -0.544 73072.889 11.199 15.525 -0.490 7.261 -11.967 0.762269913 -9.412 -1.551 0.236 -0.216 -0.032 -8.433 7.500 0.032 73438.755 11.204 16.122 -0.976 3.846 -8.300 0.500686268 -9.222 -1.296 0.537 1.022 -0.049 -1.967 15.300 -0.589 74017.699 11.212 18.353 0.347 13.834 -5.333 0.788336061 -9.134 -0.871 0.108 0.359 0.663 -4.000 17.400 1.147 74709.604 11.221 17.956 -1.681 -2.160 -3.433 0.934783509 -9.155 0.056 0.082 0.125 -0.623 5.033 11.900 0.664 75818.633 11.236 15.788 0.913 -12.077 -1.600 1.484452958 -9.280 0.367 0.057 0.266 -0.469 4.200 6.600 1.108 76478.003 11.245 16.942 1.838 7.312 2.133 0.869666637 -9.324 0.371 0.232 0.366 -0.241 7.667 3.900 -0.667 76915.812 11.250 16.661 2.186 -1.662 4.967 0.572464911 -9.426 0.054 0.506 0.040 1.051 8.467 0.800 -0.502 77120.339 11.253 12.953 2.346 -22.255 3.100 0.26590918 -9.429 -0.204 0.157 0.498 0.081 6.233 11.600 -0.949 77376.722 11.256 12.069 1.563 -6.826 2.433 0.332445464 -9.379 -0.491 0.559 0.114 1.014 4.000 8.900 -0.902 77619.748 11.260 11.118 -0.127 -7.873 -1.000 0.314082684 -9.139 -0.854 0.032 -0.030 0.361 -5.800 3.500 -1.313 77812.205 11.262 9.425 -1.274 -15.226 -7.033 0.2479475 -8.972 -0.473 0.574 0.550 0.372 -5.300 4.100 0.467 78636.331 11.273 9.888 -1.095 4.903 -5.900 1.059121888 -8.899 0.249 -0.033 0.161 0.079 -4.800 9.500 0.652 79695.183 11.286 14.501 -1.524 46.663 -1.200 1.34651787 -8.126 1.078 0.409 0.288 0.073 0.967 17.900 1.971 80843.050 11.300 19.388 -0.738 33.700 1.167 1.440321293 -7.682 1.660 0.176 0.637 0.099 7.033 6.500 2.234 81796.510 11.312 23.170 0.430 19.503 6.100 1.179396995 -7.108 1.804 0.083 0.589 0.105 11.367 18.700 1.750 82407.648 11.319 27.141 1.261 17.140 7.900 0.747144441 -6.817 1.881 0.671 1.005 -0.460 13.400 13.200 2.390 82950.036 11.326 28.440 2.210 4.785 8.100 0.658176822 -6.877 1.706 0.137 0.807 0.625 15.867 17.000 1.780 83279.659 11.330 33.516 1.917 17.849 6.167 0.397375512 -6.649 2.037 0.499 0.957 0.752 15.900 17.400 0.752 84018.389 11.339 34.063 1.149 1.631 4.933 0.887046407 -6.096 1.464 0.306 -0.288 1.087 16.833 18.700 -0.483 83968.813 11.338 27.964 -0.576 -17.905 1.433 -0.059005693 -6.514 0.846 0.827 1.479 1.308 7.133 32.100 1.071 83919.656 11.338 31.220 -1.281 11.644 -5.600 -0.058542406 -6.324 0.079 0.581 0.241 2.027 6.567 36.200 -1.187 83748.140 11.336 28.362 -2.905 -9.154 -9.400 -0.20438127 -7.374 -0.542 0.890 0.426 1.086 -1.167 45.600 -1.526 83698.841 11.335 21.588 -3.542 -23.885 -14.233 -0.058865389 -7.349 -0.284 0.604 0.415 0.085 -3.300 22.100 -0.433 84478.433 11.344 24.131 -1.996 11.782 -9.833 0.931425269 -7.272 0.055 0.163 0.171 0.001 6.333 9.200 0.643 85220.217 11.353 27.285 -1.970 13.070 -5.900 0.878074316 -7.491 0.080 0.425 0.177 -0.662 3.867 0.900 -0.782 85669.622 11.358 27.358 0.854 0.267 -7.767 0.527345919 -7.977 -0.080 0.182 0.406 -0.003 1.300 0.600 0.170 85935.562 11.361 26.874 2.110 -1.769 -9.433 0.310425245 -8.125 -0.853 0.389 0.812 0.515 2.167 5.900 0.184 85597.110 11.357 29.285 1.711 8.972 -12.367 -0.393843724 -8.080 -1.177 0.581 -0.115 0.932 -4.367 7.900 -1.623 85682.657 11.358 22.974 1.265 -21.551 -15.600 0.099941563 -8.122 -1.212 0.291 0.474 0.542 -5.867 0.000 0.204 86013.111 11.362 25.288 0.076 10.075 -12.467 0.385671612 -8.383 -0.884 0.431 0.458 -0.185 1.133 1.300 0.326 86653.501 11.370 24.738 0.357 -2.176 -6.267 0.744526447 -8.550 0.418 0.247 0.361 -0.874 4.633 11.400 0.566 88004.295 11.385 25.566 1.950 3.345 -3.767 1.558845205 -7.744 0.940 0.282 0.686 -0.763 4.133 8.000 2.383 88867.459 11.395 29.462 3.033 15.240 -0.667 0.980820232 -8.895 1.303 0.270 0.435 -0.047 6.533 17.400 1.331 89643.858 11.404 34.037 3.814 15.530 0.733 0.873659225 -8.348 1.053 0.255 0.797 1.156 12.400 18.600 -0.003 89930.131 11.407 34.027 2.403 -0.029 -0.967 0.31934485 -8.455 0.617 0.390 0.464 -0.466 8.067 13.000 0.831 90286.001 11.411 36.330 1.770 6.768 -3.800 0.395717902 -8.473 0.529 0.206 0.716 0.682 4.667 19.900 0.707 90736.578 11.416 40.983 0.797 12.807 -7.233 0.499055256 -8.499 0.361 0.317 0.822 0.965 2.033 16.900 1.929 91087.986 11.420 50.454 -0.191 23.109 -6.167 0.387283891 -8.442 0.635 0.631 0.464 0.021 4.267 17.900 3.147 91816.680 11.428 47.908 1.414 -5.046 -0.867 0.799988929 -8.553 0.833 0.260 0.585 0.775 5.133 15.300 0.765 92393.698 11.434 51.496 0.157 7.489 2.167 0.628445617 -8.669 0.669 0.455 0.663 0.976 7.667 17.500 -1.189 92695.744 11.437 55.498 -0.414 7.772 5.600 0.326912021 -7.902 1.026 0.393 0.484 -0.159 9.767 19.600 0.256 93476.876 11.445 55.005 0.717 -0.887 6.433 0.84268455 -7.913 1.626 0.194 0.203 0.289 11.567 15.300 -0.540 94484.444 11.456 46.344 0.054 -15.746 6.300 1.077879424 -7.830 2.462 0.457 0.411 0.269 14.633 20.500 -0.268 95699.671 11.469 44.306 1.068 -4.398 5.333 1.286165497 -7.993 2.374 0.421 0.326 1.491 9.100 24.000 1.834 96075.901 11.473 50.984 0.486 15.072 6.533 0.393136801 -7.067 2.670 0.286 0.376 -0.531 11.233 25.500 1.993 96818.042 11.481 54.623 0.221 7.139 5.467 0.772452315 -7.066 2.691 0.211 1.613 0.793 10.633 33.500 1.837 97306.664 11.486 61.443 -0.535 12.484 2.400 0.504680873 -6.914 2.639 0.578 1.452 1.464 13.367 29.800 2.455 97869.146 11.491 64.552 -1.796 5.060 1.700 0.578050599 -6.626 2.361 0.377 1.443 0.967 11.800 16.600 1.912 98025.350 11.493 78.399 -0.866 21.452 -0.733 0.159604793 -7.491 1.462 0.768 0.994 2.045 19.233 22.800 1.804 97532.100 11.488 76.812 -2.948 -2.025 -5.100 -0.503185507 -6.833 -0.984 0.659 -0.357 2.868 6.367 6.400 -4.429 95489.925 11.467 42.404 -5.569 -44.795 -20.733 -2.093849308 -7.768 -2.240 0.366 -0.573 0.382 -3.533 -11.200 -5.280 94392.167 11.455 34.524 -5.129 -18.582 -30.300 -1.149606236 -7.838 -2.621 0.662 -0.243 -0.178 -7.267 -11.100 -1.824 94288.967 11.454 43.373 -4.520 25.630 -27.000 -0.10933084 -7.972 -1.822 0.351 0.071 -0.703 -9.000 -11.500 0.375 95338.652 11.465 47.801 -1.654 10.208 -19.400 1.113263993 -8.087 -1.287 0.276 0.535 -0.292 -6.067 -1.700 0.397 96143.844 11.474 50.724 1.265 6.115 -10.533 0.844559578 -8.567 -1.155 -0.038 0.753 -0.677 -8.033 5.400 2.751 96600.951 11.478 55.429 2.695 9.276 -5.967 0.475440714 -8.417 -0.457 0.533 1.058 0.293 6.700 10.200 3.131 97576.043 11.488 61.910 3.479 11.693 -5.033 1.009402367 -8.379 -0.313 0.189 0.262 0.215 8.467 8.600 1.630 98007.288 11.493 59.181 2.379 -4.408 -4.900 0.441957763 -7.878 -0.191 0.567 1.027 1.033 14.433 19.300 0.781 98411.752 11.497 63.901 1.780 7.975 0.467 0.412687739 -7.083 0.167 0.334 1.002 0.850 17.567 31.100 1.603 99062.700 11.504 76.680 0.380 19.998 5.033 0.661453318 -6.915 0.181 0.243 0.830 0.135 22.567 31.300 1.219 99349.115 11.506 81.388 -0.350 6.140 0.533 0.289125073 -7.516 0.143 0.520 0.676 1.349 10.467 31.800 0.379 99570.800 11.509 79.616 -1.781 -2.177 -6.567 0.223137023 -7.062 -0.041 0.368 0.725 0.507 2.833 26.700 0.929 99637.691 11.509 81.084 -1.139 1.845 -10.333 0.067179305 -7.147 -0.068 0.718 0.962 0.825 10.833 44.000 0.979 99832.306 11.511 90.433 -0.515 11.529 -9.700 0.195322789 -7.294 -0.495 0.340 0.205 1.293 2.367 29.400 0.655 99639.009 11.509 84.984 -2.030 -6.025 -11.000 -0.193621463 -7.508 -0.762 0.367 0.496 0.504 2.300 22.500 0.319 99601.311 11.509 87.946 -1.382 3.485 -11.800 -0.037834178 -8.269 -1.106 0.391 0.591 0.705 -0.333 27.300 -0.018 99481.208 11.508 85.172 -1.568 -3.155 -13.100 -0.120584529 -8.392 -1.613 0.335 0.190 0.493 10.767 29.500 -0.214 99163.244 11.505 85.470 -2.020 0.351 -13.333 -0.319621673 -8.421 -1.365 0.366 0.076 0.300 3.033 25.200 -0.696 99640.153 11.509 78.856 -0.866 -7.739 -13.233 0.480932825 -8.465 -1.117 0.428 0.373 0.236 2.533 23.800 -0.090 100126.819 11.514 83.146 -0.823 5.441 -9.367 0.488424265 -8.498 -1.064 0.448 0.269 0.157 3.167 11.400 -0.421 100423.472 11.517 80.381 -0.087 -3.326 -6.333 0.296276996 -8.637 -1.020 0.197 0.231 -0.062 7.733 11.100 -0.135 100687.738 11.520 78.802 0.077 -1.964 -4.833 0.263151308 -8.551 -1.025 0.489 -0.214 -0.530 2.000 9.700 -1.215 100915.214 11.522 80.088 0.457 1.632 -5.933 0.22592207 -8.457 -0.896 0.304 0.075 0.367 2.233 19.000 -0.922 101297.863 11.526 77.009 1.252 -3.844 -7.233 0.379179237 -8.538 -0.849 0.367 -0.091 0.069 1.667 5.300 -0.416 101617.480 11.529 60.775 0.673 -21.081 -7.000 0.315522152 -8.673 -0.651 0.456 -0.128 -0.524 -2.600 -1.400 -1.783 102057.423 11.533 47.992 1.286 -21.033 -7.500 0.432940166 -8.643 -0.473 0.360 0.818 -0.006 2.100 8.500 0.227 102545.604 11.538 56.184 1.148 17.069 -5.067 0.478338908 -7.978 -0.721 0.405 0.219 -0.344 4.033 14.000 -1.491 102605.770 11.539 45.007 2.012 -19.895 -4.633 0.058672729 -8.721 -0.576 0.582 0.440 0.312 6.433 23.200 -1.872 103081.559 11.543 39.644 2.091 -11.915 -3.733 0.463706228 -8.248 -0.713 0.487 0.065 0.220 -0.867 18.400 -0.390 103345.028 11.546 31.177 0.654 -21.357 -3.700 0.25559217 -8.204 -0.327 0.360 0.889 -0.912 6.467 29.100 -0.394 104090.314 11.553 40.694 2.918 30.523 -1.633 0.721162791 -7.667 -0.562 0.439 0.528 0.511 6.867 19.700 0.462 104191.221 11.554 41.017 1.532 0.796 -1.233 0.09694179 -7.249 -0.645 0.145 0.479 0.284 7.433 18.600 0.768 104458.483 11.557 46.414 1.549 13.156 -1.300 0.256511007 -7.654 -0.291 0.454 1.039 0.160 5.933 25.000 2.064 105208.920 11.564 50.825 2.656 9.504 -0.800 0.718407611 -7.326 -0.167 0.448 -0.042 0.979 8.000 22.200 -0.355 105710.021 11.568 45.617 -0.216 -10.246 -1.267 0.476291443 -7.047 -0.315 0.488 0.438 0.456 8.167 18.500 -0.421 105891.125 11.570 44.049 -0.211 -3.437 -1.800 0.171321474 -6.394 -0.223 0.063 0.556 0.078 10.333 19.600 0.510 106472.210 11.576 52.207 -0.046 18.521 0.700 0.548756513 - 0.597 106816.202 11.579 54.467 4.328 1.433 0.323081895 diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/resources/mssf1 b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/resources/mssf1 deleted file mode 100644 index bcc44948..00000000 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/main/resources/mssf1 +++ /dev/null @@ -1,93 +0,0 @@ -9.673 -1.071 0.285 0.311 11.9 24.3 1.409 71527.163 11.178 n n n 1.933 n -9.588 -1.108 0.491 0.194 -0.028 2.7 22.8 0.398 71870.248 11.183 -4.767 0.479657767 -9.673 -0.892 0.385 0.307 -0.31 0.6 23.4 -0.408 72400.798 11.19 -9.333 0.738205509 -9.832 -1.045 0.286 0.324 0.654 -4.633 22.9 -0.715 72666.355 11.194 -11.533 0.366787039 -9.866 -1.757 0.401 0.685 -0.497 -10 10.1 0.686 72520.09 11.192 14.474 0.9 -13.533 -0.201282792 -9.661 -1.525 0.34 0.645 0.932 -7.167 11 -0.544 73072.889 11.199 15.525 -0.49 7.261 -11.967 0.762269913 -9.412 -1.551 0.236 -0.216 -0.032 -8.433 7.5 0.032 73438.755 11.204 16.122 -0.976 3.846 -8.3 0.500686268 -9.222 -1.296 0.537 1.022 -0.049 -1.967 15.3 -0.589 74017.699 11.212 18.353 0.347 13.834 -5.333 0.788336061 -9.134 -0.871 0.108 0.359 0.663 -4 17.4 1.147 74709.604 11.221 17.956 -1.681 -2.16 -3.433 0.934783509 -9.155 0.056 0.082 0.125 -0.623 5.033 11.9 0.664 75818.633 11.236 15.788 0.913 -12.077 -1.6 1.484452958 -9.28 0.367 0.057 0.266 -0.469 4.2 6.6 1.108 76478.003 11.245 16.942 1.838 7.312 2.133 0.869666637 -9.324 0.371 0.232 0.366 -0.241 7.667 3.9 -0.667 76915.812 11.25 16.661 2.186 -1.662 4.967 0.572464911 -9.426 0.054 0.506 0.04 1.051 8.467 0.8 -0.502 77120.339 11.253 12.953 2.346 -22.255 3.1 0.26590918 -9.429 -0.204 0.157 0.498 0.081 6.233 11.6 -0.949 77376.722 11.256 12.069 1.563 -6.826 2.433 0.332445464 -9.379 -0.491 0.559 0.114 1.014 4 8.9 -0.902 77619.748 11.26 11.118 -0.127 -7.873 -1 0.314082684 -9.139 -0.854 0.032 -0.03 0.361 -5.8 3.5 -1.313 77812.205 11.262 9.425 -1.274 -15.226 -7.033 0.2479475 -8.972 -0.473 0.574 0.55 0.372 -5.3 4.1 0.467 78636.331 11.273 9.888 -1.095 4.903 -5.9 1.059121888 -8.899 0.249 -0.033 0.161 0.079 -4.8 9.5 0.652 79695.183 11.286 14.501 -1.524 46.663 -1.2 1.34651787 -8.126 1.078 0.409 0.288 0.073 0.967 17.9 1.971 80843.05 11.3 19.388 -0.738 33.7 1.167 1.440321293 -7.682 1.66 0.176 0.637 0.099 7.033 6.5 2.234 81796.51 11.312 23.17 0.43 19.503 6.1 1.179396995 -7.108 1.804 0.083 0.589 0.105 11.367 18.7 1.75 82407.648 11.319 27.141 1.261 17.14 7.9 0.747144441 -6.817 1.881 0.671 1.005 -0.46 13.4 13.2 2.39 82950.036 11.326 28.44 2.21 4.785 8.1 0.658176822 -6.877 1.706 0.137 0.807 0.625 15.867 17 1.78 83279.659 11.33 33.516 1.917 17.849 6.167 0.397375512 -6.649 2.037 0.499 0.957 0.752 15.9 17.4 0.752 84018.389 11.339 34.063 1.149 1.631 4.933 0.887046407 -6.096 1.464 0.306 -0.288 1.087 16.833 18.7 -0.483 83968.813 11.338 27.964 -0.576 -17.905 1.433 -0.059005693 -6.514 0.846 0.827 1.479 1.308 7.133 32.1 1.071 83919.656 11.338 31.22 -1.281 11.644 -5.6 -0.058542406 -6.324 0.079 0.581 0.241 2.027 6.567 36.2 -1.187 83748.14 11.336 28.362 -2.905 -9.154 -9.4 -0.20438127 -7.374 -0.542 0.89 0.426 1.086 -1.167 45.6 -1.526 83698.841 11.335 21.588 -3.542 -23.885 -14.233 -0.058865389 -7.349 -0.284 0.604 0.415 0.085 -3.3 22.1 -0.433 84478.433 11.344 24.131 -1.996 11.782 -9.833 0.931425269 -7.272 0.055 0.163 0.171 0.001 6.333 9.2 0.643 85220.217 11.353 27.285 -1.97 13.07 -5.9 0.878074316 -7.491 0.08 0.425 0.177 -0.662 3.867 0.9 -0.782 85669.622 11.358 27.358 0.854 0.267 -7.767 0.527345919 -7.977 -0.08 0.182 0.406 -0.003 1.3 0.6 0.17 85935.562 11.361 26.874 2.11 -1.769 -9.433 0.310425245 -8.125 -0.853 0.389 0.812 0.515 2.167 5.9 0.184 85597.11 11.357 29.285 1.711 8.972 -12.367 -0.393843724 -8.08 -1.177 0.581 -0.115 0.932 -4.367 7.9 -1.623 85682.657 11.358 22.974 1.265 -21.551 -15.6 0.099941563 -8.122 -1.212 0.291 0.474 0.542 -5.867 0 0.204 86013.111 11.362 25.288 0.076 10.075 -12.467 0.385671612 -8.383 -0.884 0.431 0.458 -0.185 1.133 1.3 0.326 86653.501 11.37 24.738 0.357 -2.176 -6.267 0.744526447 -8.55 0.418 0.247 0.361 -0.874 4.633 11.4 0.566 88004.295 11.385 25.566 1.95 3.345 -3.767 1.558845205 -7.744 0.94 0.282 0.686 -0.763 4.133 8 2.383 88867.459 11.395 29.462 3.033 15.24 -0.667 0.980820232 -8.895 1.303 0.27 0.435 -0.047 6.533 17.4 1.331 89643.858 11.404 34.037 3.814 15.53 0.733 0.873659225 -8.348 1.053 0.255 0.797 1.156 12.4 18.6 -0.003 89930.131 11.407 34.027 2.403 -0.029 -0.967 0.31934485 -8.455 0.617 0.39 0.464 -0.466 8.067 13 0.831 90286.001 11.411 36.33 1.77 6.768 -3.8 0.395717902 -8.473 0.529 0.206 0.716 0.682 4.667 19.9 0.707 90736.578 11.416 40.983 0.797 12.807 -7.233 0.499055256 -8.499 0.361 0.317 0.822 0.965 2.033 16.9 1.929 91087.986 11.42 50.454 -0.191 23.109 -6.167 0.387283891 -8.442 0.635 0.631 0.464 0.021 4.267 17.9 3.147 91816.68 11.428 47.908 1.414 -5.046 -0.867 0.799988929 -8.553 0.833 0.26 0.585 0.775 5.133 15.3 0.765 92393.698 11.434 51.496 0.157 7.489 2.167 0.628445617 -8.669 0.669 0.455 0.663 0.976 7.667 17.5 -1.189 92695.744 11.437 55.498 -0.414 7.772 5.6 0.326912021 -7.902 1.026 0.393 0.484 -0.159 9.767 19.6 0.256 93476.876 11.445 55.005 0.717 -0.887 6.433 0.84268455 -7.913 1.626 0.194 0.203 0.289 11.567 15.3 -0.54 94484.444 11.456 46.344 0.054 -15.746 6.3 1.077879424 -7.83 2.462 0.457 0.411 0.269 14.633 20.5 -0.268 95699.671 11.469 44.306 1.068 -4.398 5.333 1.286165497 -7.993 2.374 0.421 0.326 1.491 9.1 24 1.834 96075.901 11.473 50.984 0.486 15.072 6.533 0.393136801 -7.067 2.67 0.286 0.376 -0.531 11.233 25.5 1.993 96818.042 11.481 54.623 0.221 7.139 5.467 0.772452315 -7.066 2.691 0.211 1.613 0.793 10.633 33.5 1.837 97306.664 11.486 61.443 -0.535 12.484 2.4 0.504680873 -6.914 2.639 0.578 1.452 1.464 13.367 29.8 2.455 97869.146 11.491 64.552 -1.796 5.06 1.7 0.578050599 -6.626 2.361 0.377 1.443 0.967 11.8 16.6 1.912 98025.35 11.493 78.399 -0.866 21.452 -0.733 0.159604793 -7.491 1.462 0.768 0.994 2.045 19.233 22.8 1.804 97532.1 11.488 76.812 -2.948 -2.025 -5.1 -0.503185507 -6.833 -0.984 0.659 -0.357 2.868 6.367 6.4 -4.429 95489.925 11.467 42.404 -5.569 -44.795 -20.733 -2.093849308 -7.768 -2.24 0.366 -0.573 0.382 -3.533 -11.2 -5.28 94392.167 11.455 34.524 -5.129 -18.582 -30.3 -1.149606236 -7.838 -2.621 0.662 -0.243 -0.178 -7.267 -11.1 -1.824 94288.967 11.454 43.373 -4.52 25.63 -27 -0.10933084 -7.972 -1.822 0.351 0.071 -0.703 -9 -11.5 0.375 95338.652 11.465 47.801 -1.654 10.208 -19.4 1.113263993 -8.087 -1.287 0.276 0.535 -0.292 -6.067 -1.7 0.397 96143.844 11.474 50.724 1.265 6.115 -10.533 0.844559578 -8.567 -1.155 -0.038 0.753 -0.677 -8.033 5.4 2.751 96600.951 11.478 55.429 2.695 9.276 -5.967 0.475440714 -8.417 -0.457 0.533 1.058 0.293 6.7 10.2 3.131 97576.043 11.488 61.91 3.479 11.693 -5.033 1.009402367 -8.379 -0.313 0.189 0.262 0.215 8.467 8.6 1.63 98007.288 11.493 59.181 2.379 -4.408 -4.9 0.441957763 -7.878 -0.191 0.567 1.027 1.033 14.433 19.3 0.781 98411.752 11.497 63.901 1.78 7.975 0.467 0.412687739 -7.083 0.167 0.334 1.002 0.85 17.567 31.1 1.603 99062.7 11.504 76.68 0.38 19.998 5.033 0.661453318 -6.915 0.181 0.243 0.83 0.135 22.567 31.3 1.219 99349.115 11.506 81.388 -0.35 6.14 0.533 0.289125073 -7.516 0.143 0.52 0.676 1.349 10.467 31.8 0.379 99570.8 11.509 79.616 -1.781 -2.177 -6.567 0.223137023 -7.062 -0.041 0.368 0.725 0.507 2.833 26.7 0.929 99637.691 11.509 81.084 -1.139 1.845 -10.333 0.067179305 -7.147 -0.068 0.718 0.962 0.825 10.833 44 0.979 99832.306 11.511 90.433 -0.515 11.529 -9.7 0.195322789 -7.294 -0.495 0.34 0.205 1.293 2.367 29.4 0.655 99639.009 11.509 84.984 -2.03 -6.025 -11 -0.193621463 -7.508 -0.762 0.367 0.496 0.504 2.3 22.5 0.319 99601.311 11.509 87.946 -1.382 3.485 -11.8 -0.037834178 -8.269 -1.106 0.391 0.591 0.705 -0.333 27.3 -0.018 99481.208 11.508 85.172 -1.568 -3.155 -13.1 -0.120584529 -8.392 -1.613 0.335 0.19 0.493 10.767 29.5 -0.214 99163.244 11.505 85.47 -2.02 0.351 -13.333 -0.319621673 -8.421 -1.365 0.366 0.076 0.3 3.033 25.2 -0.696 99640.153 11.509 78.856 -0.866 -7.739 -13.233 0.480932825 -8.465 -1.117 0.428 0.373 0.236 2.533 23.8 -0.09 100126.819 11.514 83.146 -0.823 5.441 -9.367 0.488424265 -8.498 -1.064 0.448 0.269 0.157 3.167 11.4 -0.421 100423.472 11.517 80.381 -0.087 -3.326 -6.333 0.296276996 -8.637 -1.02 0.197 0.231 -0.062 7.733 11.1 -0.135 100687.738 11.52 78.802 0.077 -1.964 -4.833 0.263151308 -8.551 -1.025 0.489 -0.214 -0.53 2 9.7 -1.215 100915.214 11.522 80.088 0.457 1.632 -5.933 0.22592207 -8.457 -0.896 0.304 0.075 0.367 2.233 19 -0.922 101297.863 11.526 77.009 1.252 -3.844 -7.233 0.379179237 -8.538 -0.849 0.367 -0.091 0.069 1.667 5.3 -0.416 101617.48 11.529 60.775 0.673 -21.081 -7 0.315522152 -8.673 -0.651 0.456 -0.128 -0.524 -2.6 -1.4 -1.783 102057.423 11.533 47.992 1.286 -21.033 -7.5 0.432940166 -8.643 -0.473 0.36 0.818 -0.006 2.1 8.5 0.227 102545.604 11.538 56.184 1.148 17.069 -5.067 0.478338908 -7.978 -0.721 0.405 0.219 -0.344 4.033 14 -1.491 102605.77 11.539 45.007 2.012 -19.895 -4.633 0.058672729 -8.721 -0.576 0.582 0.44 0.312 6.433 23.2 -1.872 103081.559 11.543 39.644 2.091 -11.915 -3.733 0.463706228 -8.248 -0.713 0.487 0.065 0.22 -0.867 18.4 -0.39 103345.028 11.546 31.177 0.654 -21.357 -3.7 0.25559217 -8.204 -0.327 0.36 0.889 -0.912 6.467 29.1 -0.394 104090.314 11.553 40.694 2.918 30.523 -1.633 0.721162791 -7.667 -0.562 0.439 0.528 0.511 6.867 19.7 0.462 104191.221 11.554 41.017 1.532 0.796 -1.233 0.09694179 -7.249 -0.645 0.145 0.479 0.284 7.433 18.6 0.768 104458.483 11.557 46.414 1.549 13.156 -1.3 0.256511007 -7.654 -0.291 0.454 1.039 0.16 5.933 25 2.064 105208.92 11.564 50.825 2.656 9.504 -0.8 0.718407611 -7.326 -0.167 0.448 -0.042 0.979 8 22.2 -0.355 105710.021 11.568 45.617 -0.216 -10.246 -1.267 0.476291443 -7.047 -0.315 0.488 0.438 0.456 8.167 18.5 -0.421 105891.125 11.57 44.049 -0.211 -3.437 -1.8 0.171321474 -6.394 -0.223 0.063 0.556 0.078 10.333 19.6 0.51 106472.21 11.576 52.207 -0.046 18.521 0.7 0.548756513 - 0.597 106816.202 11.579 54.467 4.328 1.433 0.323081895 diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/test/java/jdplus/toolkit/base/core/dstats/PoissonTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/test/java/jdplus/toolkit/base/core/dstats/PoissonTest.java new file mode 100644 index 00000000..9e7058e8 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-core/src/test/java/jdplus/toolkit/base/core/dstats/PoissonTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.base.core.dstats; + +import jdplus.toolkit.base.api.dstats.RandomNumberGenerator; +import jdplus.toolkit.base.core.random.MersenneTwister; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author palatej + */ +public class PoissonTest { + + public PoissonTest() { + } + + @Test + public void testProb() { + Poisson p=new Poisson(10); + double s=0; + for (int i=0; i<100; ++i){ + s+=p.getProbability(i); + } + assertEquals(1, s, 1e-9); + } + + @Test + public void testRandom() { + RandomNumberGenerator rnd=MersenneTwister.fromSystemNanoTime(); + Poisson p=new Poisson(20); + int[] h=new int[100]; + long N=10000; + for (long i=0; i eu.europa.ec.joinup.sat jdplus-toolkit-base-parent - 3.0.2 + 3.1.0 jdplus-toolkit-base-information diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/pom.xml b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/pom.xml index 748fb856..8d757b1f 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/pom.xml +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-toolkit-base-parent - 3.0.2 + 3.1.0 jdplus-toolkit-base-protobuf diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/jdplus/toolkit/base/protobuf/toolkit/ModellingContextProto.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/jdplus/toolkit/base/protobuf/toolkit/ModellingContextProto.java index 4290e70e..e0f74e18 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/jdplus/toolkit/base/protobuf/toolkit/ModellingContextProto.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/jdplus/toolkit/base/protobuf/toolkit/ModellingContextProto.java @@ -19,7 +19,6 @@ import jdplus.toolkit.base.api.timeseries.DynamicTsDataSupplier; import jdplus.toolkit.base.api.timeseries.StaticTsDataSupplier; import jdplus.toolkit.base.api.timeseries.TsDataSupplier; -import jdplus.toolkit.base.api.timeseries.TsMoniker; import jdplus.toolkit.base.api.timeseries.calendars.CalendarDefinition; import jdplus.toolkit.base.api.timeseries.calendars.CalendarManager; import jdplus.toolkit.base.api.timeseries.regression.ModellingContext; @@ -36,25 +35,14 @@ public class ModellingContextProto { public final String R = "r", RPREFIX = "r@"; - public ToolkitProtos.TsMoniker convert(TsMoniker moniker) { - return ToolkitProtos.TsMoniker.newBuilder() - .setSource(moniker.getSource()) - .setId(moniker.getId()) - .build(); - } - - public TsMoniker convert(ToolkitProtos.TsMoniker moniker) { - return TsMoniker.of(moniker.getSource(), moniker.getId()); - } - - public ToolkitProtos.TsDataSuppliers.Item convert(String name, TsDataSupplier supplier) { + public ToolkitProtos.TsDataSuppliers.Item convert(String name, TsDataSupplier supplier) { ToolkitProtos.TsDataSuppliers.Item.Builder builder = ToolkitProtos.TsDataSuppliers.Item.newBuilder(); builder.setName(name); if (supplier instanceof StaticTsDataSupplier s) { builder.setData(ToolkitProtosUtility.convert(s.getData())); } else if (supplier instanceof DynamicTsDataSupplier s) { ToolkitProtos.DynamicTsData.Builder dbuilder=ToolkitProtos.DynamicTsData.newBuilder(); - dbuilder.setMoniker(convert(s.getMoniker())); + dbuilder.setMoniker(ToolkitProtosUtility.convert(s.getMoniker())); dbuilder.setCurrent(ToolkitProtosUtility.convert(s.get())); builder.setDynamicData(dbuilder.build()); } @@ -73,7 +61,7 @@ public TsDataSupplier convert(ToolkitProtos.TsDataSuppliers.Item supplier) { if (supplier.hasData()) { return new StaticTsDataSupplier(ToolkitProtosUtility.convert(supplier.getData())); } else if (supplier.hasDynamicData()) { - return new DynamicTsDataSupplier(convert(supplier.getDynamicData().getMoniker()), ToolkitProtosUtility.convert(supplier.getDynamicData().getCurrent())); + return new DynamicTsDataSupplier(ToolkitProtosUtility.convert(supplier.getDynamicData().getMoniker()), ToolkitProtosUtility.convert(supplier.getDynamicData().getCurrent())); } else { return null; } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/jdplus/toolkit/base/protobuf/toolkit/ToolkitProtosUtility.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/jdplus/toolkit/base/protobuf/toolkit/ToolkitProtosUtility.java index 52159ae9..6b9e8e3d 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/jdplus/toolkit/base/protobuf/toolkit/ToolkitProtosUtility.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/jdplus/toolkit/base/protobuf/toolkit/ToolkitProtosUtility.java @@ -37,6 +37,9 @@ import jdplus.toolkit.base.protobuf.modelling.ModellingProtos; import org.checkerframework.checker.nullness.qual.NonNull; import jdplus.toolkit.base.api.math.matrices.Matrix; +import jdplus.toolkit.base.api.timeseries.Ts; +import jdplus.toolkit.base.api.timeseries.TsCollection; +import jdplus.toolkit.base.api.timeseries.TsMoniker; /** * @@ -284,6 +287,86 @@ public ToolkitProtos.TsData convert(TsData s) { .build(); } + public ToolkitProtos.TsData convert(TsData s, String name) { + if (s == null || s.isEmpty()) { + return ToolkitProtos.TsData.getDefaultInstance() + .toBuilder().setName(name) + .build(); + } + + TsPeriod start = s.getStart(); + return ToolkitProtos.TsData.newBuilder() + .setAnnualFrequency(s.getAnnualFrequency()) + .setStartYear(start.year()) + .setStartPeriod(start.annualPosition() + 1) + .addAllValues(Iterables.of(s.getValues())) + .setName(name) + .build(); + } + + public ToolkitProtos.TsMoniker convert(TsMoniker moniker) { + return ToolkitProtos.TsMoniker.newBuilder() + .setSource(moniker.getSource()) + .setId(moniker.getId()) + .build(); + } + + public TsMoniker convert(ToolkitProtos.TsMoniker moniker) { + return TsMoniker.of(moniker.getSource(), moniker.getId()); + } + + public ToolkitProtos.Ts convert(Ts s) { + if (s == null) { + return ToolkitProtos.Ts.getDefaultInstance(); + } + + return ToolkitProtos.Ts.newBuilder() + .setName(s.getName()) + .setMoniker(convert(s.getMoniker())) + .setData(convert(s.getData())) + .putAllMetadata(s.getMeta()) + .build(); + } + + public ToolkitProtos.TsCollection convert(TsCollection s) { + if (s == null) { + return ToolkitProtos.TsCollection.getDefaultInstance(); + } + + return ToolkitProtos.TsCollection.newBuilder() + .setName(s.getName()) + .setMoniker(convert(s.getMoniker())) + .putAllMetadata(s.getMeta()) + .addAllSeries(s.getItems().stream().map(t->convert(t)).toList()) + .build(); + } + + public Ts convert(ToolkitProtos.Ts s) { + if (s == null) { + return null; + } + + return Ts.builder() + .name(s.getName()) + .moniker(convert(s.getMoniker())) + .data(convert(s.getData())) + .meta(s.getMetadataMap()) + .build(); + } + + public TsCollection convert(ToolkitProtos.TsCollection s) { + if (s == null) { + return null; + } + + return TsCollection.builder() + .name(s.getName()) + .moniker(convert(s.getMoniker())) + .meta(s.getMetadataMap()) + .items(s.getSeriesList().stream().map(t->convert(t)).toList()) + .build(); + } + public ToolkitProtos.Matrix convert(Matrix m) { if (m == null || m.isEmpty()) { return ToolkitProtos.Matrix.getDefaultInstance(); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/module-info.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/module-info.java index 23865731..79f48103 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/module-info.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/java/module-info.java @@ -6,7 +6,7 @@ requires static org.checkerframework.checker.qual; requires jdplus.toolkit.base.core; - requires com.google.protobuf; + requires protobuf.java; exports jdplus.toolkit.base.protobuf.modelling; exports jdplus.toolkit.base.protobuf.regarima; diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/proto/toolkit.proto b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/proto/toolkit.proto index c9423396..e6c883eb 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/proto/toolkit.proto +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-protobuf/src/main/proto/toolkit.proto @@ -351,6 +351,20 @@ message TsMoniker{ string id = 2; } +message Ts{ + string name=1; + TsMoniker moniker = 2; + map metadata= 3; + TsData data = 4; +} + +message TsCollection{ + string name=1; + TsMoniker moniker = 2; + map metadata = 3; + repeated Ts series = 4; +} + message DynamicTsData{ TsMoniker moniker = 1; TsData current = 2; diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/pom.xml b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/pom.xml index 068d9759..a618a392 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/pom.xml +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-toolkit-base-parent - 3.0.2 + 3.1.0 jdplus-toolkit-base-r diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/arima/SarimaModels.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/arima/SarimaModels.java index 4858bf44..23f062d2 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/arima/SarimaModels.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/arima/SarimaModels.java @@ -12,16 +12,25 @@ import jdplus.toolkit.base.protobuf.regarima.RegArimaEstimationProto; import java.util.function.DoubleUnaryOperator; +import jdplus.toolkit.base.api.arima.SarimaOrders; +import jdplus.toolkit.base.api.arima.SarmaOrders; +import jdplus.toolkit.base.api.data.Parameter; +import jdplus.toolkit.base.api.data.ParameterType; import jdplus.toolkit.base.core.arima.ArimaModel; import jdplus.toolkit.base.core.arima.ArimaSeriesGenerator; import jdplus.toolkit.base.core.arima.AutoCovarianceFunction; +import jdplus.toolkit.base.core.data.DataBlock; import jdplus.toolkit.base.core.dstats.Normal; import jdplus.toolkit.base.core.dstats.T; +import jdplus.toolkit.base.core.math.linearfilters.BackFilter; import jdplus.toolkit.base.core.math.matrices.FastMatrix; +import jdplus.toolkit.base.core.random.XorshiftRNG; import jdplus.toolkit.base.core.regarima.RegArimaEstimation; import jdplus.toolkit.base.core.regarima.RegArimaModel; import jdplus.toolkit.base.core.regsarima.RegSarimaComputer; import jdplus.toolkit.base.core.sarima.SarimaModel; +import jdplus.toolkit.base.core.sarima.SarimaUtility; +import jdplus.toolkit.base.core.sarima.estimation.HannanRissanen; import jdplus.toolkit.base.core.sarima.estimation.SarimaMapping; import jdplus.toolkit.base.protobuf.regarima.RegArimaProtos; @@ -56,12 +65,13 @@ public SarimaModel of(int period, double[] phi, int d, double[] theta, double[] * @param btheta * @param stde * @param tdegree Degrees of T-Stat. O if normal is used - * @return + * @param seed If seed < 0, use random seeds @return */ - public double[] random(int length, int period, double[] phi, int d, double[] theta, double[] bphi, int bd, double[] btheta, double stde, int tdegree) { + public double[] random(int length, int period, double[] phi, int d, double[] theta, double[] bphi, int bd, double[] btheta, double stde, int tdegree, int seed) { if (stde == 0) { stde = 1; } + XorshiftRNG rnd = seed < 0 ? XorshiftRNG.fromSystemNanoTime() : new XorshiftRNG(seed); SarimaModel sarima = SarimaModel.builder(period) .differencing(d, bd) .phi(phi) @@ -69,7 +79,7 @@ public double[] random(int length, int period, double[] phi, int d, double[] the .bphi(bphi) .btheta(btheta) .build(); - ArimaSeriesGenerator generator = ArimaSeriesGenerator.builder() + ArimaSeriesGenerator generator = ArimaSeriesGenerator.builder(rnd) .distribution(tdegree <= 0 ? new Normal(0, stde) : new T(tdegree)) .startMean(10 * stde) .startStdev(stde) @@ -77,22 +87,76 @@ public double[] random(int length, int period, double[] phi, int d, double[] the return generator.generate(sarima, length); } - public RegArimaEstimation estimate(double[] data, int[] regular, int period, int[] seasonal, boolean mean, Matrix X, double[] parameters, double eps) { - SarimaSpec.Builder builder = SarimaSpec.builder() - .period(period) - .p(regular[0]) - .d(regular[1]) - .q(regular[2]); + public SarimaModel hannanRissanen(double[] data, int[] regular, int period, int[] seasonal, String initialization, boolean biasCorrection, boolean finalCorrection) { + SarimaOrders spec = new SarimaOrders(period); + spec.setRegular(regular[0], regular[1], regular[2]); + BackFilter ur; if (seasonal != null) { - builder - .bp(seasonal[0]) - .bd(seasonal[1]) - .bq(seasonal[2]); + spec.setSeasonal(seasonal[0], seasonal[1], seasonal[2]); + ur = SarimaUtility.differencingFilter(period, regular[1], seasonal[1]); + } else { + ur = SarimaUtility.differencingFilter(1, regular[1], 0); } - - // TODO. Fix parameters, if any - if (parameters != null) { + SarmaOrders dspec = spec.doStationary(); + HannanRissanen hr = HannanRissanen.builder() + .initialization(HannanRissanen.Initialization.valueOf(initialization)) + .biasCorrection(biasCorrection) + .finalCorrection(finalCorrection) + .build(); + int d = ur.getDegree(); + DataBlock x; + if (d > 0) { + double[] tmp = new double[data.length - d]; + x = DataBlock.of(tmp); + ur.apply(DataBlock.of(data), x); + } else { + x = DataBlock.of(data); + } + hr.process(x, dspec); + SarimaModel model = hr.getModel(); + if (d >0) + model=model.toBuilder().differencing(spec.getD(), spec.getBd()).build(); + return model; + } + + public RegArimaEstimation estimate(double[] data, int[] regular, int period, int[] seasonal, boolean mean, Matrix X, double[] parameters, double eps) { + SarimaSpec.Builder builder = SarimaSpec.builder() + .period(period); + + if (parameters != null) { + int cur = 0; + int p = regular[0]; + if (p > 0) { + builder.phi(Parameter.of(DoubleSeq.of(parameters, cur, p), ParameterType.Fixed)); + cur += p; + } + int q = regular[2]; + if (q > 0) { + builder.theta(Parameter.of(DoubleSeq.of(parameters, cur, q), ParameterType.Fixed)); + cur += q; + } + if (seasonal != null) { + int bp = seasonal[0]; + if (bp > 0) { + builder.bphi(Parameter.of(DoubleSeq.of(parameters, cur, bp), ParameterType.Fixed)); + cur += bp; + } + int bq = seasonal[2]; + if (bq > 0) { + builder.theta(Parameter.of(DoubleSeq.of(parameters, cur, bq), ParameterType.Fixed)); + } + } + } else { + builder.p(regular[0]) + .d(regular[1]) + .q(regular[2]); + if (seasonal != null) { + builder + .bp(seasonal[0]) + .bd(seasonal[1]) + .bq(seasonal[2]); + } } SarimaSpec sarima = builder.build(); @@ -122,8 +186,8 @@ public double[] spectrum(SarimaModel m, int n) { } return g; } - - public ArimaModel convert(SarimaModel model){ + + public ArimaModel convert(SarimaModel model) { return ArimaModel.of(model); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/stats/Tests.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/stats/Tests.java index 785afbeb..472f30f5 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/stats/Tests.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/stats/Tests.java @@ -10,10 +10,13 @@ import java.util.function.IntToDoubleFunction; import jdplus.toolkit.base.api.stats.AutoCovariances; import jdplus.toolkit.base.core.stats.InverseAutoCorrelations; +import jdplus.toolkit.base.core.stats.RobustStandardDeviationComputer; import jdplus.toolkit.base.core.stats.tests.BowmanShenton; import jdplus.toolkit.base.core.stats.tests.DoornikHansen; import jdplus.toolkit.base.core.stats.tests.JarqueBera; +import jdplus.toolkit.base.core.stats.tests.Kurtosis; import jdplus.toolkit.base.core.stats.tests.LjungBox; +import jdplus.toolkit.base.core.stats.tests.Skewness; import jdplus.toolkit.base.core.stats.tests.TestOfRuns; import jdplus.toolkit.base.core.stats.tests.TestOfUpDownRuns; @@ -51,6 +54,14 @@ public double[] inverseAutocorrelations(double[] data, int nar, int n){ return iac; } + public StatisticalTest skewness(double[] data){ + return new Skewness(DoubleSeq.of(data)).build(); + } + + public StatisticalTest kurtosis(double[] data){ + return new Kurtosis(DoubleSeq.of(data)).build(); + } + public StatisticalTest bowmanShenton(double[] data){ return new BowmanShenton(DoubleSeq.of(data)).build(); } @@ -86,5 +97,9 @@ public StatisticalTest ljungBox(double[] data, int k, int lag, int nhp, int sign .build(); } + public static double mad(double[] data, double centile, boolean mdedianCorrected){ + return RobustStandardDeviationComputer.mad(centile, mdedianCorrected).compute(DoubleSeq.of(data)); + } + } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/timeseries/Revisions.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/timeseries/Revisions.java new file mode 100644 index 00000000..f253b60a --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/timeseries/Revisions.java @@ -0,0 +1,125 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.base.r.timeseries; + +import java.time.LocalDate; +import java.util.List; +import jdplus.toolkit.base.api.information.Explorable; +import jdplus.toolkit.base.api.stats.StatisticalTest; +import jdplus.toolkit.base.api.timeseries.TsData; +import jdplus.toolkit.base.api.timeseries.TsDataTable; +import jdplus.toolkit.base.api.timeseries.TsDomain; +import jdplus.toolkit.base.api.timeseries.TsPeriod; +import jdplus.toolkit.base.api.timeseries.TsUnit; +import jdplus.toolkit.base.api.timeseries.regression.RegressionItem; +import jdplus.toolkit.base.core.timeseries.simplets.analysis.DiagnosticInfo; +import jdplus.toolkit.base.core.timeseries.simplets.analysis.RevisionHistory; + +/** + * + * @author palatej + * @param + */ +@lombok.Value +public class Revisions { + + RevisionHistory revisions; + + public TsDomain referenceDomain() { + return revisions.getReferenceDomain(); + } + + public T result(String period) { + LocalDate date = LocalDate.parse(period); + TsDomain referenceDomain = revisions.getReferenceDomain(); + int id = referenceDomain.indexOf(date.atStartOfDay()); + if (id < 0) { + return null; + } + TsDomain cur = referenceDomain.range(0, id + 1); + return revisions.tsInfo(cur); + } + + public TsData history(String id, String start) { + LocalDate date = LocalDate.parse(start); + TsDomain referenceDomain = revisions.getReferenceDomain(); + TsPeriod pstart = TsPeriod.of(referenceDomain.getTsUnit(), date); + return revisions.revision(pstart, rslt -> toDouble(rslt.getData(id, Object.class))); + } + + public TsData tsHistory(String id, String period, String start) { + LocalDate date = LocalDate.parse(start), refDate = LocalDate.parse(period); + TsDomain referenceDomain = revisions.getReferenceDomain(); + TsPeriod pstart = TsPeriod.of(referenceDomain.getTsUnit(), date), + pref = TsPeriod.of(referenceDomain.getTsUnit(), refDate); + return revisions.tsRevision(pref, pstart, rslt -> rslt.getData(id, TsData.class)); + } + + public TsDataTable tsSelect(String id, String start, String end) { + LocalDate d0 = LocalDate.parse(start), d1 = LocalDate.parse(end); + List sel = revisions.select(d0, d1, r -> r.getData(id, TsData.class)); + TsDataTable table = TsDataTable.of(sel); + return table; + } + + public TsDomain referenceDomain(String id) { + TsData data = revisions.getReferenceInfo().getData(id, TsData.class); + return data == null ? null : data.getDomain(); + } + + public TsData diagnosticOf(String id, String start, String end, String diag) { + LocalDate d0 = LocalDate.parse(start), d1 = LocalDate.parse(end); + TsUnit unit = revisions.getReferenceDomain().getTsUnit(); + TsPeriod p0 = TsPeriod.of(unit, d0), p1 = TsPeriod.of(unit, d1); + TsDomain domain = TsDomain.of(p0, p0.until(p1) + 1); + if (domain.isEmpty()) { + return null; + } + DiagnosticInfo info = DiagnosticInfo.valueOf(diag); + double[] revs = new double[domain.length()]; + for (int i = 0; i < revs.length; ++i) { + revs[i] = revisions.seriesRevision(p0.plus(i), info, rslt -> rslt.getData(id, TsData.class)); + } + return TsData.ofInternal(p0, revs); + } + + public static double toDouble(Object obj) { + if (obj == null) { + return Double.NaN; + } + if (obj instanceof Double dobj) { + return dobj; + } + if (obj instanceof Integer iobj) { + return iobj.doubleValue(); + } + if (obj instanceof Boolean bobj) { + return bobj ? 1 : 0; + } + if (obj instanceof StatisticalTest tobj) { + return tobj.getPvalue(); + } + if (obj instanceof RegressionItem robj) { + return robj.getCoefficient(); + } + if (obj instanceof double[] aobj) { + return aobj.length == 1 ? aobj[0] : Double.NaN; + } + + return Double.NaN; + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/timeseries/TsUtility.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/timeseries/TsUtility.java index 96dcbace..54e55d27 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/timeseries/TsUtility.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/main/java/jdplus/toolkit/base/r/timeseries/TsUtility.java @@ -16,6 +16,7 @@ */ package jdplus.toolkit.base.r.timeseries; +import com.google.protobuf.InvalidProtocolBufferException; import jdplus.toolkit.base.api.data.AggregationType; import jdplus.toolkit.base.api.timeseries.CalendarPeriodObs; import jdplus.toolkit.base.api.timeseries.CalendarTimeSeries; @@ -25,8 +26,17 @@ import jdplus.toolkit.base.api.timeseries.TsUnit; import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; +import jdplus.toolkit.base.api.timeseries.Ts; +import jdplus.toolkit.base.api.timeseries.TsCollection; +import jdplus.toolkit.base.api.timeseries.TsDataTable; +import jdplus.toolkit.base.api.timeseries.TsFactory; +import jdplus.toolkit.base.api.timeseries.TsInformationType; +import jdplus.toolkit.base.api.timeseries.TsMoniker; +import jdplus.toolkit.base.protobuf.toolkit.ToolkitProtos; +import jdplus.toolkit.base.protobuf.toolkit.ToolkitProtosUtility; /** * @@ -35,6 +45,11 @@ @lombok.experimental.UtilityClass public class TsUtility { + public void updateProviders() { + TsFactory nfactory = TsFactory.ofServiceLoader(); + TsFactory.setDefault(nfactory); + } + public TsData of(int freq, int year, int start, double[] data) { switch (freq) { case 1 -> { @@ -84,6 +99,10 @@ public int[] startPeriod(TsData s) { return of(s.getStart()); } + public int[] startPeriod(TsDataTable s) { + return of(s.getDomain().getStartPeriod()); + } + public int[] of(TsPeriod p) { LocalDate start = p.start().toLocalDate(); int freq = p.getUnit().getAnnualFrequency(); @@ -119,8 +138,71 @@ public CalendarTimeSeries of(String[] starts, String[] ends, double[] data) { } return CalendarTimeSeries.of(entries); } - + public TsData cleanExtremities(TsData s) { return s.cleanExtremities(); } + + public byte[] toBuffer(Ts s){ + return ToolkitProtosUtility.convert(s).toByteArray(); + } + + public Ts tsOfBytes(byte[] bytes) throws InvalidProtocolBufferException{ + return ToolkitProtosUtility.convert(ToolkitProtos.Ts.parseFrom(bytes)); + } + + public byte[] toBuffer(TsCollection s){ + return ToolkitProtosUtility.convert(s).toByteArray(); + } + + public TsCollection tsCollectionOfBytes(byte[] bytes) throws InvalidProtocolBufferException{ + return ToolkitProtosUtility.convert(ToolkitProtos.TsCollection.parseFrom(bytes)); + } + + private String dayOf(TsPeriod p, int pos){ + switch (pos){ + case 0 -> { + return p.start().toLocalDate().format(DateTimeFormatter.ISO_DATE); + } + case 2 -> { + return p.end().toLocalDate().minusDays(1).format(DateTimeFormatter.ISO_DATE); + } + default -> { + LocalDate d0=p.start().toLocalDate(), d1=p.end().toLocalDate(); + return d0.plusDays(d0.until(d1, ChronoUnit.DAYS)/2).format(DateTimeFormatter.ISO_DATE); + } + + } + } + + /** + * + * @param domain + * @param pos 0 for first day, 1 for middle day, 2 for last day + * @return + */ + public String[] daysOf(TsDomain domain, int pos){ + String[] days=new String[domain.size()]; + for (int i=0; i cproviders = new ArrayList<>(TsFactory.getDefault().getProviders().toList()); + for (TsProvider p : providers) { + if (p != null) { + cproviders.add(p); + } + } + TsFactory.setDefault(TsFactory.of(cproviders)); + } + + public ObsGathering obsGathering(int period, String aggregationType, boolean allowPartialAggregation, boolean includeMissing) { + if (period <= 0 && !includeMissing) { + return ObsGathering.DEFAULT; + } + ObsGathering.Builder builder = ObsGathering.builder().includeMissingValues(includeMissing); + if (period > 0) { + builder.unit(TsUnit.ofAnnualFrequency(period)) + .allowPartialAggregation(allowPartialAggregation) + .aggregationType(AggregationType.valueOf(aggregationType)); + } + return builder.build(); + } + +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/test/java/jdplus/toolkit/base/r/arima/SarimaModelsTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/test/java/jdplus/toolkit/base/r/arima/SarimaModelsTest.java index 986e3bad..8a90e415 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/test/java/jdplus/toolkit/base/r/arima/SarimaModelsTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-r/src/test/java/jdplus/toolkit/base/r/arima/SarimaModelsTest.java @@ -23,7 +23,7 @@ public SarimaModelsTest() { @Test public void testRandom() { - double[] rnd = SarimaModels.random(200, 12, new double[]{-.2, -.5}, 1, new double[]{-.5}, null, 1, new double[]{-.8}, 1, 5); + double[] rnd = SarimaModels.random(200, 12, new double[]{-.2, -.5}, 1, new double[]{-.5}, null, 1, new double[]{-.8}, 1, 5, -1); // System.out.println(DoubleSeq.of(rnd)); assertTrue(rnd.length == 200); } @@ -35,5 +35,15 @@ public void testArima() { byte[] buffer = SarimaModels.toBuffer(estimate); assertTrue(buffer != null); } + + @Test + public void testHR(){ + RegArimaEstimation estimate = SarimaModels.estimate(Data.ABS_RETAIL, new int[]{3, 1, 1}, 12, new int[]{0, 1, 1}, false, null, null, 1e-9); +// System.out.println(estimate.getModel().arima()); + SarimaModel hr = SarimaModels.hannanRissanen(Data.ABS_RETAIL, new int[]{3, 1, 1}, 12, new int[]{0, 1, 1}, "Ols", true, false); +// System.out.println(hr); + hr = SarimaModels.hannanRissanen(Data.ABS_RETAIL, new int[]{3, 1, 1}, 12, new int[]{0, 1, 1}, "Ols", true, true); +// System.out.println(hr); + } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/pom.xml b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/pom.xml index 5fa36c73..e2d43ea2 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/pom.xml +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-toolkit-base-parent - 3.0.2 + 3.1.0 jdplus-toolkit-base-tsp @@ -28,6 +28,17 @@ java-io-base ${java-io-util.version} + + com.github.ben-manes.caffeine + caffeine + 3.1.8 + + + * + * + + + diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/DefaultTsMeta.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/DefaultTsMeta.java index 4bcd6beb..60b9b0d4 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/DefaultTsMeta.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/DefaultTsMeta.java @@ -22,6 +22,7 @@ import java.util.function.Function; import nbbrd.io.text.Formatter; import nbbrd.io.text.Parser; +import org.checkerframework.checker.nullness.qual.NonNull; /** * @@ -42,23 +43,23 @@ public final class DefaultTsMeta implements TsMeta { private final Formatter formatter; @Override - public T load(Map meta) { + public T load(@NonNull Map meta) { return load(meta::get); } @Override - public T load(Function meta) { + public T load(@NonNull Function meta) { String text = meta.apply(key); return text != null ? parser.parse(text) : null; } @Override - public void store(Map meta, T value) { + public void store(@NonNull Map meta, @NonNull T value) { store(meta::put, value); } @Override - public void store(BiConsumer meta, T value) { + public void store(@NonNull BiConsumer meta, @NonNull T value) { String text = formatter.formatAsString(value); meta.accept(key, text); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/InternalTsProvider.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/InternalTsProvider.java index 68a21ed4..3f84d265 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/InternalTsProvider.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/InternalTsProvider.java @@ -18,9 +18,8 @@ import jdplus.toolkit.base.api.timeseries.TsMoniker; import jdplus.toolkit.base.tsp.*; -import jdplus.toolkit.base.tsp.util.DataSourcePreconditions; -import jdplus.toolkit.base.api.util.List2; import jdplus.toolkit.base.tsp.fixme.Strings; +import jdplus.toolkit.base.tsp.util.DataSourcePreconditions; import nbbrd.io.text.Formatter; import nbbrd.io.text.Parser; import org.checkerframework.checker.nullness.qual.NonNull; @@ -87,7 +86,7 @@ public DataDisplayNameSupport(String providerName, Formatter dataSou } @Override - public String getDisplayName(DataSource dataSource) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSource dataSource) throws IllegalArgumentException { checkProvider(dataSource); String result = dataSourceFormatter.formatAsString(dataSource); if (result == null) { @@ -97,7 +96,7 @@ public String getDisplayName(DataSource dataSource) throws IllegalArgumentExcept } @Override - public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSet dataSet) throws IllegalArgumentException { checkProvider(dataSet); String result = dataSetFormatter.formatAsString(dataSet); if (result == null) { @@ -123,7 +122,7 @@ public DataMonikerSupport(String providerName, Formatter dataSourceF } @Override - public TsMoniker toMoniker(DataSource dataSource) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSource dataSource) throws IllegalArgumentException { checkProvider(dataSource); String id = dataSourceFormatter.formatAsString(dataSource); if (id == null) { @@ -133,7 +132,7 @@ public TsMoniker toMoniker(DataSource dataSource) throws IllegalArgumentExceptio } @Override - public TsMoniker toMoniker(DataSet dataSet) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSet dataSet) throws IllegalArgumentException { checkProvider(dataSet); String id = dataSetFormatter.formatAsString(dataSet); if (id == null) { @@ -143,13 +142,13 @@ public TsMoniker toMoniker(DataSet dataSet) throws IllegalArgumentException { } @Override - public Optional toDataSet(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSet(@NonNull TsMoniker moniker) throws IllegalArgumentException { checkProvider(moniker); return dataSetParser.parseValue(moniker.getId()); } @Override - public Optional toDataSource(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSource(@NonNull TsMoniker moniker) throws IllegalArgumentException { checkProvider(moniker); return dataSourceParser.parseValue(moniker.getId()); } @@ -167,12 +166,12 @@ public DataSourceBeanSupport(String providerName, DataSource.Converter param, } @Override - public T newBean() { + public @NonNull T newBean() { return param.getDefaultValue(); } @Override - public DataSource encodeBean(Object bean) throws IllegalArgumentException { + public @NonNull DataSource encodeBean(@NonNull Object bean) throws IllegalArgumentException { Objects.requireNonNull(bean); try { DataSource.Builder result = DataSource.builder(providerName, version); @@ -184,7 +183,7 @@ public DataSource encodeBean(Object bean) throws IllegalArgumentException { } @Override - public T decodeBean(DataSource dataSource) throws IllegalArgumentException { + public @NonNull T decodeBean(@NonNull DataSource dataSource) throws IllegalArgumentException { checkProvider(dataSource); return param.get(dataSource); } @@ -198,31 +197,31 @@ public static final class DataSourceListSupport extends ProviderPart implements public DataSourceListSupport(String providerName, Iterable dataSources, Consumer cacheCleaner) { super(providerName); - this.dataSources = StreamSupport.stream(dataSources.spliterator(), false).collect(List2.toUnmodifiableList()); + this.dataSources = StreamSupport.stream(dataSources.spliterator(), false).toList(); this.eventSupport = DataSourceEventSupport.create(); this.cacheCleaner = Objects.requireNonNull(cacheCleaner); dataSources.forEach(this::checkProvider); } @Override - public void reload(DataSource dataSource) { + public void reload(@NonNull DataSource dataSource) { checkProvider(dataSource); cacheCleaner.accept(dataSource); eventSupport.fireChanged(dataSource); } @Override - public List getDataSources() { + public @NonNull List getDataSources() { return dataSources; } @Override - public void addDataSourceListener(DataSourceListener listener) { + public void addDataSourceListener(@NonNull DataSourceListener listener) { eventSupport.add(listener); } @Override - public void removeDataSourceListener(DataSourceListener listener) { + public void removeDataSourceListener(@NonNull DataSourceListener listener) { eventSupport.remove(listener); } } @@ -241,14 +240,14 @@ public DataSourceMutableListSupport(String providerName, LinkedHashSet getDataSources() { + public @NonNull List getDataSources() { synchronized (dataSources) { - return List2.copyOf(dataSources); + return List.copyOf(dataSources); } } @Override - public void addDataSourceListener(DataSourceListener listener) { + public void addDataSourceListener(@NonNull DataSourceListener listener) { eventSupport.add(listener); } @Override - public void removeDataSourceListener(DataSourceListener listener) { + public void removeDataSourceListener(@NonNull DataSourceListener listener) { eventSupport.remove(listener); } } @@ -330,13 +329,13 @@ public NoOpDataHierarchy(String providerName) { } @Override - public List children(DataSource dataSource) throws IllegalArgumentException, IOException { + public @NonNull List children(@NonNull DataSource dataSource) throws IllegalArgumentException, IOException { checkProvider(dataSource); return Collections.emptyList(); } @Override - public List children(DataSet parent) throws IllegalArgumentException, IOException { + public @NonNull List children(@NonNull DataSet parent) throws IllegalArgumentException, IOException { checkProvider(parent); return Collections.emptyList(); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/stream/NoOpTsStream.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/stream/NoOpTsStream.java index 3c5b6fc0..30c05d4a 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/stream/NoOpTsStream.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/stream/NoOpTsStream.java @@ -22,6 +22,7 @@ import jdplus.toolkit.base.tsp.stream.DataSetTs; import jdplus.toolkit.base.tsp.stream.HasTsStream; import jdplus.toolkit.base.tsp.util.DataSourcePreconditions; +import org.checkerframework.checker.nullness.qual.NonNull; import java.io.IOException; import java.util.Objects; @@ -37,14 +38,14 @@ public final class NoOpTsStream implements HasTsStream { private final String providerName; @Override - public Stream getData(DataSource dataSource, TsInformationType type) throws IllegalArgumentException, IOException { + public @NonNull Stream getData(@NonNull DataSource dataSource, @NonNull TsInformationType type) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(providerName, dataSource); Objects.requireNonNull(type); return Stream.empty(); } @Override - public Stream getData(DataSet dataSet, TsInformationType type) throws IllegalArgumentException, IOException { + public @NonNull Stream getData(@NonNull DataSet dataSet, @NonNull TsInformationType type) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(providerName, dataSet); Objects.requireNonNull(type); return Stream.empty(); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/CaffeineCaching.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/CaffeineCaching.java new file mode 100644 index 00000000..e1a63b48 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/CaffeineCaching.java @@ -0,0 +1,54 @@ +package internal.toolkit.base.tsp.util; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.Ticker; +import jdplus.toolkit.base.tsp.util.ShortLivedCache; +import jdplus.toolkit.base.tsp.util.ShortLivedCaching; +import lombok.NonNull; +import nbbrd.design.VisibleForTesting; +import nbbrd.service.ServiceProvider; + +import java.io.File; +import java.time.Duration; + +@ServiceProvider +public final class CaffeineCaching implements ShortLivedCaching { + + public CaffeineCaching() { + this(Ticker.systemTicker()); + } + + private final @NonNull Ticker ticker; + + @VisibleForTesting + CaffeineCaching(@NonNull Ticker ticker) { + this.ticker = ticker; + } + + @Override + public @NonNull String getId() { + return "caffeine"; + } + + @Override + public @NonNull ShortLivedCache ofTtl(@NonNull Duration ttl) { + Cache result = Caffeine + .newBuilder() + .ticker(ticker) + .expireAfterWrite(ttl) + .softValues() + .build(); + return new SimpleMapCache<>(result.asMap()); + } + + @Override + public @NonNull ShortLivedCache ofFile(@NonNull File file) { + Cache result = Caffeine + .newBuilder() + .ticker(ticker) + .softValues() + .build(); + return new FileMapCache<>(result.asMap(), file); + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/DefaultIOCacheFactory.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/DefaultIOCacheFactory.java deleted file mode 100644 index 710b214b..00000000 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/DefaultIOCacheFactory.java +++ /dev/null @@ -1,100 +0,0 @@ -package internal.toolkit.base.tsp.util; - -import jdplus.toolkit.base.tsp.util.IOCache; -import jdplus.toolkit.base.tsp.util.IOCacheFactory; -import nbbrd.design.VisibleForTesting; -import nbbrd.service.ServiceProvider; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; - -import java.io.File; -import java.io.IOException; -import java.time.Clock; -import java.time.Duration; -import java.time.Instant; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.BiPredicate; - -@ServiceProvider -public final class DefaultIOCacheFactory implements IOCacheFactory { - - @Override - public @NonNull IOCache ofTtl(@NonNull Duration ttl) { - return new DefaultIOCache<>(new ConcurrentHashMap<>(), Clock.systemDefaultZone(), ttlValidator(ttl)); - } - - @Override - public @NonNull IOCache ofFile(@NonNull File file) { - return new DefaultIOCache<>(new ConcurrentHashMap<>(), Clock.systemDefaultZone(), fileValidator(file)); - } - - @VisibleForTesting - @FunctionalInterface - interface Validator extends BiPredicate> { - } - - @VisibleForTesting - static Validator ttlValidator(Duration ttl) { - Objects.requireNonNull(ttl); - return (clock, holder) -> clock.instant().isBefore(holder.getCreationTime().plus(ttl)); - } - - @VisibleForTesting - static Validator fileValidator(File file) { - Objects.requireNonNull(file); - return (clock, holder) -> file.exists() && file.lastModified() <= holder.getCreationTime().toEpochMilli(); - } - - @VisibleForTesting - @lombok.RequiredArgsConstructor - static final class DefaultIOCache implements IOCache { - - @lombok.NonNull - private final ConcurrentMap> cache; - - @lombok.NonNull - private final Clock clock; - - @lombok.NonNull - private final Validator validator; - - @Override - public void put(@NonNull K key, @NonNull V value) { - Objects.requireNonNull(key); - Objects.requireNonNull(value); - cache.put(key, new ValueHolder<>(value, clock.instant())); - } - - @Override - public @Nullable V get(@NonNull K key) { - Objects.requireNonNull(key); - ValueHolder result = cache.get(key); - if (result == null) { - return null; - } - if (!validator.test(clock, result)) { - cache.remove(key); - return null; - } - return result.getValue(); - } - - @Override - public void close() throws IOException { - cache.clear(); - } - } - - @VisibleForTesting - @lombok.Value - static class ValueHolder { - - @lombok.NonNull - V value; - - @lombok.NonNull - Instant creationTime; - } -} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/FileMapCache.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/FileMapCache.java new file mode 100644 index 00000000..72311d20 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/FileMapCache.java @@ -0,0 +1,38 @@ +package internal.toolkit.base.tsp.util; + +import lombok.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.io.File; +import java.util.Map; + +@lombok.Getter +@lombok.RequiredArgsConstructor +public final class FileMapCache implements MapCache { + + private final @NonNull Map map; + + private final @NonNull File file; + + private long lastModified = Long.MIN_VALUE; + + @Override + public void put(@NonNull K key, @NonNull V value) { + map.put(key, value); + } + + @Override + public @Nullable V get(@NonNull K key) { + V result = map.get(key); + if (result == null) { + return null; + } + long timInMillis = file.lastModified(); + if (timInMillis != lastModified) { + lastModified = timInMillis; + map.clear(); + return null; + } + return result; + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/MapCache.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/MapCache.java new file mode 100644 index 00000000..57951b0f --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/MapCache.java @@ -0,0 +1,13 @@ +package internal.toolkit.base.tsp.util; + +import jdplus.toolkit.base.tsp.util.ShortLivedCache; +import lombok.NonNull; + +import java.util.Map; + +public sealed interface MapCache + extends ShortLivedCache + permits FileMapCache, SimpleMapCache, TtlMapCache { + + @NonNull Map getMap(); +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/MapCaching.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/MapCaching.java new file mode 100644 index 00000000..a871e957 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/MapCaching.java @@ -0,0 +1,40 @@ +package internal.toolkit.base.tsp.util; + +import jdplus.toolkit.base.tsp.util.ShortLivedCache; +import jdplus.toolkit.base.tsp.util.ShortLivedCaching; +import lombok.NonNull; +import nbbrd.design.VisibleForTesting; + +import java.io.File; +import java.time.Duration; +import java.util.HashMap; +import java.util.function.LongSupplier; + +public final class MapCaching implements ShortLivedCaching { + + public MapCaching() { + this(System::nanoTime); + } + + private final LongSupplier ticker; + + @VisibleForTesting + MapCaching(@NonNull LongSupplier ticker) { + this.ticker = ticker; + } + + @Override + public @NonNull String getId() { + return "hashmap"; + } + + @Override + public @NonNull ShortLivedCache ofTtl(@NonNull Duration ttl) { + return new TtlMapCache<>(new HashMap<>(), ticker, ttl); + } + + @Override + public @NonNull ShortLivedCache ofFile(@NonNull File file) { + return new FileMapCache<>(new HashMap<>(), file); + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/SimpleMapCache.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/SimpleMapCache.java new file mode 100644 index 00000000..e05ddf8a --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/SimpleMapCache.java @@ -0,0 +1,23 @@ +package internal.toolkit.base.tsp.util; + +import lombok.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Map; + +@lombok.Getter +@lombok.RequiredArgsConstructor +public final class SimpleMapCache implements MapCache { + + private final @NonNull Map map; + + @Override + public void put(@NonNull K key, @NonNull V value) { + map.put(key, value); + } + + @Override + public @Nullable V get(@NonNull K key) { + return map.get(key); + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/TtlMapCache.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/TtlMapCache.java new file mode 100644 index 00000000..f83640ae --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/internal/toolkit/base/tsp/util/TtlMapCache.java @@ -0,0 +1,47 @@ +package internal.toolkit.base.tsp.util; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import nbbrd.design.VisibleForTesting; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.time.Duration; +import java.util.Map; +import java.util.function.LongSupplier; + +@lombok.Getter +@RequiredArgsConstructor +public final class TtlMapCache implements MapCache { + + private final @NonNull Map> map; + + private final @NonNull LongSupplier ticker; + + private final @NonNull Duration ttl; + + @Override + public void put(@NonNull K key, @NonNull V value) { + map.put(key, new Entry<>(value, ticker.getAsLong())); + } + + @Override + public @Nullable V get(@NonNull K key) { + Entry result = map.get(key); + if (result == null) { + return null; + } + if (!validate(result.creationTime())) { + map.remove(key); + return null; + } + return result.value(); + } + + private boolean validate(long creationTime) { + return ticker.getAsLong() < creationTime + ttl.toNanos(); + } + + @VisibleForTesting + public record Entry(@NonNull V value, long creationTime) { + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/DataSourceFactory.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/DataSourceFactory.java index 3b45acb2..93008657 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/DataSourceFactory.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/DataSourceFactory.java @@ -101,4 +101,9 @@ default Optional getTs(@NonNull DataSet dataSet, @NonNull TsInformationType } }); } + + default boolean open(@lombok.NonNull DataSource dataSource) { + return getProvider(DataSourceLoader.class, dataSource.getProviderName()) + .map(loader -> loader.open(dataSource)).orElse(false); + } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/DataSourceProvider.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/DataSourceProvider.java index b4112037..af168cfe 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/DataSourceProvider.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/DataSourceProvider.java @@ -33,7 +33,7 @@ public interface DataSourceProvider extends TsProvider, HasDataSourceList, HasDataHierarchy, HasDataDisplayName, HasDataMoniker { @Override - default void reload(DataSource dataSource) { + default void reload(@NonNull DataSource dataSource) { clearCache(); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/FileLoader.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/FileLoader.java index 358452fe..0a8c26d7 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/FileLoader.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/FileLoader.java @@ -31,10 +31,12 @@ public interface FileLoader extends DataSourceLoader, FileFilter, HasFilePaths { @Override + @NonNull B newBean(); @Override - B decodeBean(DataSource dataSource) throws IllegalArgumentException; + @NonNull + B decodeBean(@NonNull DataSource dataSource) throws IllegalArgumentException; @NonNull String getFileDescription(); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/HasDataSourceList.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/HasDataSourceList.java index 995ff166..2c5fbc4f 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/HasDataSourceList.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/HasDataSourceList.java @@ -62,7 +62,7 @@ public interface HasDataSourceList { void removeDataSourceListener(@NonNull DataSourceListener listener); @NonNull - public static HasDataSourceList of( + static HasDataSourceList of( @NonNull String providerName, @NonNull Iterable dataSources, @NonNull Consumer cacheCleaner) { @@ -70,7 +70,7 @@ public static HasDataSourceList of( } @NonNull - public static HasDataSourceList of( + static HasDataSourceList of( @NonNull String providerName, @NonNull Iterable dataSources) { return of(providerName, dataSources, InternalTsProvider.DO_NOTHING); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/HasDataSourceMutableList.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/HasDataSourceMutableList.java index b18f86f8..95dc0723 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/HasDataSourceMutableList.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/HasDataSourceMutableList.java @@ -62,12 +62,12 @@ default void closeAll() { } @NonNull - public static HasDataSourceMutableList of(@NonNull String providerName, @NonNull Consumer cacheCleaner) { + static HasDataSourceMutableList of(@NonNull String providerName, @NonNull Consumer cacheCleaner) { return new InternalTsProvider.DataSourceMutableListSupport(providerName, new LinkedHashSet<>(), cacheCleaner); } @NonNull - public static HasDataSourceMutableList of(@NonNull String providerName) { + static HasDataSourceMutableList of(@NonNull String providerName) { return of(providerName, InternalTsProvider.DO_NOTHING); } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/TsMeta.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/TsMeta.java index 5cc8d02f..1dc6557a 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/TsMeta.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/TsMeta.java @@ -1,23 +1,29 @@ /* * Copyright 2018 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved * by the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: - * + * * http://ec.europa.eu/idabc/eupl - * - * Unless required by applicable law or agreed to in writing, software + * + * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and + * See the Licence for the specific language governing permissions and * limitations under the Licence. */ package jdplus.toolkit.base.tsp; -import jdplus.toolkit.base.tsp.util.ObsFormat; import internal.toolkit.base.tsp.DefaultTsMeta; +import jdplus.toolkit.base.tsp.fixme.Strings; +import jdplus.toolkit.base.tsp.util.ObsFormat; +import nbbrd.io.text.Formatter; +import nbbrd.io.text.Parser; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; @@ -25,16 +31,9 @@ import java.util.function.BiConsumer; import java.util.function.Function; -import jdplus.toolkit.base.tsp.fixme.Strings; -import nbbrd.io.text.Formatter; -import nbbrd.io.text.Parser; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; - /** - * - * @author Philippe Charles * @param + * @author Philippe Charles */ public interface TsMeta { @@ -82,55 +81,55 @@ static TsMeta onTimestamp() { // from ec.tss.Ts @Deprecated - static final TsMeta SOURCE_OLD = onString("tsmoniker.source"); + TsMeta SOURCE_OLD = onString("tsmoniker.source"); // from ec.tss.Ts @Deprecated - static final TsMeta ID_OLD = onString("tsmoniker.id"); + TsMeta ID_OLD = onString("tsmoniker.id"); // from ec.tss.Ts @Deprecated - static final TsMeta DYNAMIC = onString("dynamic"); + TsMeta DYNAMIC = onString("dynamic"); // from ec.tss.Ts - static final TsMeta BEG = onDateTime("@beg", "yyyy-MM-dd", Locale.ROOT); + TsMeta BEG = onDateTime("@beg", "yyyy-MM-dd", Locale.ROOT); // from ec.tss.Ts - static final TsMeta END = onDateTime("@end", "yyyy-MM-dd", Locale.ROOT); + TsMeta END = onDateTime("@end", "yyyy-MM-dd", Locale.ROOT); // from ec.tss.Ts - static final TsMeta CONFIDENTIAL = onString("@confidential"); + TsMeta CONFIDENTIAL = onString("@confidential"); // from ec.tstoolkit.MetaData - static final TsMeta DESCRIPTION = onString("@description"); + TsMeta DESCRIPTION = onString("@description"); // from ec.tstoolkit.MetaData - static final TsMeta OWNER = onString("@owner"); + TsMeta OWNER = onString("@owner"); // from ec.tstoolkit.MetaData - static final TsMeta SOURCE = onString("@source"); + TsMeta SOURCE = onString("@source"); // from ec.tstoolkit.MetaData - static final TsMeta ID = onString("@id"); + TsMeta ID = onString("@id"); // from ec.tstoolkit.MetaData - static final TsMeta TIMESTAMP = onTimestamp(); + TsMeta TIMESTAMP = onTimestamp(); // from ec.tstoolkit.MetaData - static final TsMeta DOCUMENT = onString("@document"); + TsMeta DOCUMENT = onString("@document"); // from ec.tstoolkit.MetaData - static final TsMeta SUMMARY = onString("@summary"); + TsMeta SUMMARY = onString("@summary"); // from ec.tstoolkit.MetaData - static final TsMeta NOTE = onString("@note"); + TsMeta NOTE = onString("@note"); // from ec.tstoolkit.MetaData - static final TsMeta TODO = onString("@todo"); + TsMeta TODO = onString("@todo"); // from ec.tstoolkit.MetaData - static final TsMeta ALGORITHM = onString("@algorithm"); + TsMeta ALGORITHM = onString("@algorithm"); // from ec.tstoolkit.MetaData - static final TsMeta QUALITY = onString("@quality"); + TsMeta QUALITY = onString("@quality"); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/BulkCubeConnection.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/BulkCubeConnection.java index 787791c2..6a0956a4 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/BulkCubeConnection.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/BulkCubeConnection.java @@ -16,8 +16,8 @@ */ package jdplus.toolkit.base.tsp.cube; -import jdplus.toolkit.base.tsp.util.IOCache; -import jdplus.toolkit.base.tsp.util.IOCacheFactory; +import jdplus.toolkit.base.tsp.util.ShortLivedCache; +import jdplus.toolkit.base.tsp.util.ShortLivedCaching; import lombok.AccessLevel; import nbbrd.io.IOIterator; import nbbrd.io.Resource; @@ -43,7 +43,7 @@ public final class BulkCubeConnection implements CubeConnection { @NonNull - public static CubeConnection of(@NonNull CubeConnection delegate, @NonNull BulkCube options, @NonNull IOCacheFactory cacheFactory) { + public static CubeConnection of(@NonNull CubeConnection delegate, @NonNull BulkCube options, @NonNull ShortLivedCaching cacheFactory) { return options.isCacheEnabled() ? new BulkCubeConnection(delegate, options.getDepth(), cacheFactory.ofTtl(options.getTtl())) : delegate; @@ -56,14 +56,14 @@ public static CubeConnection of(@NonNull CubeConnection delegate, @NonNull BulkC private final int depth; @lombok.NonNull - private final IOCache> cache; + private final ShortLivedCache> cache; private int getCacheLevel() throws IOException { return Math.max(0, delegate.getRoot().getMaxLevel() - depth); } @Override - public Stream getAllSeriesWithData(CubeId ref) throws IOException { + public @NonNull Stream getAllSeriesWithData(@NonNull CubeId ref) throws IOException { if (!ref.isSeries()) { int cacheLevel = getCacheLevel(); if (ref.getLevel() == cacheLevel) { @@ -79,7 +79,7 @@ public Stream getAllSeriesWithData(CubeId ref) throws IOExce } @Override - public Optional getSeriesWithData(CubeId ref) throws IOException { + public @NonNull Optional getSeriesWithData(@NonNull CubeId ref) throws IOException { if (ref.isSeries()) { int cacheLevel = getCacheLevel(); CubeId ancestor = ref.getAncestor(cacheLevel); @@ -93,53 +93,53 @@ public Optional getSeriesWithData(CubeId ref) throws IOExcep } @Override - public Optional testConnection() { + public @NonNull Optional testConnection() { return delegate.testConnection(); } @Override - public CubeId getRoot() throws IOException { + public @NonNull CubeId getRoot() throws IOException { return delegate.getRoot(); } @Override - public Stream getAllSeries(CubeId id) throws IOException { + public @NonNull Stream getAllSeries(@NonNull CubeId id) throws IOException { return delegate.getAllSeries(id); } @Override - public Optional getSeries(CubeId id) throws IOException { + public @NonNull Optional getSeries(@NonNull CubeId id) throws IOException { return delegate.getSeries(id); } @Override - public Stream getChildren(CubeId id) throws IOException { + public @NonNull Stream getChildren(@NonNull CubeId id) throws IOException { return delegate.getChildren(id); } @Override - public String getDisplayName() throws IOException { + public @NonNull String getDisplayName() throws IOException { return delegate.getDisplayName(); } @Override - public String getDisplayName(CubeId id) throws IOException { + public @NonNull String getDisplayName(@NonNull CubeId id) throws IOException { return delegate.getDisplayName(id); } @Override - public String getDisplayNodeName(CubeId id) throws IOException { + public @NonNull String getDisplayNodeName(@NonNull CubeId id) throws IOException { return delegate.getDisplayNodeName(id); } @Override public void close() throws IOException { - Resource.closeBoth(cache, delegate); + delegate.close(); } @NonNull private static Stream getOrLoad( - @NonNull IOCache> cache, + @NonNull ShortLivedCache> cache, @NonNull CubeId key, @NonNull IOFunction> loader) throws IOException { @@ -160,7 +160,7 @@ private static Stream getOrLoad( private static final class CachingIterator implements IOIterator, Closeable { private final CubeId key; - private final IOCache cache; + private final ShortLivedCache> cache; private final IOIterator delegate; private final Closeable closeable; @@ -179,13 +179,13 @@ public CubeSeriesWithData nextWithIO() throws IOException, NoSuchElementExceptio } @Override - public Stream asStream() { + public @lombok.NonNull Stream asStream() { return IOIterator.super.asStream().onClose(IORunnable.unchecked(this::close)); } @Override public void close() throws IOException { - Resource.closeBoth(this::flushToCache, closeable::close); + Resource.closeBoth(this::flushToCache, closeable); } private void flushToCache() throws IOException { diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/BulkCubeHandler.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/BulkCubeHandler.java index 9b6918ca..15b93496 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/BulkCubeHandler.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/BulkCubeHandler.java @@ -18,7 +18,7 @@ public final class BulkCubeHandler implements PropertyHandler { private final PropertyHandler depth; @Override - public @NonNull BulkCube get(@NonNull Function properties) { + public @NonNull @org.checkerframework.checker.nullness.qual.NonNull BulkCube get(@NonNull @org.checkerframework.checker.nullness.qual.NonNull Function properties) { return BulkCube .builder() .ttl(ttl.get(properties)) @@ -27,7 +27,7 @@ public final class BulkCubeHandler implements PropertyHandler { } @Override - public void set(@NonNull BiConsumer properties, @Nullable BulkCube value) { + public void set(@NonNull @org.checkerframework.checker.nullness.qual.NonNull BiConsumer properties, @Nullable BulkCube value) { if (value != null) { ttl.set(properties, value.getTtl()); depth.set(properties, value.getDepth()); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/CubeSupport.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/CubeSupport.java index 8617f684..189c9b7c 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/CubeSupport.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/CubeSupport.java @@ -63,7 +63,7 @@ public final class CubeSupport implements HasDataHierarchy, HasTsStream, HasData // @Override - public List children(DataSource dataSource) throws IOException { + public @NonNull List children(@NonNull DataSource dataSource) throws IOException { DataSourcePreconditions.checkProvider(providerName, dataSource); try (CubeConnection connection = cube.open(dataSource)) { @@ -91,7 +91,7 @@ public List children(DataSource dataSource) throws IOException { } @Override - public List children(DataSet parent) throws IOException { + public @NonNull List children(@NonNull DataSet parent) throws IOException { DataSourcePreconditions.checkProvider(providerName, parent); if (!DataSet.Kind.COLLECTION.equals(parent.getKind())) { @@ -121,7 +121,7 @@ private static DataSet.Kind getDataSetKind(CubeId cubeId) { // @Override - public Stream getData(DataSource dataSource, TsInformationType type) throws IOException { + public @NonNull Stream getData(@NonNull DataSource dataSource, @NonNull TsInformationType type) throws IOException { DataSourcePreconditions.checkProvider(providerName, dataSource); CubeConnection connection = cube.open(dataSource); @@ -142,7 +142,7 @@ public Stream getData(DataSource dataSource, TsInformationType type) } @Override - public Stream getData(DataSet dataSet, TsInformationType type) throws IOException { + public @NonNull Stream getData(@NonNull DataSet dataSet, @NonNull TsInformationType type) throws IOException { DataSourcePreconditions.checkProvider(providerName, dataSet); CubeConnection connection = cube.open(dataSet.getDataSource()); @@ -168,7 +168,7 @@ public Stream getData(DataSet dataSet, TsInformationType type) throws // @Override - public String getDisplayName(DataSource dataSource) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSource dataSource) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSource); try (CubeConnection connection = cube.open(dataSource)) { @@ -179,7 +179,7 @@ public String getDisplayName(DataSource dataSource) throws IllegalArgumentExcept } @Override - public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSet); try (CubeConnection connection = cube.open(dataSet.getDataSource())) { @@ -191,7 +191,7 @@ public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { } @Override - public String getDisplayNodeName(DataSet dataSet) throws IllegalArgumentException { + public @NonNull String getDisplayNodeName(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(providerName, dataSet); try (CubeConnection connection = cube.open(dataSet.getDataSource())) { @@ -244,12 +244,12 @@ private static final class ByNameParam implements DataSet.Converter { private final CubeId root; @Override - public CubeId getDefaultValue() { + public @NonNull CubeId getDefaultValue() { return root; } @Override - public CubeId get(DataSet config) { + public @NonNull CubeId get(@NonNull DataSet config) { String[] dimValues = new String[root.getMaxLevel()]; int i = 0; while (i < dimValues.length) { @@ -263,7 +263,7 @@ public CubeId get(DataSet config) { } @Override - public void set(DataSet.Builder builder, CubeId value) { + public void set(DataSet.@NonNull Builder builder, CubeId value) { for (int i = 0; i < value.getLevel(); i++) { builder.parameter(value.getDimensionId(i), value.getDimensionValue(i)); } @@ -278,12 +278,12 @@ private static final class BySeparatorParam implements DataSet.Converter private final String name; @Override - public CubeId getDefaultValue() { + public @NonNull CubeId getDefaultValue() { return root; } @Override - public CubeId get(DataSet config) { + public @NonNull CubeId get(@NonNull DataSet config) { String value = config.getParameter(name); if (value == null || value.isEmpty()) { return getDefaultValue(); @@ -300,7 +300,7 @@ public CubeId get(DataSet config) { } @Override - public void set(DataSet.Builder builder, CubeId value) { + public void set(DataSet.@NonNull Builder builder, CubeId value) { if (value.getLevel() > 0) { StringBuilder sb = new StringBuilder(); sb.append(value.getDimensionValue(0)); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/TableAsCubeConnection.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/TableAsCubeConnection.java index 32354f0c..9abc4091 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/TableAsCubeConnection.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/cube/TableAsCubeConnection.java @@ -127,13 +127,13 @@ public interface ChildrenCursor extends TableCursor { private final Resource resource; @Override - public Optional testConnection() { + public @NonNull Optional testConnection() { Exception result = resource.testConnection(); return result != null ? Optional.of(WrappedIOException.wrap(result)) : Optional.empty(); } @Override - public CubeId getRoot() throws IOException { + public @NonNull CubeId getRoot() throws IOException { try { return resource.getRoot(); } catch (Exception ex) { @@ -142,7 +142,7 @@ public CubeId getRoot() throws IOException { } @Override - public Stream getAllSeries(CubeId id) throws IOException { + public @NonNull Stream getAllSeries(@NonNull CubeId id) throws IOException { try { AllSeriesCursor cursor = resource.getAllSeriesCursor(id); return new AllSeriesIterator(id, cursor).asStream(); @@ -152,7 +152,7 @@ public Stream getAllSeries(CubeId id) throws IOException { } @Override - public Stream getAllSeriesWithData(CubeId id) throws IOException { + public @NonNull Stream getAllSeriesWithData(@NonNull CubeId id) throws IOException { try { AllSeriesWithDataCursor cursor = resource.getAllSeriesWithDataCursor(id); return new AllSeriesWithDataIterator(id, cursor, resource.newBuilder()).asStream(); @@ -162,7 +162,7 @@ public Stream getAllSeriesWithData(CubeId id) throws IOExcep } @Override - public Optional getSeries(CubeId id) throws IOException { + public @NonNull Optional getSeries(@NonNull CubeId id) throws IOException { try (SeriesCursor cursor = resource.getSeriesCursor(id)) { AbstractIOIterator result = new SeriesIterator(id, cursor); return result.hasNextWithIO() ? Optional.of(result.nextWithIO()) : Optional.empty(); @@ -172,7 +172,7 @@ public Optional getSeries(CubeId id) throws IOException { } @Override - public Optional getSeriesWithData(CubeId id) throws IOException { + public @NonNull Optional getSeriesWithData(@NonNull CubeId id) throws IOException { try (SeriesWithDataCursor cursor = resource.getSeriesWithDataCursor(id)) { AbstractIOIterator result = new SeriesWithDataIterator(id, cursor, resource.newBuilder()); return result.hasNextWithIO() ? Optional.of(result.nextWithIO()) : Optional.empty(); @@ -182,7 +182,7 @@ public Optional getSeriesWithData(CubeId id) throws IOExcept } @Override - public Stream getChildren(CubeId id) throws IOException { + public @NonNull Stream getChildren(@NonNull CubeId id) throws IOException { try { ChildrenCursor cursor = resource.getChildrenCursor(id); return new ChildrenIterator(id, cursor).asStream(); @@ -192,7 +192,7 @@ public Stream getChildren(CubeId id) throws IOException { } @Override - public String getDisplayName() throws IOException { + public @NonNull String getDisplayName() throws IOException { try { return resource.getDisplayName(); } catch (Exception ex) { @@ -201,7 +201,7 @@ public String getDisplayName() throws IOException { } @Override - public String getDisplayName(CubeId id) throws IOException { + public @NonNull String getDisplayName(@NonNull CubeId id) throws IOException { try { return resource.getDisplayName(id); } catch (Exception ex) { @@ -210,7 +210,7 @@ public String getDisplayName(CubeId id) throws IOException { } @Override - public String getDisplayNodeName(CubeId id) throws IOException { + public @NonNull String getDisplayNodeName(@NonNull CubeId id) throws IOException { try { return resource.getDisplayNodeName(id); } catch (Exception ex) { diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridReader.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridReader.java index 34dc4db4..a9984f63 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridReader.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridReader.java @@ -16,6 +16,9 @@ */ package jdplus.toolkit.base.tsp.grid; +import internal.toolkit.base.tsp.grid.InternalValueReader; +import internal.toolkit.base.tsp.grid.MarkableStream; +import internal.toolkit.base.tsp.grid.TsDataBuilders; import jdplus.toolkit.base.api.timeseries.Ts; import jdplus.toolkit.base.api.timeseries.TsCollection; import jdplus.toolkit.base.api.timeseries.TsData; @@ -23,11 +26,8 @@ import jdplus.toolkit.base.api.timeseries.util.ObsGathering; import jdplus.toolkit.base.api.timeseries.util.TsDataBuilder; import jdplus.toolkit.base.api.util.MultiLineNameUtil; -import jdplus.toolkit.base.tsp.util.ObsFormat; import jdplus.toolkit.base.tsp.fixme.Substitutor; -import internal.toolkit.base.tsp.grid.InternalValueReader; -import internal.toolkit.base.tsp.grid.MarkableStream; -import internal.toolkit.base.tsp.grid.TsDataBuilders; +import jdplus.toolkit.base.tsp.util.ObsFormat; import lombok.AccessLevel; import nbbrd.design.LombokWorkaround; import org.checkerframework.checker.nullness.qual.NonNull; @@ -113,14 +113,18 @@ private void readSeriesByRow(TypedInputStream input, TsCollection.Builder output head.skip(input); while (input.readRow()) { - String series = names.apply(input); - if (series == null) { - break; - } + String nullableName = names.apply(input); for (int col = 0; col < head.columns && input.readCell(); col++) { data.add(head.getPeriod(col), input.getNumber()); } - output.item(getTs(series, data.build())); + TsData result = data.build(); + if (isNotVoid(nullableName, result)) { + output.item(Ts.builder() + .type(TsInformationType.Data) + .name(fixNullName(nullableName)) + .data(result) + .build()); + } data.clear(); } } @@ -174,7 +178,7 @@ TypedInputStreamFunc getNameFunc(String namePattern, String nameSeparato Supplier nameGenerator = getNameGenerator(namePattern); return (stream) -> nameGenerator.get(); case 1: - return (stream) -> stream.readCell() ? stream.getString() : null; + return (stream) -> stream.readCell() ? stream.getString() : NULL_NAME; default: Collector nameJoiner = Collectors.joining(nameSeparator); String[] path = new String[firstObsIndex]; @@ -189,7 +193,7 @@ TypedInputStreamFunc getNameFunc(String namePattern, String nameSeparato path[index] = null; } } - return !hasHeader ? null : joinSkippingNulls(path, nameJoiner); + return !hasHeader ? NULL_NAME : joinSkippingNulls(path, nameJoiner); }; } } @@ -216,7 +220,15 @@ private void readPeriodByRow(TypedInputStream input, TsCollection.Builder output List names = head.getNames(namePattern, nameSeparator); for (int column = 0; column < head.columns; column++) { - output.item(getTs(names.get(column), data.build(column))); + String nullableName = names.get(column); + TsData result = data.build(column); + if (isNotVoid(nullableName, result)) { + output.item(Ts.builder() + .type(TsInformationType.Data) + .name(fixNullName(nullableName)) + .data(result) + .build()); + } } } @@ -246,8 +258,6 @@ static PeriodByRowHead peek(TypedInputStream stream) throws IOException { // level 1 List firstLine = line; if (!stream.readRow() || (line = readNameLine(stream)) == null) { - int index = firstLine.lastIndexOf(null); - firstLine = index == -1 ? firstLine : firstLine.subList(0, index); return new PeriodByRowHead(1, firstLine.size(), new String[][]{firstLine.toArray(new String[firstLine.size()])}); } @@ -411,14 +421,6 @@ private static boolean peekSeriesByRow(TypedInputStream typedStream) throws IOEx } } - private static Ts getTs(String name, TsData data) { - return Ts.builder() - .type(TsInformationType.Data) - .name(name) - .data(data) - .build(); - } - private static List readCells(TypedInputStream stream, TypedInputStreamFunc func) throws IOException { List result = new ArrayList<>(); while (stream.readCell()) { @@ -448,4 +450,14 @@ private static Substitutor getIndexSubstitutor(AtomicInteger counter) { } }); } + + private static final String NULL_NAME = null; + + private static boolean isNotVoid(String nullableName, TsData result) { + return nullableName != null || !result.isEmpty(); + } + + private static String fixNullName(String name) { + return name != null ? name : "null"; + } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridReaderHandler.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridReaderHandler.java index 01a1c2c5..ee5c85de 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridReaderHandler.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridReaderHandler.java @@ -27,7 +27,7 @@ public final class GridReaderHandler implements PropertyHandler { private final PropertyHandler nameSeparator; @Override - public GridReader get(Function properties) { + public @org.checkerframework.checker.nullness.qual.NonNull GridReader get(@org.checkerframework.checker.nullness.qual.NonNull Function properties) { return GridReader .builder() .format(format.get(properties)) @@ -39,7 +39,7 @@ public GridReader get(Function propertie } @Override - public void set(BiConsumer properties, GridReader value) { + public void set(@org.checkerframework.checker.nullness.qual.NonNull BiConsumer properties, GridReader value) { if (value != null) { format.set(properties, value.getFormat()); gathering.set(properties, value.getGathering()); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridWriterHandler.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridWriterHandler.java index b712a8df..feb4d438 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridWriterHandler.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/grid/GridWriterHandler.java @@ -29,7 +29,7 @@ public final class GridWriterHandler implements PropertyHandler { private final PropertyHandler reverseChronology; @Override - public GridWriter get(Function properties) { + public @org.checkerframework.checker.nullness.qual.NonNull GridWriter get(@org.checkerframework.checker.nullness.qual.NonNull Function properties) { return GridWriter .builder() .format(format.get(properties)) @@ -42,7 +42,7 @@ public GridWriter get(Function propertie } @Override - public void set(BiConsumer properties, GridWriter value) { + public void set(@org.checkerframework.checker.nullness.qual.NonNull BiConsumer properties, GridWriter value) { if (value != null) { format.set(properties, value.getFormat()); layout.set(properties, value.getLayout()); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/legacy/LegacyFileId.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/legacy/LegacyFileId.java index d9225c39..0da8f876 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/legacy/LegacyFileId.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/legacy/LegacyFileId.java @@ -29,7 +29,7 @@ */ @DemetraPlusLegacy @lombok.Value -public final class LegacyFileId implements CharSequence { +public class LegacyFileId implements CharSequence { @Nullable public static LegacyFileId of(@NonNull File file) { diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/stream/TsStreamAsProvider.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/stream/TsStreamAsProvider.java index 01bc3179..ee9d9136 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/stream/TsStreamAsProvider.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/stream/TsStreamAsProvider.java @@ -73,7 +73,7 @@ public void close() { } @Override - public TsCollection getTsCollection(TsMoniker moniker, TsInformationType type) throws IOException, IllegalArgumentException { + public @NonNull TsCollection getTsCollection(@NonNull TsMoniker moniker, @NonNull TsInformationType type) throws IOException, IllegalArgumentException { DataSourcePreconditions.checkProvider(getSource(), moniker); TsCollection.Builder result = TsCollection.builder().moniker(moniker).type(type); @@ -94,7 +94,7 @@ public TsCollection getTsCollection(TsMoniker moniker, TsInformationType type) t } @Override - public Ts getTs(TsMoniker moniker, TsInformationType type) throws IOException, IllegalArgumentException { + public @NonNull Ts getTs(@NonNull TsMoniker moniker, @NonNull TsInformationType type) throws IOException, IllegalArgumentException { DataSourcePreconditions.checkProvider(getSource(), moniker); Ts.Builder result = Ts.builder().moniker(moniker).type(type); @@ -109,7 +109,7 @@ public Ts getTs(TsMoniker moniker, TsInformationType type) throws IOException, I } @Override - public String getSource() { + public @NonNull String getSource() { return providerName; } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/FallbackDataMoniker.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/FallbackDataMoniker.java index 38e30505..47d6c7ab 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/FallbackDataMoniker.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/FallbackDataMoniker.java @@ -20,6 +20,7 @@ import jdplus.toolkit.base.tsp.DataSet; import jdplus.toolkit.base.tsp.DataSource; import jdplus.toolkit.base.tsp.HasDataMoniker; +import org.checkerframework.checker.nullness.qual.NonNull; import java.util.Optional; @@ -36,23 +37,23 @@ public final class FallbackDataMoniker implements HasDataMoniker { private final HasDataMoniker second; @Override - public TsMoniker toMoniker(DataSource dataSource) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSource dataSource) throws IllegalArgumentException { return first.toMoniker(dataSource); } @Override - public TsMoniker toMoniker(DataSet dataSet) throws IllegalArgumentException { + public @NonNull TsMoniker toMoniker(@NonNull DataSet dataSet) throws IllegalArgumentException { return first.toMoniker(dataSet); } @Override - public Optional toDataSource(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSource(@NonNull TsMoniker moniker) throws IllegalArgumentException { Optional result = first.toDataSource(moniker); return result.isPresent() ? result : second.toDataSource(moniker); } @Override - public Optional toDataSet(TsMoniker moniker) throws IllegalArgumentException { + public @NonNull Optional toDataSet(@NonNull TsMoniker moniker) throws IllegalArgumentException { Optional result = first.toDataSet(moniker); return result.isPresent() ? result : second.toDataSet(moniker); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/IOCacheFactory.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/IOCacheFactory.java deleted file mode 100644 index 51380a75..00000000 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/IOCacheFactory.java +++ /dev/null @@ -1,20 +0,0 @@ -package jdplus.toolkit.base.tsp.util; - -import nbbrd.service.Quantifier; -import nbbrd.service.ServiceDefinition; -import org.checkerframework.checker.nullness.qual.NonNull; - -import java.io.File; -import java.time.Duration; - -@ServiceDefinition( - quantifier = Quantifier.SINGLE, - singleton = true, - noFallback = true -) -public interface IOCacheFactory { - - @NonNull IOCache ofTtl(@NonNull Duration ttl); - - @NonNull IOCache ofFile(@NonNull File file); -} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsFormat.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsFormat.java index 5eb80d97..5493475c 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsFormat.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsFormat.java @@ -184,10 +184,10 @@ DateTimeFormatter newDateTimeFormatter() throws IllegalArgumentException { result.appendPattern("yyyy-MM-dd['T'HH:mm:ss]"); } else { result - .append(new DateTimeFormatterBuilder().appendLocalized(FormatStyle.MEDIUM, null).toFormatter(Locale.getDefault())) + .append(new DateTimeFormatterBuilder().appendLocalized(FormatStyle.MEDIUM, null).toFormatter(nonNullLocale)) .optionalStart() .appendLiteral(' ') - .append(new DateTimeFormatterBuilder().appendLocalized(null, FormatStyle.MEDIUM).toFormatter(Locale.getDefault())) + .append(new DateTimeFormatterBuilder().appendLocalized(null, FormatStyle.MEDIUM).toFormatter(nonNullLocale)) .optionalEnd(); } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsFormatHandler.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsFormatHandler.java index cfe6cb0f..ac86f32f 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsFormatHandler.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsFormatHandler.java @@ -23,7 +23,7 @@ public final class ObsFormatHandler implements PropertyHandler { private final PropertyHandler ignoreNumberGrouping; @Override - public @NonNull ObsFormat get(@NonNull Function properties) { + public @NonNull @org.checkerframework.checker.nullness.qual.NonNull ObsFormat get(@NonNull @org.checkerframework.checker.nullness.qual.NonNull Function properties) { return ObsFormat .builder() .locale(locale.get(properties)) @@ -34,7 +34,7 @@ public final class ObsFormatHandler implements PropertyHandler { } @Override - public void set(@NonNull BiConsumer properties, @Nullable ObsFormat value) { + public void set(@NonNull @org.checkerframework.checker.nullness.qual.NonNull BiConsumer properties, @Nullable ObsFormat value) { if (value != null) { locale.set(properties, value.getLocale()); dateTimePattern.set(properties, value.getDateTimePattern()); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsGatheringHandler.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsGatheringHandler.java index 1f28c6ae..52a8ca71 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsGatheringHandler.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ObsGatheringHandler.java @@ -25,7 +25,7 @@ public final class ObsGatheringHandler implements PropertyHandler private final PropertyHandler includeMissingValues; @Override - public @NonNull ObsGathering get(@NonNull Function properties) { + public @NonNull @org.checkerframework.checker.nullness.qual.NonNull ObsGathering get(@NonNull @org.checkerframework.checker.nullness.qual.NonNull Function properties) { return ObsGathering .builder() .unit(unit.get(properties)) @@ -36,7 +36,7 @@ public final class ObsGatheringHandler implements PropertyHandler } @Override - public void set(@NonNull BiConsumer properties, @Nullable ObsGathering value) { + public void set(@NonNull @org.checkerframework.checker.nullness.qual.NonNull BiConsumer properties, @Nullable ObsGathering value) { if (value != null) { unit.set(properties, value.getUnit()); aggregationType.set(properties, value.getAggregationType()); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/IOCache.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ShortLivedCache.java similarity index 86% rename from jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/IOCache.java rename to jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ShortLivedCache.java index b6b91449..7d602cf3 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/IOCache.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ShortLivedCache.java @@ -16,15 +16,15 @@ */ package jdplus.toolkit.base.tsp.util; -import org.checkerframework.checker.nullness.qual.NonNull; +import lombok.NonNull; +import nbbrd.design.NotThreadSafe; import org.checkerframework.checker.nullness.qual.Nullable; -import java.io.Closeable; - /** * @author Philippe Charles */ -public interface IOCache extends Closeable { +@NotThreadSafe +public interface ShortLivedCache { void put(@NonNull K key, @NonNull V value); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ShortLivedCaching.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ShortLivedCaching.java new file mode 100644 index 00000000..9266fc8b --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/jdplus/toolkit/base/tsp/util/ShortLivedCaching.java @@ -0,0 +1,27 @@ +package jdplus.toolkit.base.tsp.util; + +import internal.toolkit.base.tsp.util.MapCaching; +import lombok.NonNull; +import nbbrd.design.ThreadSafe; +import nbbrd.service.Quantifier; +import nbbrd.service.ServiceDefinition; +import nbbrd.service.ServiceId; + +import java.io.File; +import java.time.Duration; + +@ServiceDefinition( + quantifier = Quantifier.SINGLE, + singleton = true, + fallback = MapCaching.class +) +@ThreadSafe +public interface ShortLivedCaching { + + @ServiceId + @NonNull String getId(); + + @NonNull ShortLivedCache ofTtl(@NonNull Duration ttl); + + @NonNull ShortLivedCache ofFile(@NonNull File file); +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/module-info.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/module-info.java index 2101936b..e8e88558 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/module-info.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/main/java/module-info.java @@ -1,3 +1,6 @@ +import internal.toolkit.base.tsp.util.CaffeineCaching; +import jdplus.toolkit.base.tsp.util.ShortLivedCaching; + module jdplus.toolkit.base.tsp { requires static lombok; @@ -9,6 +12,7 @@ requires transitive jdplus.toolkit.base.api; requires java.desktop; requires java.logging; + requires com.github.benmanes.caffeine; exports jdplus.toolkit.base.tsp; exports jdplus.toolkit.base.tsp.cube; @@ -20,8 +24,7 @@ // FIXME: exports jdplus.toolkit.base.tsp.fixme; - uses jdplus.toolkit.base.tsp.util.IOCacheFactory; + uses jdplus.toolkit.base.tsp.util.ShortLivedCaching; - provides jdplus.toolkit.base.tsp.util.IOCacheFactory with - internal.toolkit.base.tsp.util.DefaultIOCacheFactory; + provides ShortLivedCaching with CaffeineCaching; } \ No newline at end of file diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/FakeClock.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/FakeClock.java new file mode 100644 index 00000000..1d158e35 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/FakeClock.java @@ -0,0 +1,44 @@ +package _test; + +import nbbrd.design.MightBePromoted; +import nbbrd.design.SkipProcessing; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; + +@MightBePromoted +@SkipProcessing(target = MightBePromoted.class, reason = "_test package") +public final class FakeClock extends Clock { + + private Instant current = Instant.now(); + + public FakeClock set(Instant current) { + this.current = current; + return this; + } + + public FakeClock set(long epochMilli) { + return set(Instant.ofEpochMilli(epochMilli)); + } + + public FakeClock plus(long durationInMillis) { + return set(current.plus(durationInMillis, ChronoUnit.MILLIS)); + } + + @Override + public ZoneId getZone() { + return ZoneId.systemDefault(); + } + + @Override + public Clock withZone(ZoneId zone) { + return this; + } + + @Override + public Instant instant() { + return current; + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/FixAssertj.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/FixAssertj.java similarity index 98% rename from jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/FixAssertj.java rename to jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/FixAssertj.java index efedcb29..4fa9a7dd 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/FixAssertj.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/FixAssertj.java @@ -14,7 +14,7 @@ * See the Licence for the specific language governing permissions and * limitations under the Licence. */ -package _util; +package _test; import java.util.Arrays; import static org.assertj.core.api.Assertions.assertThat; diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/tsproviders/FailingTsCursorSupport.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/tsproviders/FailingTsCursorSupport.java similarity index 80% rename from jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/tsproviders/FailingTsCursorSupport.java rename to jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/tsproviders/FailingTsCursorSupport.java index b93d5adf..414f9992 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/tsproviders/FailingTsCursorSupport.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/tsproviders/FailingTsCursorSupport.java @@ -14,7 +14,7 @@ * See the Licence for the specific language governing permissions and * limitations under the Licence. */ -package _util.tsproviders; +package _test.tsproviders; import jdplus.toolkit.base.tsp.DataSet; import jdplus.toolkit.base.tsp.DataSource; @@ -24,6 +24,7 @@ import java.io.IOException; import java.util.stream.Stream; import jdplus.toolkit.base.tsp.stream.HasTsStream; +import org.checkerframework.checker.nullness.qual.NonNull; /** * @@ -40,13 +41,13 @@ public FailingTsCursorSupport(String providerName, String message) { } @Override - public Stream getData(DataSource dataSource, TsInformationType type) throws IllegalArgumentException, IOException { + public @NonNull Stream getData(@NonNull DataSource dataSource, @NonNull TsInformationType type) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(providerName, dataSource); throw new IOException(message); } @Override - public Stream getData(DataSet dataSet, TsInformationType type) throws IllegalArgumentException, IOException { + public @NonNull Stream getData(@NonNull DataSet dataSet, @NonNull TsInformationType type) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(providerName, dataSet); throw new IOException(message); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/tsproviders/XCubeConnection.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/tsproviders/XCubeConnection.java similarity index 74% rename from jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/tsproviders/XCubeConnection.java rename to jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/tsproviders/XCubeConnection.java index ae7c1602..4b71969b 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/tsproviders/XCubeConnection.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_test/tsproviders/XCubeConnection.java @@ -14,7 +14,7 @@ * See the Licence for the specific language governing permissions and * limitations under the Licence. */ -package _util.tsproviders; +package _test.tsproviders; import jdplus.toolkit.base.tsp.fixme.ResourceWatcher; import jdplus.toolkit.base.tsp.cube.CubeConnection; @@ -22,6 +22,7 @@ import jdplus.toolkit.base.tsp.cube.CubeSeries; import jdplus.toolkit.base.tsp.cube.CubeSeriesWithData; import nbbrd.io.function.IORunnable; +import org.checkerframework.checker.nullness.qual.NonNull; import java.io.IOException; import java.util.Objects; @@ -42,59 +43,59 @@ public XCubeConnection(CubeId root, ResourceWatcher resourceWatcher) { } @Override - public Optional testConnection() { + public @NonNull Optional testConnection() { return Optional.empty(); } @Override - public CubeId getRoot() { + public @NonNull CubeId getRoot() { return root; } @Override - public Stream getAllSeries(CubeId id) throws IOException { + public @NonNull Stream getAllSeries(@NonNull CubeId id) throws IOException { Objects.requireNonNull(id); return Stream.empty().onClose(IORunnable.unchecked(resourceWatcher.watchAsCloseable("getAllSeries")::close)); } @Override - public Stream getAllSeriesWithData(CubeId id) throws IOException { + public @NonNull Stream getAllSeriesWithData(@NonNull CubeId id) throws IOException { Objects.requireNonNull(id); return Stream.empty().onClose(IORunnable.unchecked(resourceWatcher.watchAsCloseable("getAllSeriesWithData")::close)); } @Override - public Optional getSeries(CubeId id) throws IOException { + public @NonNull Optional getSeries(@NonNull CubeId id) throws IOException { Objects.requireNonNull(id); resourceWatcher.watchAsCloseable("getSeries").close(); return Optional.empty(); } @Override - public Optional getSeriesWithData(CubeId id) throws IOException { + public @NonNull Optional getSeriesWithData(@NonNull CubeId id) throws IOException { Objects.requireNonNull(id); resourceWatcher.watchAsCloseable("getSeriesWithData").close(); return Optional.empty(); } @Override - public Stream getChildren(CubeId id) throws IOException { + public @NonNull Stream getChildren(@NonNull CubeId id) throws IOException { Objects.requireNonNull(id); return Stream.empty().onClose(IORunnable.unchecked(resourceWatcher.watchAsCloseable("getChildren")::close)); } @Override - public String getDisplayName() throws IOException { + public @NonNull String getDisplayName() throws IOException { return root.toString(); } @Override - public String getDisplayName(CubeId id) throws IOException { + public @NonNull String getDisplayName(@NonNull CubeId id) throws IOException { return id.toString(); } @Override - public String getDisplayNodeName(CubeId id) throws IOException { + public @NonNull String getDisplayNodeName(@NonNull CubeId id) throws IOException { return id.toString(); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/tsproviders/FakeTs.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/tsproviders/FakeTs.java deleted file mode 100644 index 7bbba9aa..00000000 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/tsproviders/FakeTs.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2017 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved - * by the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * http://ec.europa.eu/idabc/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ -package _util.tsproviders; - -import jdplus.toolkit.base.api.timeseries.TsUnit; -import jdplus.toolkit.base.api.timeseries.TsData; -import java.util.Collections; -import java.util.Map; - -/** - * - * @author Philippe Charles - */ -@lombok.Value -@lombok.Builder -public final class FakeTs { - - @lombok.NonNull - String label; - @lombok.NonNull - TsData data; - @lombok.NonNull - Map meta = Collections.emptyMap(); - - public static final FakeTs S1 = FakeTs.builder().label("Series 1").data(TsData.random(TsUnit.MONTH, 1)).build(); - public static final FakeTs S2 = FakeTs.builder().label("Series 2").data(TsData.random(TsUnit.MONTH, 2)).build(); - public static final FakeTs S3 = FakeTs.builder().label("Series 3").data(TsData.empty("Missing")).build(); -} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/grid/InternalValueReaderTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/grid/InternalValueReaderTest.java index 2d4b9f9a..7dae543f 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/grid/InternalValueReaderTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/grid/InternalValueReaderTest.java @@ -46,12 +46,12 @@ public void testOnDateTime() throws IOException { assertThat(x.read(grid.getValue(0, 0))).isNull(); assertThat(x.read(grid.getValue(1, 0))).isNull(); - assertThat(x.read(grid.getValue(0, 1))).isEqualTo(JAN_2010); - assertThat(x.read(grid.getValue(0, 2))).isEqualTo(FEB_2010); + assertThat(x.read(grid.getValue(0, 1))).isEqualTo(JAN_); + assertThat(x.read(grid.getValue(0, 2))).isEqualTo(FEB_); } private final Object[][] data = { - {null, JAN_2010, FEB_2010, MAR_2010}, + {null, JAN_, FEB_, MAR_}, {"S1", 3.14, 4.56, 7.89} }; private final ArrayGridInput grid = ArrayGridInput.of(data); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/grid/InternalValueWriterTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/grid/InternalValueWriterTest.java index 47c55815..fa3fec24 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/grid/InternalValueWriterTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/grid/InternalValueWriterTest.java @@ -29,7 +29,7 @@ import java.time.format.DateTimeFormatter; import java.util.EnumSet; -import static _util.FixAssertj.assertDeepEqualTo; +import static _test.FixAssertj.assertDeepEqualTo; import static internal.toolkit.base.tsp.grid.InternalValueWriter.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.atIndex; @@ -46,7 +46,7 @@ public void testOnNull() throws IOException { InternalValueWriter x = onNull(); Object[][] data = { - {null, JAN_2010, FEB_2010, MAR_2010}, + {null, JAN_, FEB_, MAR_}, {"S1", 3.14, 4.56, 7.89} }; @@ -75,11 +75,11 @@ public void testOnDateTime() throws IOException { ArrayGridOutput out = new ArrayGridOutput(GridLayout.VERTICAL, EnumSet.allOf(GridDataType.class)); try (GridOutput.Stream stream = out.open("test", 1, 2)) { - x.write(stream, JAN_2010); + x.write(stream, JAN_); x.write(stream, null); } - assertThat(out.getData().get("test")).contains(new Object[]{JAN_2010, null}, atIndex(0)); + assertThat(out.getData().get("test")).contains(new Object[]{JAN_, null}, atIndex(0)); } @Test @@ -114,12 +114,12 @@ public void testOnStringFormatter() throws IOException { ArrayGridOutput out = new ArrayGridOutput(GridLayout.VERTICAL, EnumSet.allOf(GridDataType.class)); try (GridOutput.Stream stream = out.open("test", 1, 4)) { - onStringFormatter(f.dateTimeFormatter()::formatAsString).write(stream, JAN_2010); + onStringFormatter(f.dateTimeFormatter()::formatAsString).write(stream, JAN_); onStringFormatter(f.dateTimeFormatter()::formatAsString).write(stream, null); onStringFormatter(f.numberFormatter()::formatAsString).write(stream, null); onStringFormatter(f.numberFormatter()::formatAsString).write(stream, 3.14); } - assertThat(out.getData().get("test")).contains(new Object[]{JAN_2010.format(DateTimeFormatter.ISO_DATE), null, null, "3.14"}, atIndex(0)); + assertThat(out.getData().get("test")).contains(new Object[]{JAN_.format(DateTimeFormatter.ISO_DATE), null, null, "3.14"}, atIndex(0)); } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/CaffeineCachingTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/CaffeineCachingTest.java new file mode 100644 index 00000000..a9015d65 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/CaffeineCachingTest.java @@ -0,0 +1,30 @@ +package internal.toolkit.base.tsp.util; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.attribute.FileTime; +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import static jdplus.toolkit.base.tsp.util.ShortLivedCachingTest.assertCompliance; +import static jdplus.toolkit.base.tsp.util.ShortLivedCachingTest.touch; + +public class CaffeineCachingTest { + + @Test + public void testCompliance(@TempDir Path temp) throws IOException { + var tickerInNanos = new AtomicLong(0); + + assertCompliance( + new CaffeineCaching(tickerInNanos::get), + duration -> tickerInNanos.addAndGet(duration.toNanos()), + file -> touch(file, FileTime.from(tickerInNanos.addAndGet(Duration.ofMillis(1).toNanos()), TimeUnit.NANOSECONDS)), + temp + ); + } + +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/DefaultIOCacheFactoryTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/DefaultIOCacheFactoryTest.java deleted file mode 100644 index 556e2b86..00000000 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/DefaultIOCacheFactoryTest.java +++ /dev/null @@ -1,124 +0,0 @@ -package internal.toolkit.base.tsp.util; - -import nbbrd.design.MightBePromoted; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.FileTime; -import java.time.Clock; -import java.time.Duration; -import java.time.Instant; -import java.time.ZoneId; -import java.time.temporal.ChronoUnit; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicBoolean; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatNullPointerException; - -@SuppressWarnings("ConstantConditions") -public class DefaultIOCacheFactoryTest { - - @Test - public void testOfTtl() { - assertThatNullPointerException().isThrownBy(() -> new DefaultIOCacheFactory().ofTtl(null)); - } - - @Test - public void testOfFile() { - assertThatNullPointerException().isThrownBy(() -> new DefaultIOCacheFactory().ofFile(null)); - } - - @Test - public void testTtlValidator() { - FakeClock clock = new FakeClock(); - - Duration ttl = Duration.ofMillis(100); - DefaultIOCacheFactory.Validator validator = DefaultIOCacheFactory.ttlValidator(ttl); - - assertThat(validator.test(clock, new DefaultIOCacheFactory.ValueHolder<>("", clock.instant()))) - .isTrue(); - - assertThat(validator.test(clock, new DefaultIOCacheFactory.ValueHolder<>("", clock.instant().minus(ttl)))) - .isFalse(); - } - - @Test - public void testFileValidator(@TempDir Path temp) throws IOException { - File file = java.nio.file.Files.createFile(temp.resolve("fileValidator")).toFile(); - assertThat(file).exists(); - - FakeClock clock = new FakeClock().set(file.lastModified()); - - DefaultIOCacheFactory.Validator validator = DefaultIOCacheFactory.fileValidator(file); - DefaultIOCacheFactory.ValueHolder valueHolder = new DefaultIOCacheFactory.ValueHolder<>("", clock.instant()); - - assertThat(validator.test(clock, valueHolder)).isTrue(); - - Files.setLastModifiedTime(file.toPath(), FileTime.from(clock.instant().plusMillis(1))); - assertThat(validator.test(clock, valueHolder)).isFalse(); - - assertThat(file.delete()).isTrue(); - assertThat(validator.test(clock, valueHolder)).isFalse(); - } - - @Test - public void testDefaultIOCache() { - ConcurrentMap> map = new ConcurrentHashMap<>(); - FakeClock clock = new FakeClock(); - AtomicBoolean valid = new AtomicBoolean(true); - - DefaultIOCacheFactory.DefaultIOCache cache = new DefaultIOCacheFactory.DefaultIOCache<>(map, clock, (x, y) -> valid.get()); - - String key = "key1"; - Integer value = 1; - - cache.put(key, value); - assertThat(map).containsKey(key); - assertThat(cache.get(key)).isEqualTo(value); - - valid.set(false); - assertThat(map).containsKey(key); - assertThat(cache.get(key)).isNull(); - assertThat(map).isEmpty(); - } - - @MightBePromoted - static final class FakeClock extends Clock { - - private Instant current = Instant.now(); - - public FakeClock set(Instant current) { - this.current = current; - return this; - } - - public FakeClock set(long epochMilli) { - return set(Instant.ofEpochMilli(epochMilli)); - } - - public FakeClock plus(long durationInMillis) { - return set(current.plus(durationInMillis, ChronoUnit.MILLIS)); - } - - @Override - public ZoneId getZone() { - return ZoneId.systemDefault(); - } - - @Override - public Clock withZone(ZoneId zone) { - return this; - } - - @Override - public Instant instant() { - return current; - } - } -} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/MapCacheTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/MapCacheTest.java new file mode 100644 index 00000000..d172d18b --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/MapCacheTest.java @@ -0,0 +1,33 @@ +package internal.toolkit.base.tsp.util; + +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicLong; + +import static org.assertj.core.api.Assertions.assertThat; + +@SuppressWarnings("ConstantConditions") +public class MapCacheTest { + + @Test + public void testCache() { + AtomicLong ticker = new AtomicLong(0); + Duration ttl = Duration.ofMillis(10); + + TtlMapCache cache = new TtlMapCache<>(new HashMap<>(), ticker::get, ttl); + + String key = "key1"; + Integer value = 1; + + cache.put(key, value); + assertThat(cache.getMap()).containsKey(key); + assertThat(cache.get(key)).isEqualTo(value); + + ticker.addAndGet(ttl.toNanos()); + assertThat(cache.getMap()).containsKey(key); + assertThat(cache.get(key)).isNull(); + assertThat(cache.getMap()).isEmpty(); + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/MapCachingTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/MapCachingTest.java new file mode 100644 index 00000000..ef589a38 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/internal/toolkit/base/tsp/util/MapCachingTest.java @@ -0,0 +1,30 @@ +package internal.toolkit.base.tsp.util; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.attribute.FileTime; +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import static jdplus.toolkit.base.tsp.util.ShortLivedCachingTest.assertCompliance; +import static jdplus.toolkit.base.tsp.util.ShortLivedCachingTest.touch; + +@SuppressWarnings("ConstantConditions") +public class MapCachingTest { + + @Test + public void testCompliance(@TempDir Path temp) throws IOException { + var tickerInNanos = new AtomicLong(0); + + assertCompliance( + new MapCaching(tickerInNanos::get), + duration -> tickerInNanos.addAndGet(duration.toNanos()), + file -> touch(file, FileTime.from(tickerInNanos.addAndGet(Duration.ofMillis(1).toNanos()), TimeUnit.NANOSECONDS)), + temp + ); + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/HasDataSourceBeanTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/HasDataSourceBeanTest.java index dc14c377..5e757aff 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/HasDataSourceBeanTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/HasDataSourceBeanTest.java @@ -21,6 +21,7 @@ import nbbrd.io.text.Formatter; import nbbrd.io.text.Parser; import nbbrd.io.text.Property; +import org.checkerframework.checker.nullness.qual.NonNull; import org.junit.jupiter.api.Test; import java.io.File; @@ -69,7 +70,7 @@ public boolean equals(Object obj) { private final Property detailsParam = Property.of("d", "defaultValue", Parser.onString(), Formatter.onString()); @Override - public CustomBean getDefaultValue() { + public @NonNull CustomBean getDefaultValue() { CustomBean result = new CustomBean(); result.file = fileParam.getDefaultValue(); result.details = detailsParam.getDefaultValue(); @@ -77,7 +78,7 @@ public CustomBean getDefaultValue() { } @Override - public CustomBean get(DataSource config) { + public @NonNull CustomBean get(@NonNull DataSource config) { CustomBean result = new CustomBean(); result.file = fileParam.get(config::getParameter); result.details = detailsParam.get(config::getParameter); @@ -85,7 +86,7 @@ public CustomBean get(DataSource config) { } @Override - public void set(DataSource.Builder builder, CustomBean value) { + public void set(DataSource.@NonNull Builder builder, CustomBean value) { fileParam.set(builder::parameter, value.file); detailsParam.set(builder::parameter, value.details); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/cube/BulkCubeConnectionTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/cube/BulkCubeConnectionTest.java index 35fe8856..b96179db 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/cube/BulkCubeConnectionTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/cube/BulkCubeConnectionTest.java @@ -16,19 +16,15 @@ */ package jdplus.toolkit.base.tsp.cube; -import _util.tsproviders.XCubeConnection; +import internal.toolkit.base.tsp.util.SimpleMapCache; +import _test.tsproviders.XCubeConnection; +import internal.toolkit.base.tsp.util.MapCaching; import jdplus.toolkit.base.tsp.fixme.ResourceWatcher; -import jdplus.toolkit.base.tsp.util.IOCache; -import jdplus.toolkit.base.tsp.util.IOCacheFactory; -import org.checkerframework.checker.nullness.qual.NonNull; import org.junit.jupiter.api.Test; -import java.io.File; import java.io.IOException; -import java.time.Duration; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.IntFunction; +import java.util.HashMap; +import java.util.List; import static jdplus.toolkit.base.tsp.cube.CubeIdTest.*; import static org.assertj.core.api.Assertions.assertThat; @@ -43,94 +39,80 @@ private static CubeConnection newSample() { return new XCubeConnection(DIM2_LEV0, new ResourceWatcher()); } + @SuppressWarnings("DataFlowIssue") @Test - public void testBulkApi() throws IOException { - CubeConnection accessor = BulkCubeConnection.of(newSample(), BulkCube.NONE, new FakeCacheFactory()); - assertThatThrownBy(() -> accessor.getAllSeriesWithData(null)).isInstanceOf(NullPointerException.class); - assertThatThrownBy(() -> accessor.getSeriesWithData(null)).isInstanceOf(NullPointerException.class); + public void testBulkApi() { + var connection = BulkCubeConnection.of(newSample(), BulkCube.NONE, new MapCaching()); + assertThatThrownBy(() -> connection.getAllSeriesWithData(null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> connection.getSeriesWithData(null)).isInstanceOf(NullPointerException.class); } @Test public void testBulkDepth() throws IOException { - ConcurrentMap x = new ConcurrentHashMap<>(); - try (IOCache cache = new FakeCache(x)) { - IntFunction factory = o -> { - x.clear(); - return new BulkCubeConnection(newSample(), o, cache); - }; + var cache = newMapCache(); - factory.apply(0).getSeriesWithData(DIM2_LEV2); - assertThat(x).isEmpty(); + try (var connection = new BulkCubeConnection(newSample(), 0, clear(cache))) { + connection.getSeriesWithData(DIM2_LEV2); + assertThat(cache.getMap()).isEmpty(); + } - factory.apply(0).getAllSeriesWithData(DIM2_LEV1).close(); - assertThat(x).isEmpty(); + try (var connection = new BulkCubeConnection(newSample(), 0, clear(cache))) { + connection.getAllSeriesWithData(DIM2_LEV1).close(); + assertThat(cache.getMap()).isEmpty(); + } - factory.apply(0).getAllSeriesWithData(DIM2_LEV0).close(); - assertThat(x).isEmpty(); + try (var connection = new BulkCubeConnection(newSample(), 0, clear(cache))) { + connection.getAllSeriesWithData(DIM2_LEV0).close(); + assertThat(cache.getMap()).isEmpty(); + } - factory.apply(1).getSeriesWithData(DIM2_LEV2); - assertThat(x).isNotEmpty(); + try (var connection = new BulkCubeConnection(newSample(), 1, clear(cache))) { + connection.getSeriesWithData(DIM2_LEV2); + assertThat(cache.getMap()).isNotEmpty(); + } - factory.apply(1).getAllSeriesWithData(DIM2_LEV1).close(); - assertThat(x).isNotEmpty(); + try (var connection = new BulkCubeConnection(newSample(), 1, clear(cache))) { + connection.getAllSeriesWithData(DIM2_LEV1).close(); + assertThat(cache.getMap()).isNotEmpty(); + } - factory.apply(1).getAllSeriesWithData(DIM2_LEV0).close(); - assertThat(x).isEmpty(); + try (var connection = new BulkCubeConnection(newSample(), 1, clear(cache))) { + connection.getAllSeriesWithData(DIM2_LEV0).close(); + assertThat(cache.getMap()).isEmpty(); + } - factory.apply(2).getSeriesWithData(DIM2_LEV2); - assertThat(x).isNotEmpty(); + try (var connection = new BulkCubeConnection(newSample(), 2, clear(cache))) { + connection.getSeriesWithData(DIM2_LEV2); + assertThat(cache.getMap()).isNotEmpty(); + } - factory.apply(2).getAllSeriesWithData(DIM2_LEV1).close(); - assertThat(x).isNotEmpty(); + try (var connection = new BulkCubeConnection(newSample(), 2, clear(cache))) { + connection.getAllSeriesWithData(DIM2_LEV1).close(); + assertThat(cache.getMap()).isNotEmpty(); + } - factory.apply(2).getAllSeriesWithData(DIM2_LEV0).close(); - assertThat(x).isNotEmpty(); + try (var connection = new BulkCubeConnection(newSample(), 2, clear(cache))) { + connection.getAllSeriesWithData(DIM2_LEV0).close(); + assertThat(cache.getMap()).isNotEmpty(); } } @Test public void testResourceLeak() throws IOException { ResourceWatcher watcher = new ResourceWatcher(); - ConcurrentMap x = new ConcurrentHashMap<>(); - try (IOCache cache = new FakeCache(x)) { - BulkCubeConnection accessor = new BulkCubeConnection(new XCubeConnection(DIM2_LEV0, watcher), 1, cache); - accessor.getSeriesWithData(DIM2_LEV2); - assertThat(x).isNotEmpty(); - assertThat(watcher.isLeaking()).isFalse(); - } + var cache = newMapCache(); + var connection = new BulkCubeConnection(new XCubeConnection(DIM2_LEV0, watcher), 1, cache); + connection.getSeriesWithData(DIM2_LEV2); + assertThat(cache.getMap()).isNotEmpty(); + assertThat(watcher.isLeaking()).isFalse(); } - private static final class FakeCacheFactory implements IOCacheFactory { - - @Override - public @NonNull IOCache ofTtl(@NonNull Duration ttl) { - return new FakeCache<>(new ConcurrentHashMap<>()); - } - - @Override - public @NonNull IOCache ofFile(@NonNull File file) { - return new FakeCache<>(new ConcurrentHashMap<>()); - } + private static SimpleMapCache> newMapCache() { + return new SimpleMapCache<>(new HashMap<>()); } - @lombok.AllArgsConstructor - private static final class FakeCache implements IOCache { - - @lombok.NonNull - private final ConcurrentMap delegate; - - @Override - public void put(K key, V value) { - delegate.put(key, value); - } - - @Override - public V get(K key) { - return delegate.get(key); - } - - @Override - public void close() throws IOException { - } + private static SimpleMapCache clear(SimpleMapCache cache) { + cache.getMap().clear(); + return cache; } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/cube/CubeSupportTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/cube/CubeSupportTest.java index 8f6ae064..451addc1 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/cube/CubeSupportTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/cube/CubeSupportTest.java @@ -16,7 +16,7 @@ */ package jdplus.toolkit.base.tsp.cube; -import _util.tsproviders.XCubeConnection; +import _test.tsproviders.XCubeConnection; import jdplus.toolkit.base.tsp.fixme.ResourceWatcher; import jdplus.toolkit.base.api.timeseries.TsInformationType; import jdplus.toolkit.base.tsp.DataSet; diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/grid/GridReaderTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/grid/GridReaderTest.java index 6828dfc9..1521b999 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/grid/GridReaderTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/grid/GridReaderTest.java @@ -49,10 +49,9 @@ public void testReadEmpty() throws IOException { public void testReadHorizontal() throws IOException { GridReader x = GridReader.DEFAULT.toBuilder().namePattern("Series ${index}").build(); - for (GridInput o : new GridInput[]{HGRID, HGRID_OVERFLOW, HGRID_NULL_NAME, HGRID_CORNER_LABEL}) { + for (GridInput o : new GridInput[]{HGRID, HGRID_GAP, HGRID_OVERFLOW, HGRID_CORNER_LABEL}) { assertThat(x.read(o)).isEqualTo(c(HORIZONTAL, s("S1", MONTH, 2010, 0, 3.14, 4.56, 7.89))); } - assertThat(x.read(HGRID_UNDERFLOW)) .isEqualTo(c(HORIZONTAL, s("S1", MONTH, 2010, 0, 3.14, 4.56))); @@ -62,15 +61,24 @@ public void testReadHorizontal() throws IOException { assertThat(x.toBuilder().namePattern("X${number}").build().read(HGRID_NO_NAME)) .isEqualTo(c(HORIZONTAL, s("X1", MONTH, 2010, 0, 3.14, 4.56, 7.89))); + assertThat(x.read(HGRID_NULL_NAME)) + .isEqualTo(TsCollection + .builder() + .meta(GridLayout.PROPERTY, HORIZONTAL.name()) + .type(TsInformationType.Data) + .item(s("S1", MONTH, 2010, 0, 3.14, 4.56, 7.89)) + .item(s("null", MONTH, 2010, 0, 3333, 4444, 5555)) + .build()); + assertThat(x.read(HGRID_MULTI_NAME)) .isEqualTo(TsCollection .builder() .meta(GridLayout.PROPERTY, HORIZONTAL.name()) .type(TsInformationType.Data) .item(s("G1\nS1", MONTH, 2010, 0, 3.14, 4.56, 7.89)) - .item(s("G1\nS2", MONTH, 2010, 0, 3, 4, 5)) - .item(s("G2\nS1", MONTH, 2010, 0, 7, 8, 9)) - .item(s("S1", MONTH, 2010, 0, 0, 1, 2)) + .item(s("G1\nS2", MONTH, 2010, 0, 1003, 1004, 1005)) + .item(s("G2\nS1", MONTH, 2010, 0, 1007, 1008, 1009)) + .item(s("S1", MONTH, 2010, 0, 1000, 1001, 1002)) .build()); } @@ -78,7 +86,7 @@ public void testReadHorizontal() throws IOException { public void testReadVertical() throws IOException { GridReader x = GridReader.DEFAULT.toBuilder().namePattern("Series ${index}").build(); - for (GridInput o : new GridInput[]{VGRID, VGRID_OVERFLOW, VGRID_NULL_NAME, VGRID_CORNER_LABEL}) { + for (GridInput o : new GridInput[]{VGRID, VGRID_GAP, VGRID_OVERFLOW, VGRID_CORNER_LABEL}) { assertThat(x.read(o)).isEqualTo(c(VERTICAL, s("S1", MONTH, 2010, 0, 3.14, 4.56, 7.89))); } @@ -91,15 +99,24 @@ public void testReadVertical() throws IOException { assertThat(x.toBuilder().namePattern("X${number}").build().read(VGRID_NO_NAME)) .isEqualTo(c(VERTICAL, s("X1", MONTH, 2010, 0, 3.14, 4.56, 7.89))); + assertThat(x.read(VGRID_NULL_NAME)) + .isEqualTo(TsCollection + .builder() + .meta(GridLayout.PROPERTY, VERTICAL.name()) + .type(TsInformationType.Data) + .item(s("S1", MONTH, 2010, 0, 3.14, 4.56, 7.89)) + .item(s("null", MONTH, 2010, 0, 3333, 4444, 5555)) + .build()); + assertThat(x.read(VGRID_MULTI_NAME)) .isEqualTo(TsCollection .builder() .meta(GridLayout.PROPERTY, VERTICAL.name()) .type(TsInformationType.Data) .item(s("G1\nS1", MONTH, 2010, 0, 3.14, 4.56, 7.89)) - .item(s("G1\nS2", MONTH, 2010, 0, 3, 4, 5)) - .item(s("G2\nS1", MONTH, 2010, 0, 7, 8, 9)) - .item(s("S1", MONTH, 2010, 0, 0, 1, 2)) + .item(s("G1\nS2", MONTH, 2010, 0, 1003, 1004, 1005)) + .item(s("G2\nS1", MONTH, 2010, 0, 1007, 1008, 1009)) + .item(s("S1", MONTH, 2010, 0, 1000, 1001, 1002)) .build()); } @@ -113,9 +130,9 @@ public void testNameSeparator() throws IOException { .meta(GridLayout.PROPERTY, VERTICAL.name()) .type(TsInformationType.Data) .item(s("G1-S1", MONTH, 2010, 0, 3.14, 4.56, 7.89)) - .item(s("G1-S2", MONTH, 2010, 0, 3, 4, 5)) - .item(s("G2-S1", MONTH, 2010, 0, 7, 8, 9)) - .item(s("S1", MONTH, 2010, 0, 0, 1, 2)) + .item(s("G1-S2", MONTH, 2010, 0, 1003, 1004, 1005)) + .item(s("G2-S1", MONTH, 2010, 0, 1007, 1008, 1009)) + .item(s("S1", MONTH, 2010, 0, 1000, 1001, 1002)) .build()); } @@ -127,9 +144,9 @@ public void testLayout() throws IOException { .meta(GridLayout.PROPERTY, HORIZONTAL.name()) .type(TsInformationType.Data) .item(s("G1\nS1", MONTH, 2010, 0, 3.14, 4.56, 7.89)) - .item(s("G1\nS2", MONTH, 2010, 0, 3, 4, 5)) - .item(s("G2\nS1", MONTH, 2010, 0, 7, 8, 9)) - .item(s("S1", MONTH, 2010, 0, 0, 1, 2)) + .item(s("G1\nS2", MONTH, 2010, 0, 1003, 1004, 1005)) + .item(s("G2\nS1", MONTH, 2010, 0, 1007, 1008, 1009)) + .item(s("S1", MONTH, 2010, 0, 1000, 1001, 1002)) .build()); assertThat(GridReader.builder().layout(VERTICAL).build().read(VGRID_MULTI_NAME)) @@ -138,9 +155,9 @@ public void testLayout() throws IOException { .meta(GridLayout.PROPERTY, VERTICAL.name()) .type(TsInformationType.Data) .item(s("G1\nS1", MONTH, 2010, 0, 3.14, 4.56, 7.89)) - .item(s("G1\nS2", MONTH, 2010, 0, 3, 4, 5)) - .item(s("G2\nS1", MONTH, 2010, 0, 7, 8, 9)) - .item(s("S1", MONTH, 2010, 0, 0, 1, 2)) + .item(s("G1\nS2", MONTH, 2010, 0, 1003, 1004, 1005)) + .item(s("G2\nS1", MONTH, 2010, 0, 1007, 1008, 1009)) + .item(s("S1", MONTH, 2010, 0, 1000, 1001, 1002)) .build()); } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/grid/GridWriterTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/grid/GridWriterTest.java index dad1c498..e5017a79 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/grid/GridWriterTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/grid/GridWriterTest.java @@ -26,7 +26,7 @@ import java.util.EnumSet; import java.util.Set; -import static _util.FixAssertj.assertDeepEqualTo; +import static _test.FixAssertj.assertDeepEqualTo; import static jdplus.toolkit.base.api.timeseries.TsUnit.MONTH; import static jdplus.toolkit.base.api.timeseries.TsUnit.QUARTER; import static jdplus.toolkit.base.tsp.grid.GridLayout.HORIZONTAL; @@ -47,31 +47,31 @@ public void testVertical() throws IOException { assertDeepEqualTo(toArray(sample, opts.ignoreNames(false).ignoreDates(false).reverseChronology(false).build()), new Object[][]{ {"x", "G1\nS1", "G1\nS2", "G2\nS1", "S1"}, - {JAN_2010, 1.01, 2.01, 3.01, null}, - {FEB_2010, null, null, 3.02, 4.02}, - {MAR_2010, 1.03, null, null, 4.03} + {JAN_, 1.01, 2.01, 3.01, null}, + {FEB_, null, null, 3.02, 4.02}, + {MAR_, 1.03, null, null, 4.03} }); assertDeepEqualTo(toArray(sample, opts.ignoreNames(false).ignoreDates(false).reverseChronology(true).build()), new Object[][]{ {"x", "G1\nS1", "G1\nS2", "G2\nS1", "S1"}, - {MAR_2010, 1.03, null, null, 4.03}, - {FEB_2010, null, null, 3.02, 4.02}, - {JAN_2010, 1.01, 2.01, 3.01, null} + {MAR_, 1.03, null, null, 4.03}, + {FEB_, null, null, 3.02, 4.02}, + {JAN_, 1.01, 2.01, 3.01, null} }); assertDeepEqualTo(toArray(sample, opts.ignoreNames(true).ignoreDates(false).reverseChronology(false).build()), new Object[][]{ - {JAN_2010, 1.01, 2.01, 3.01, null}, - {FEB_2010, null, null, 3.02, 4.02}, - {MAR_2010, 1.03, null, null, 4.03} + {JAN_, 1.01, 2.01, 3.01, null}, + {FEB_, null, null, 3.02, 4.02}, + {MAR_, 1.03, null, null, 4.03} }); assertDeepEqualTo(toArray(sample, opts.ignoreNames(true).ignoreDates(false).reverseChronology(true).build()), new Object[][]{ - {MAR_2010, 1.03, null, null, 4.03}, - {FEB_2010, null, null, 3.02, 4.02}, - {JAN_2010, 1.01, 2.01, 3.01, null} + {MAR_, 1.03, null, null, 4.03}, + {FEB_, null, null, 3.02, 4.02}, + {JAN_, 1.01, 2.01, 3.01, null} }); assertDeepEqualTo(toArray(sample, opts.ignoreNames(false).ignoreDates(true).reverseChronology(false).build()), @@ -124,7 +124,7 @@ public void testHorizontal() throws IOException { assertDeepEqualTo(toArray(sample, opts.ignoreNames(false).ignoreDates(false).reverseChronology(false).build()), new Object[][]{ - {"x", JAN_2010, FEB_2010, MAR_2010}, + {"x", JAN_, FEB_, MAR_}, {"G1\nS1", 1.01, null, 1.03}, {"G1\nS2", 2.01, null, null}, {"G2\nS1", 3.01, 3.02, null}, @@ -133,7 +133,7 @@ public void testHorizontal() throws IOException { assertDeepEqualTo(toArray(sample, opts.ignoreNames(false).ignoreDates(false).reverseChronology(true).build()), new Object[][]{ - {"x", MAR_2010, FEB_2010, JAN_2010}, + {"x", MAR_, FEB_, JAN_}, {"G1\nS1", 1.03, null, 1.01}, {"G1\nS2", null, null, 2.01}, {"G2\nS1", null, 3.02, 3.01}, @@ -142,7 +142,7 @@ public void testHorizontal() throws IOException { assertDeepEqualTo(toArray(sample, opts.ignoreNames(true).ignoreDates(false).reverseChronology(false).build()), new Object[][]{ - {JAN_2010, FEB_2010, MAR_2010}, + {JAN_, FEB_, MAR_}, {1.01, null, 1.03}, {2.01, null, null}, {3.01, 3.02, null}, @@ -151,7 +151,7 @@ public void testHorizontal() throws IOException { assertDeepEqualTo(toArray(sample, opts.ignoreNames(true).ignoreDates(false).reverseChronology(true).build()), new Object[][]{ - {MAR_2010, FEB_2010, JAN_2010}, + {MAR_, FEB_, JAN_}, {1.03, null, 1.01}, {null, null, 2.01}, {null, 3.02, 3.01}, @@ -212,17 +212,17 @@ public void testValueTypes() throws IOException { assertDeepEqualTo(toArray(sample, opts, EnumSet.allOf(GridDataType.class)), new Object[][]{ {null, "G1\nS1", "G1\nS2", "G2\nS1", "S1"}, - {JAN_2010, 1.01, 2.01, 3.01, null}, - {FEB_2010, null, null, 3.02, 4.02}, - {MAR_2010, 1.03, null, null, 4.03} + {JAN_, 1.01, 2.01, 3.01, null}, + {FEB_, null, null, 3.02, 4.02}, + {MAR_, 1.03, null, null, 4.03} }); assertDeepEqualTo(toArray(sample, opts, EnumSet.of(GridDataType.LOCAL_DATE_TIME)), new Object[][]{ {null, null, null, null, null}, - {JAN_2010, null, null, null, null}, - {FEB_2010, null, null, null, null}, - {MAR_2010, null, null, null, null} + {JAN_, null, null, null, null}, + {FEB_, null, null, null, null}, + {MAR_, null, null, null, null} }); assertDeepEqualTo(toArray(sample, opts, EnumSet.of(GridDataType.DOUBLE)), diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/poc/FakeDbConnection.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/poc/FakeDbConnection.java index b9aebce4..ef0078d4 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/poc/FakeDbConnection.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/poc/FakeDbConnection.java @@ -21,6 +21,7 @@ import jdplus.toolkit.base.tsp.cube.CubeId; import jdplus.toolkit.base.tsp.cube.CubeSeries; import jdplus.toolkit.base.tsp.cube.CubeSeriesWithData; +import org.checkerframework.checker.nullness.qual.NonNull; import java.io.IOException; import java.util.Collections; @@ -50,37 +51,37 @@ public FakeDbConnection() { } @Override - public Optional testConnection() { + public @NonNull Optional testConnection() { return Optional.empty(); } @Override - public CubeId getRoot() { + public @NonNull CubeId getRoot() { return root; } @Override - public Stream getAllSeries(CubeId id) throws IOException { + public @NonNull Stream getAllSeries(@NonNull CubeId id) throws IOException { return toSeriesStream(data).filter(ts -> id.isAncestorOf(ts.getId())); } @Override - public Stream getAllSeriesWithData(CubeId id) throws IOException { + public @NonNull Stream getAllSeriesWithData(@NonNull CubeId id) throws IOException { return toSeriesWithDataStream(data).filter(ts -> id.isAncestorOf(ts.getId())); } @Override - public Optional getSeries(CubeId id) throws IOException { + public @NonNull Optional getSeries(@NonNull CubeId id) throws IOException { return toSeriesStream(data).filter(ts -> id.isAncestorOf(ts.getId())).findFirst(); } @Override - public Optional getSeriesWithData(CubeId id) throws IOException { + public @NonNull Optional getSeriesWithData(@NonNull CubeId id) throws IOException { return toSeriesWithDataStream(data).filter(ts -> id.isAncestorOf(ts.getId())).findFirst(); } @Override - public Stream getChildren(CubeId id) throws IOException { + public @NonNull Stream getChildren(@NonNull CubeId id) throws IOException { return data.keySet().stream() .filter(id::isAncestorOf) .map(o -> o.getDimensionValue(id.getLevel())) @@ -89,17 +90,17 @@ public Stream getChildren(CubeId id) throws IOException { } @Override - public String getDisplayName() throws IOException { + public @NonNull String getDisplayName() throws IOException { return "Fake"; } @Override - public String getDisplayName(CubeId id) throws IOException { + public @NonNull String getDisplayName(@NonNull CubeId id) throws IOException { return id.isVoid() ? "All" : id.getDimensionValueStream().collect(Collectors.joining(", ")); } @Override - public String getDisplayNodeName(CubeId id) throws IOException { + public @NonNull String getDisplayNodeName(@NonNull CubeId id) throws IOException { return id.isVoid() ? "All" : id.getDimensionValue(id.getLevel() - 1); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/poc/FakeDbParam.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/poc/FakeDbParam.java index d9b480a8..3846dae5 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/poc/FakeDbParam.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/poc/FakeDbParam.java @@ -48,7 +48,7 @@ public String getVersion() { } @Override - public FakeDbBean getDefaultValue() { + public @NonNull FakeDbBean getDefaultValue() { FakeDbBean result = new FakeDbBean(); result.setDbName(dbName.getDefaultValue()); result.setTableName(tableName.getDefaultValue()); @@ -56,7 +56,7 @@ public FakeDbBean getDefaultValue() { } @Override - public FakeDbBean get(DataSource dataSource) { + public @NonNull FakeDbBean get(@NonNull DataSource dataSource) { FakeDbBean result = new FakeDbBean(); result.setDbName(dbName.get(dataSource::getParameter)); result.setTableName(tableName.get(dataSource::getParameter)); @@ -64,7 +64,7 @@ public FakeDbBean get(DataSource dataSource) { } @Override - public void set(DataSource.Builder builder, FakeDbBean value) { + public void set(DataSource.@NonNull Builder builder, FakeDbBean value) { dbName.set(builder::parameter, value.getDbName()); tableName.set(builder::parameter, value.getTableName()); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/stream/TsStreamAsProviderTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/stream/TsStreamAsProviderTest.java index 40670068..54f49677 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/stream/TsStreamAsProviderTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/stream/TsStreamAsProviderTest.java @@ -16,12 +16,13 @@ */ package jdplus.toolkit.base.tsp.stream; -import _util.tsproviders.FailingTsCursorSupport; +import _test.tsproviders.FailingTsCursorSupport; import jdplus.toolkit.base.api.timeseries.*; import jdplus.toolkit.base.tsp.DataSet; import jdplus.toolkit.base.tsp.DataSource; import jdplus.toolkit.base.tsp.HasDataMoniker; import internal.toolkit.base.api.timeseries.util.TsDataBuilderUtil; +import org.checkerframework.checker.nullness.qual.NonNull; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -74,7 +75,7 @@ public class TsStreamAsProviderTest { s3 = Ts.builder().moniker(leaf3).type(All).name("leaf3").data(TsData.random(TsUnit.MONTH, 3)).meta(customMeta).build(); goodCursor = new HasTsStream() { @Override - public Stream getData(DataSource dataSource, TsInformationType type) throws IllegalArgumentException, IOException { + public @NonNull Stream getData(@NonNull DataSource dataSource, @NonNull TsInformationType type) throws IllegalArgumentException, IOException { if (dataSource.equals(ds)) { DataSet.Builder b = DataSet.builder(dataSource, SERIES); Function toDataSet = o -> { @@ -93,7 +94,7 @@ public Stream getData(DataSource dataSource, TsInformationType type) } @Override - public Stream getData(DataSet dataSet, TsInformationType type) throws IllegalArgumentException, IOException { + public @NonNull Stream getData(@NonNull DataSet dataSet, @NonNull TsInformationType type) throws IllegalArgumentException, IOException { return getData(dataSet.getDataSource(), type) .filter(o -> o.getId().getParameter("id").startsWith(dataSet.getParameter("id"))); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/util/ObsFormatTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/util/ObsFormatTest.java index 7cfe22ce..48c44afd 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/util/ObsFormatTest.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/util/ObsFormatTest.java @@ -30,8 +30,8 @@ import java.util.function.BiConsumer; import java.util.function.Function; -import static jdplus.toolkit.base.tsp.util.ObsFormat.*; import static java.util.Locale.*; +import static jdplus.toolkit.base.tsp.util.ObsFormat.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -180,7 +180,7 @@ public void testNewDateTimeFormatter() { assertThat(f1.parseBest("1 janv. 2000", temporalQueries)).isEqualTo(value); DateTimeFormatter f2 = builder().locale(US).build().newDateTimeFormatter(); - assertThat(f2.format(value)).isEqualTo("Jan 1, 2000 12:00:00 AM"); + assertThat(fixNNBSP(f2.format(value))).isEqualTo("Jan 1, 2000 12:00:00 AM"); assertThat(f2.parseBest("Jan 1, 2000", temporalQueries)).isEqualTo(value); DateTimeFormatter f3 = builder().locale(FRANCE).dateTimePattern("yyyy-MMM").build().newDateTimeFormatter(); @@ -229,4 +229,11 @@ private static char groupingSeparator(NumberFormat format) { private static char decimalSeparator(NumberFormat format) { return (((DecimalFormat) format).getDecimalFormatSymbols()).getDecimalSeparator(); } + + // Since JDK20: NBSP/NNBSP prefixed to AM/PM in time format, instead of a normal space + // See https://www.oracle.com/java/technologies/javase/20all-relnotes.html#JDK-8284840 + // See https://bugs.openjdk.org/browse/JDK-8304925 + private String fixNNBSP(String text) { + return text.replace('\u202f', ' '); + } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/util/ShortLivedCachingTest.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/util/ShortLivedCachingTest.java new file mode 100644 index 00000000..41d3fe6a --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/jdplus/toolkit/base/tsp/util/ShortLivedCachingTest.java @@ -0,0 +1,133 @@ +package jdplus.toolkit.base.tsp.util; + +import lombok.NonNull; +import org.assertj.core.api.Condition; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileTime; +import java.time.Duration; +import java.util.function.Consumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; + +public class ShortLivedCachingTest { + + @SuppressWarnings({"DataFlowIssue"}) + public static void assertCompliance( + @NonNull ShortLivedCaching factory, + @NonNull Consumer timeIncrementer, + @NonNull Consumer fileIncrementer, + @NonNull Path temp + ) throws IOException { + + assertThatNullPointerException().isThrownBy(() -> factory.ofTtl(null)); + assertThatNullPointerException().isThrownBy(() -> factory.ofFile(null)); + + assertTtl(factory, timeIncrementer); + assertFile(factory, fileIncrementer, temp); + } + + @SuppressWarnings({"DataFlowIssue"}) + private static void assertTtl(ShortLivedCaching factory, Consumer timeIncrementer) { + Duration ttl = Duration.ofMillis(10); + ShortLivedCache cache = factory.ofTtl(ttl); + + assertThatNullPointerException().isThrownBy(() -> cache.get(null)); + assertThatNullPointerException().isThrownBy(() -> cache.put(null, 1)); + assertThatNullPointerException().isThrownBy(() -> cache.put("k1", null)); + + assertThat(cache.get("k1")).isNull(); + assertThat(cache.get("k2")).isNull(); + + cache.put("k1", 1); + assertThat(cache.get("k1")).is(nullOrEqualTo(1)); + assertThat(cache.get("k2")).isNull(); + + cache.put("k1", 11); + assertThat(cache.get("k1")).is(nullOrEqualTo(11)); + assertThat(cache.get("k2")).isNull(); + + cache.put("k2", 2); + assertThat(cache.get("k1")).is(nullOrEqualTo(11)); + assertThat(cache.get("k2")).is(nullOrEqualTo(2)); + + timeIncrementer.accept(ttl.dividedBy(2)); + cache.put("k2", 22); + timeIncrementer.accept(ttl.dividedBy(2)); + + assertThat(cache.get("k1")).isNull(); + assertThat(cache.get("k2")).is(nullOrEqualTo(22)); + } + + @SuppressWarnings({"DataFlowIssue"}) + private static void assertFile(ShortLivedCaching factory, Consumer touch, Path temp) { + File file = create(temp); + touch.accept(file); + + ShortLivedCache cache = factory.ofFile(file); + + assertThatNullPointerException().isThrownBy(() -> cache.get(null)); + assertThatNullPointerException().isThrownBy(() -> cache.put(null, 1)); + assertThatNullPointerException().isThrownBy(() -> cache.put("k1", null)); + + assertThat(cache.get("k1")).isNull(); + assertThat(cache.get("k2")).isNull(); + + cache.put("k1", 1); + assertThat(cache.get("k1")).is(nullOrEqualTo(1)); + assertThat(cache.get("k2")).isNull(); + + cache.put("k1", 11); + assertThat(cache.get("k1")).is(nullOrEqualTo(11)); + assertThat(cache.get("k2")).isNull(); + + cache.put("k2", 2); + assertThat(cache.get("k1")).is(nullOrEqualTo(11)); + assertThat(cache.get("k2")).is(nullOrEqualTo(2)); + + touch.accept(file); + cache.put("k2", 22); + assertThat(cache.get("k1")).isNull(); + assertThat(cache.get("k2")).is(nullOrEqualTo(22)); + + touch.accept(file); + assertThat(cache.get("k1")).isNull(); + assertThat(cache.get("k2")).isNull(); + + delete(file); + cache.put("k2", 222); + assertThat(cache.get("k2")).isNull(); + } + + public static Condition nullOrEqualTo(V value) { + return new Condition<>((V found) -> found == null || found.equals(value), "null or equal to " + value); + } + + public static File create(Path temp) { + try { + return Files.createTempFile(temp, "test", ".tmp").toFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static void delete(File file) { + try { + Files.delete(file.toPath()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static void touch(File file, FileTime fileTime) { + try { + Files.setLastModifiedTime(file.toPath(), fileTime); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/test/tsprovider/grid/ArrayGridOutput.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/test/tsprovider/grid/ArrayGridOutput.java index b7575b61..5060011c 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/test/tsprovider/grid/ArrayGridOutput.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/test/tsprovider/grid/ArrayGridOutput.java @@ -19,6 +19,8 @@ import jdplus.toolkit.base.tsp.grid.GridDataType; import jdplus.toolkit.base.tsp.grid.GridLayout; import jdplus.toolkit.base.tsp.grid.GridOutput; +import org.checkerframework.checker.nullness.qual.NonNull; + import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -43,12 +45,12 @@ public final class ArrayGridOutput implements GridOutput { private final Map data = new HashMap<>(); @Override - public Set getDataTypes() { + public @NonNull Set getDataTypes() { return dataTypes; } @Override - public Stream open(String name, int rows, int columns) throws IOException { + public @NonNull Stream open(@NonNull String name, int rows, int columns) throws IOException { return new ArrayGridOutputStream(name, rows, columns); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/test/tsprovider/grid/Data.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/test/tsprovider/grid/Data.java index 73e75d26..8137f184 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/test/tsprovider/grid/Data.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/test/tsprovider/grid/Data.java @@ -28,99 +28,114 @@ @lombok.experimental.UtilityClass public class Data { - public final LocalDateTime JAN_2010 = LocalDate.of(2010, 1, 1).atStartOfDay(); - public final LocalDateTime FEB_2010 = LocalDate.of(2010, 2, 1).atStartOfDay(); - public final LocalDateTime MAR_2010 = LocalDate.of(2010, 3, 1).atStartOfDay(); + public final LocalDateTime JAN_ = LocalDate.of(2010, 1, 1).atStartOfDay(); + public final LocalDateTime FEB_ = LocalDate.of(2010, 2, 1).atStartOfDay(); + public final LocalDateTime MAR_ = LocalDate.of(2010, 3, 1).atStartOfDay(); public final ArrayGridInput EMPTY = ArrayGridInput.of(new Object[][]{}); public final ArrayGridInput HGRID = ArrayGridInput.of(new Object[][]{ - {null, JAN_2010, FEB_2010, MAR_2010}, + {null, JAN_, FEB_, MAR_}, {"S1", 3.14, 4.56, 7.89} }); + public final ArrayGridInput HGRID_GAP = ArrayGridInput.of(new Object[][]{ + {null, JAN_, FEB_, MAR_, null}, + {null, null, null, null, null}, + {"S1", 3.14, 4.56, 7.89, null}, + {null, null, null, null, null}, + }); + public final ArrayGridInput HGRID_OVERFLOW = ArrayGridInput.of(new Object[][]{ - {null, JAN_2010, FEB_2010, MAR_2010}, + {null, JAN_, FEB_, MAR_}, {"S1", 3.14, 4.56, 7.89, 666} }); public final ArrayGridInput HGRID_UNDERFLOW = ArrayGridInput.of(new Object[][]{ - {null, JAN_2010, FEB_2010, MAR_2010}, + {null, JAN_, FEB_, MAR_}, {"S1", 3.14, 4.56} }); public final ArrayGridInput HGRID_NULL_NAME = ArrayGridInput.of(new Object[][]{ - {null, JAN_2010, FEB_2010, MAR_2010}, + {null, JAN_, FEB_, MAR_}, {"S1", 3.14, 4.56, 7.89}, - {null, 3, 4, 5} + {null, 3333, 4444, 5555} }); public final ArrayGridInput HGRID_CORNER_LABEL = ArrayGridInput.of(new Object[][]{ - {"Date", JAN_2010, FEB_2010, MAR_2010}, + {"Dt", JAN_, FEB_, MAR_}, {"S1", 3.14, 4.56, 7.89} }); public final ArrayGridInput HGRID_NO_NAME = ArrayGridInput.of(new Object[][]{ - {JAN_2010, FEB_2010, MAR_2010}, + {JAN_, FEB_, MAR_}, {3.14, 4.56, 7.89} }); public final ArrayGridInput HGRID_MULTI_NAME = ArrayGridInput.of(new Object[][]{ - {null, null, JAN_2010, FEB_2010, MAR_2010}, + {null, null, JAN_, FEB_, MAR_}, {"G1", "S1", 3.14, 4.56, 7.89}, - {null, "S2", 3, 4, 5}, - {"G2", "S1", 7, 8, 9}, - {"S1", null, 0, 1, 2} + {null, "S2", 1003, 1004, 1005}, + {"G2", "S1", 1007, 1008, 1009}, + {"S1", null, 1000, 1001, 1002} }); public final ArrayGridInput VGRID = ArrayGridInput.of(new Object[][]{ {null, "S1"}, - {JAN_2010, 3.14}, - {FEB_2010, 4.56}, - {MAR_2010, 7.89} + {JAN_, 3.14}, + {FEB_, 4.56}, + {MAR_, 7.89} + }); + + public final ArrayGridInput VGRID_GAP = ArrayGridInput.of(new Object[][]{ + {null, null, "S1", null}, + {JAN_, null, 3.14, null}, + {FEB_, null, 4.56, null}, + {MAR_, null, 7.89, null}, + {null, null, null, null} }); public final ArrayGridInput VGRID_OVERFLOW = ArrayGridInput.of(new Object[][]{ {null, "S1"}, - {JAN_2010, 3.14}, - {FEB_2010, 4.56}, - {MAR_2010, 7.89}, + {JAN_, 3.14}, + {FEB_, 4.56}, + {MAR_, 7.89}, {null, 666} }); public final ArrayGridInput VGRID_UNDERFLOW = ArrayGridInput.of(new Object[][]{ {null, "S1"}, - {JAN_2010, 3.14}, - {FEB_2010, 4.56}, - {MAR_2010} + {JAN_, 3.14}, + {FEB_, 4.56}, + {MAR_} }); public final ArrayGridInput VGRID_NULL_NAME = ArrayGridInput.of(new Object[][]{ {null, "S1", null}, - {JAN_2010, 3.14, 3}, - {FEB_2010, 4.56, 4}, - {MAR_2010, 7.89, 5} + {JAN_, 3.14, 3333}, + {FEB_, 4.56, 4444}, + {MAR_, 7.89, 5555} }); public final ArrayGridInput VGRID_CORNER_LABEL = ArrayGridInput.of(new Object[][]{ - {"Date", "S1"}, - {JAN_2010, 3.14}, - {FEB_2010, 4.56}, - {MAR_2010, 7.89} + {"Dt", "S1"}, + {JAN_, 3.14}, + {FEB_, 4.56}, + {MAR_, 7.89} }); public final ArrayGridInput VGRID_NO_NAME = ArrayGridInput.of(new Object[][]{ - {JAN_2010, 3.14}, - {FEB_2010, 4.56}, - {MAR_2010, 7.89} + {JAN_, 3.14}, + {FEB_, 4.56}, + {MAR_, 7.89} }); public final ArrayGridInput VGRID_MULTI_NAME = ArrayGridInput.of(new Object[][]{ {null, "G1", null, "G2", "S1"}, {null, "S1", "S2", "S1", null}, - {JAN_2010, 3.14, 3, 7, 0}, - {FEB_2010, 4.56, 4, 8, 1}, - {MAR_2010, 7.89, 5, 9, 2} + {JAN_, 3.14, 1003, 1007, 1000}, + {FEB_, 4.56, 1004, 1008, 1001}, + {MAR_, 7.89, 1005, 1009, 1002} }); public static TsData d(TsUnit freq, int year, int position, double... values) { @@ -141,10 +156,6 @@ public static Ts s(String name, TsData data) { .build(); } - public static TsCollection c(GridLayout layout, String seriesName, TsData data) { - return c(layout, s(seriesName, data)); - } - public static TsCollection c(GridLayout layout, Ts ts) { return TsCollection.builder() .type(TsInformationType.Data) diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/pom.xml b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/pom.xml index 3c35c751..47c34094 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/pom.xml +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-toolkit-base-parent - 3.0.2 + 3.1.0 jdplus-toolkit-base-tspbridge diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/main/java/jdplus/toolkit/base/tspbridge/ToDataSourceProvider.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/main/java/jdplus/toolkit/base/tspbridge/ToDataSourceProvider.java index 761baeb2..270f4df2 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/main/java/jdplus/toolkit/base/tspbridge/ToDataSourceProvider.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/main/java/jdplus/toolkit/base/tspbridge/ToDataSourceProvider.java @@ -32,7 +32,7 @@ public ec.tss.tsproviders.IDataSourceProvider getDelegate() { } @Override - public void reload(DataSource dataSource) { + public void reload(@NonNull DataSource dataSource) { getDelegate().reload(TsConverter.fromDataSource(dataSource)); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/main/java/jdplus/toolkit/base/tspbridge/demo/PocProvider.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/main/java/jdplus/toolkit/base/tspbridge/demo/PocProvider.java index a140cfab..9a7c67b7 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/main/java/jdplus/toolkit/base/tspbridge/demo/PocProvider.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/main/java/jdplus/toolkit/base/tspbridge/demo/PocProvider.java @@ -25,6 +25,7 @@ import nbbrd.io.text.Formatter; import nbbrd.io.text.Parser; import nbbrd.io.text.Property; +import org.checkerframework.checker.nullness.qual.NonNull; import java.io.IOException; import java.io.UncheckedIOException; @@ -108,7 +109,7 @@ private static DataSource createDataSource(DataType o) { private static final class PocDataDisplayName implements HasDataDisplayName { @Override - public String getDisplayName(DataSource dataSource) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSource dataSource) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(NAME, dataSource); switch (TYPE_PARAM.get(dataSource::getParameter)) { case NORMAL: @@ -129,13 +130,13 @@ public String getDisplayName(DataSource dataSource) throws IllegalArgumentExcept } @Override - public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(NAME, dataSet); return getDisplayName(dataSet.getDataSource()) + System.lineSeparator() + getDisplayNodeName(dataSet); } @Override - public String getDisplayNodeName(DataSet dataSet) throws IllegalArgumentException { + public @NonNull String getDisplayNodeName(@NonNull DataSet dataSet) throws IllegalArgumentException { DataSourcePreconditions.checkProvider(NAME, dataSet); TsDomain domain = TYPE_PARAM.get(dataSet.getDataSource()::getParameter).getDomain(INDEX_PARAM.get(dataSet::getParameter)); return domain.getStartPeriod().getUnit() + "#" + domain.getLength(); @@ -155,7 +156,7 @@ public PocDataSupport() { } @Override - public List children(DataSource dataSource) throws IllegalArgumentException, IOException { + public @NonNull List children(@NonNull DataSource dataSource) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(NAME, dataSource); try (Stream cursor = cursorOf(dataSource, TsInformationType.Definition)) { return cursor.map(DataSetTs::getId).collect(Collectors.toList()); @@ -165,19 +166,19 @@ public List children(DataSource dataSource) throws IllegalArgumentExcep } @Override - public List children(DataSet parent) throws IllegalArgumentException, IOException { + public @NonNull List children(@NonNull DataSet parent) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(NAME, parent); throw new IllegalArgumentException("Invalid hierarchy"); } @Override - public Stream getData(DataSource dataSource, TsInformationType type) throws IllegalArgumentException, IOException { + public @NonNull Stream getData(@NonNull DataSource dataSource, @NonNull TsInformationType type) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(NAME, dataSource); return cursorOf(dataSource, type); } @Override - public Stream getData(DataSet dataSet, TsInformationType type) throws IllegalArgumentException, IOException { + public @NonNull Stream getData(@NonNull DataSet dataSet, @NonNull TsInformationType type) throws IllegalArgumentException, IOException { DataSourcePreconditions.checkProvider(NAME, dataSet); if (!dataSet.getKind().equals(DataSet.Kind.SERIES)) { throw new IllegalArgumentException("Invalid hierarchy"); diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/test/java/_util/MockedDataSourceLoader.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/test/java/_util/MockedDataSourceLoader.java index 6ca53766..22b4ec3f 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/test/java/_util/MockedDataSourceLoader.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tspbridge/src/test/java/_util/MockedDataSourceLoader.java @@ -29,7 +29,7 @@ public final class MockedDataSourceLoader implements DataSourceLoader { } @Override - public void set(@lombok.NonNull DataSource.Builder builder, @Nullable String value) { + public void set(@lombok.NonNull DataSource.@NonNull Builder builder, @Nullable String value) { property.set(builder::parameter, value); } }; diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-workspace/pom.xml b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-workspace/pom.xml index 9cc6035d..ad820b13 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-workspace/pom.xml +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-workspace/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-toolkit-base-parent - 3.0.2 + 3.1.0 jdplus-toolkit-base-workspace diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/pom.xml b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/pom.xml index 8e7a98e1..5d6f5ad8 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/pom.xml +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/pom.xml @@ -4,7 +4,7 @@ eu.europa.ec.joinup.sat jdplus-toolkit-base-parent - 3.0.2 + 3.1.0 jdplus-toolkit-base-xml diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlInformation.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlInformation.java index 9b8eb595..b7839bbb 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlInformation.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlInformation.java @@ -38,6 +38,7 @@ import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.adapters.XmlAdapter; import jdplus.toolkit.base.api.math.matrices.Matrix; +import jdplus.toolkit.base.api.timeseries.TsUnit; /** * @@ -128,6 +129,12 @@ public class XmlInformation { fromXmlMap.put(XmlTsMoniker.class, monikerMapper); toXmlMap.put(TsMoniker.class, monikerMapper); + XmlConverterAdapter unitMapper + = new XmlConverterAdapter<>(XmlTsUnit.class); + + fromXmlMap.put(XmlTsUnit.class, unitMapper); + toXmlMap.put(TsUnit.class, unitMapper); + XmlConverterAdapter tsMapper = new XmlConverterAdapter<>(XmlTs.class); @@ -186,6 +193,7 @@ public class XmlInformation { @XmlElement(type = XmlTsData.class, name = "tsdata"), @XmlElement(type = XmlTsMoniker.class, name = "moniker"), @XmlElement(type = XmlTs.class, name = "ts"), + @XmlElement(type = XmlTsUnit.class, name = "tsunit"), @XmlElement(type = XmlTsCollection.class, name = "tscollection"), @XmlElement(type = XmlPeriodSelection.class, name = "span"), @XmlElement(type = XmlStatisticalTest.class, name = "test"), diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTs.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTs.java index 06ed5634..32f8cece 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTs.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTs.java @@ -16,6 +16,8 @@ */ package jdplus.toolkit.base.xml.information; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import jdplus.toolkit.base.api.timeseries.Ts; import jdplus.toolkit.base.api.timeseries.TsData; import jdplus.toolkit.base.api.timeseries.TsInformationType; @@ -28,6 +30,7 @@ import javax.xml.bind.annotation.XmlList; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; +import jdplus.toolkit.base.api.data.Doubles; /** * @@ -56,6 +59,13 @@ public class XmlTs implements IXmlConverter { @XmlElement public Integer firstPeriod; + // Alternative storage for more general tsdata (high-frequency) + @XmlElement + public XmlTsUnit unit; + + @XmlElement + public String start; + /** * */ @@ -91,10 +101,17 @@ public class XmlTs implements IXmlConverter { @Override public void copy(Ts t) { TsData tsdata = t.getData(); - TsPeriod start = tsdata.getStart(); - freq = start.getUnit().getAnnualFrequency(); - firstYear = start.year(); - firstPeriod = start.annualPosition() + 1; + TsPeriod tstart = tsdata.getStart(); + int ifreq = tstart.getUnit().getAnnualFrequency(); + if (ifreq > 0) { + freq=ifreq; + firstYear = tstart.year(); + firstPeriod = tstart.annualPosition() + 1; + } else { + unit = new XmlTsUnit(); + unit.copy(tstart.getUnit()); + start = tstart.start().format(DateTimeFormatter.ISO_DATE_TIME); + } data = tsdata.getValues().toArray(); source = t.getMoniker().getSource(); identifier = t.getMoniker().getId(); @@ -112,7 +129,7 @@ public void copy(Ts t) { */ @Override public Ts create() { - TsMoniker moniker = (source == null && identifier == null)? TsMoniker.of() : TsMoniker.of(source, identifier); + TsMoniker moniker = (source == null && identifier == null) ? TsMoniker.of() : TsMoniker.of(source, identifier); Ts.Builder info = Ts.builder() .name(name) .moniker(moniker) @@ -122,7 +139,15 @@ public Ts create() { info.meta(metaData.create()); } if (data != null) { - info.data(XmlTsData.of(freq, firstYear, firstPeriod, data)); + if (freq != null) { + info.data(XmlTsData.of(freq, firstYear, firstPeriod, data)); + } else { + LocalDateTime tstart = LocalDateTime.parse(start, DateTimeFormatter.ISO_DATE_TIME); + TsPeriod pstart = TsPeriod.of(unit.create(), tstart); + info.data(TsData.ofInternal(pstart, data == null ? Doubles.EMPTYARRAY : data)); + + } + } return info.build(); } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTsData.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTsData.java index a7d3c304..1e5363f7 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTsData.java +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTsData.java @@ -22,6 +22,9 @@ import jdplus.toolkit.base.api.timeseries.TsUnit; import jdplus.toolkit.base.xml.legacy.IXmlConverter; import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlList; @@ -42,17 +45,24 @@ public class XmlTsData implements IXmlConverter { * */ @XmlElement - public int freq; + public Integer freq; /** * */ @XmlElement - public int firstYear; + public Integer firstYear; /** * */ @XmlElement public Integer firstPeriod; + + // Alternative storage for more general tsdata (high-frequency) + @XmlElement + public XmlTsUnit unit; + + @XmlElement + public String start; /** * */ @@ -69,13 +79,20 @@ public class XmlTsData implements IXmlConverter { */ @Override public void copy(TsData t) { - TsPeriod start = t.getStart(); - freq = start.getUnit().getAnnualFrequency(); - firstYear = start.year(); - if (freq != 1) { - firstPeriod = start.annualPosition() + 1; + TsPeriod tstart = t.getStart(); + int ifreq = tstart.getUnit().getAnnualFrequency(); + if (ifreq > 0) { + freq=ifreq; + firstYear = tstart.year(); + if (freq != 1) { + firstPeriod = tstart.annualPosition() + 1; + } else { + firstPeriod = null; + } } else { - firstPeriod = null; + unit=new XmlTsUnit(); + unit.copy(tstart.getUnit()); + start = tstart.start().format(DateTimeFormatter.ISO_DATE_TIME); } if (!t.getValues().isEmpty()) { data = t.getValues().toArray(); @@ -88,19 +105,28 @@ public void copy(TsData t) { */ @Override public TsData create() { - return of(freq, firstYear, firstPeriod, data); + if (freq != null) { + return of(freq, firstYear, firstPeriod, data); + } else { + LocalDateTime tstart=LocalDateTime.parse(start, DateTimeFormatter.ISO_DATE_TIME); + TsPeriod pstart=TsPeriod.of(unit.create(), tstart); + return TsData.ofInternal(pstart, data == null ? Doubles.EMPTYARRAY : data); + } } static TsData of(int freq, int year, int period, double[] data) { switch (freq) { - case 1: + case 1 -> { return TsData.ofInternal(TsPeriod.yearly(year), data); - case 12: + } + case 12 -> { return TsData.ofInternal(TsPeriod.monthly(year, period), data); - default: + } + default -> { int c = 12 / freq; TsPeriod pstart = TsPeriod.of(TsUnit.ofAnnualFrequency(freq), LocalDate.of(year, (period - 1) * c + 1, 1)); return TsData.ofInternal(pstart, data == null ? Doubles.EMPTYARRAY : data); + } } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTsUnit.java b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTsUnit.java new file mode 100644 index 00000000..810c8264 --- /dev/null +++ b/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-xml/src/main/java/jdplus/toolkit/base/xml/information/XmlTsUnit.java @@ -0,0 +1,65 @@ +/* +* Copyright 2013 National Bank of Belgium +* +* Licensed under the EUPL, Version 1.1 or – as soon they will be approved +* by the European Commission - subsequent versions of the EUPL (the "Licence"); +* You may not use this work except in compliance with the Licence. +* You may obtain a copy of the Licence at: +* +* http://ec.europa.eu/idabc/eupl +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the Licence is distributed on an "AS IS" basis, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the Licence for the specific language governing permissions and +* limitations under the Licence. +*/ + +package jdplus.toolkit.base.xml.information; + +import java.time.temporal.ChronoUnit; +import jdplus.toolkit.base.api.timeseries.TsMoniker; +import jdplus.toolkit.base.xml.legacy.IXmlConverter; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import jdplus.toolkit.base.api.timeseries.TsUnit; + +/** + * + * @author Jean Palate + */ +@XmlType(name = XmlTsUnit.NAME) +public class XmlTsUnit implements IXmlConverter { + + static final String NAME = "tsUnitType"; + /** + * + */ + @XmlElement + public String unit; + /** + * + */ + @XmlElement + public int amount; + /** + * + * @param tunit + */ + @Override + public void copy(TsUnit tunit) + { + unit = tunit.getChronoUnit().name(); + amount = (int)tunit.getAmount(); + } + + /** + * + * @return + */ + @Override + public TsUnit create() + { + return TsUnit.of(amount, ChronoUnit.valueOf(unit)); + } +} diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/pom.xml b/jdplus-main-base/jdplus-toolkit-base-parent/pom.xml index cb354fec..9fb69a21 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/pom.xml +++ b/jdplus-main-base/jdplus-toolkit-base-parent/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-main-base - 3.0.2 + 3.1.0 jdplus-toolkit-base-parent diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-api/pom.xml b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-api/pom.xml index f5e17a59..f0821ab0 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-api/pom.xml +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-api/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-tramoseats-base-parent - 3.0.2 + 3.1.0 jdplus-tramoseats-base-api diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-api/src/test/java/jdplus/tramoseats/base/api/tramoseats/TramoSeatsDictionariesTest.java b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-api/src/test/java/jdplus/tramoseats/base/api/tramoseats/TramoSeatsDictionariesTest.java index 0c224ceb..315a0290 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-api/src/test/java/jdplus/tramoseats/base/api/tramoseats/TramoSeatsDictionariesTest.java +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-api/src/test/java/jdplus/tramoseats/base/api/tramoseats/TramoSeatsDictionariesTest.java @@ -4,8 +4,6 @@ */ package jdplus.tramoseats.base.api.tramoseats; -import jdplus.tramoseats.base.api.tramoseats.TramoSeatsDictionaries; - /** * * @author PALATEJ diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-core/pom.xml b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-core/pom.xml index e8c6a86f..6f8588b8 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-core/pom.xml +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-core/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-tramoseats-base-parent - 3.0.2 + 3.1.0 jdplus-tramoseats-base-core diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-information/pom.xml b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-information/pom.xml index bfc572f0..6f8965a0 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-information/pom.xml +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-information/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-tramoseats-base-parent - 3.0.2 + 3.1.0 jdplus-tramoseats-base-information diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-protobuf/pom.xml b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-protobuf/pom.xml index a0c08e23..5290ca2a 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-protobuf/pom.xml +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-protobuf/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-tramoseats-base-parent - 3.0.2 + 3.1.0 jdplus-tramoseats-base-protobuf diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/pom.xml b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/pom.xml index c7c68950..181a43ec 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/pom.xml +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-tramoseats-base-parent - 3.0.2 + 3.1.0 jdplus-tramoseats-base-r diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/jdplus/tramoseats/base/r/TramoSeats.java b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/jdplus/tramoseats/base/r/TramoSeats.java index 5fd6fc2a..aa1dcd3a 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/jdplus/tramoseats/base/r/TramoSeats.java +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/jdplus/tramoseats/base/r/TramoSeats.java @@ -21,6 +21,7 @@ import jdplus.toolkit.base.api.timeseries.TsData; import jdplus.toolkit.base.api.timeseries.TsDomain; import jdplus.toolkit.base.api.timeseries.regression.ModellingContext; +import jdplus.tramoseats.base.api.tramoseats.TramoSeatsDictionaries; import jdplus.tramoseats.base.api.tramoseats.TramoSeatsSpec; import jdplus.tramoseats.base.protobuf.Spec; import jdplus.tramoseats.base.protobuf.SpecProto; @@ -90,5 +91,9 @@ public TramoSeatsOutput fullProcess(TsData series, String defSpec) { public byte[] toBuffer(TramoSeatsOutput output) { return TramoSeatsProtosUtility.convert(output).toByteArray(); } + + public String[] dictionary(){ + return TramoSeatsDictionaries.TRAMOSEATSDICTIONARY.entries().map(entry->entry.fullName()).toArray(n->new String[n]); + } } diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/jdplus/tramoseats/base/r/TramoSeatsRevisionHistory.java b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/jdplus/tramoseats/base/r/TramoSeatsRevisionHistory.java new file mode 100644 index 00000000..cd1d1117 --- /dev/null +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/jdplus/tramoseats/base/r/TramoSeatsRevisionHistory.java @@ -0,0 +1,42 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.tramoseats.base.r; + +import jdplus.toolkit.base.api.processing.ProcessingLog; +import jdplus.toolkit.base.api.timeseries.TsData; +import jdplus.toolkit.base.api.timeseries.regression.ModellingContext; +import jdplus.toolkit.base.core.timeseries.simplets.analysis.RevisionHistory; +import jdplus.toolkit.base.r.timeseries.Revisions; +import jdplus.tramoseats.base.api.tramoseats.TramoSeatsSpec; +import jdplus.tramoseats.base.core.tramoseats.TramoSeatsKernel; +import jdplus.tramoseats.base.core.tramoseats.TramoSeatsResults; + +/** + * + * @author palatej + */ +@lombok.experimental.UtilityClass +public class TramoSeatsRevisionHistory { + + + public Revisions revisions(TsData series, TramoSeatsSpec spec, ModellingContext context) { + TramoSeatsKernel kernel = TramoSeatsKernel.of(spec, context); + RevisionHistory rh = new RevisionHistory<>(series.getDomain(), d -> kernel.process(TsData.fitToDomain(series, d), ProcessingLog.dummy())); + return new Revisions<>(rh); + } + +} diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/module-info.java b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/module-info.java index 1819d255..240516be 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/module-info.java +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-r/src/main/java/module-info.java @@ -5,12 +5,13 @@ requires static nbbrd.service; requires static org.checkerframework.checker.qual; - requires transitive jdplus.tramoseats.base.api; - requires com.google.protobuf; - requires jdplus.tramoseats.base.protobuf; - requires jdplus.tramoseats.base.core; requires jdplus.toolkit.base.core; requires jdplus.toolkit.base.protobuf; - + requires jdplus.toolkit.base.r; + requires transitive jdplus.tramoseats.base.api; + requires jdplus.tramoseats.base.core; + requires jdplus.tramoseats.base.protobuf; + requires protobuf.java; + exports jdplus.tramoseats.base.r; } \ No newline at end of file diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-workspace/pom.xml b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-workspace/pom.xml index 9faa41ca..c526eb18 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-workspace/pom.xml +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-workspace/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-tramoseats-base-parent - 3.0.2 + 3.1.0 jdplus-tramoseats-base-workspace diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-xml/pom.xml b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-xml/pom.xml index 9bffeb7c..bf5c4b79 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-xml/pom.xml +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/jdplus-tramoseats-base-xml/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-tramoseats-base-parent - 3.0.2 + 3.1.0 jdplus-tramoseats-base-xml diff --git a/jdplus-main-base/jdplus-tramoseats-base-parent/pom.xml b/jdplus-main-base/jdplus-tramoseats-base-parent/pom.xml index bb929078..747c155e 100644 --- a/jdplus-main-base/jdplus-tramoseats-base-parent/pom.xml +++ b/jdplus-main-base/jdplus-tramoseats-base-parent/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-main-base - 3.0.2 + 3.1.0 jdplus-tramoseats-base-parent diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-api/pom.xml b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-api/pom.xml index cbd1b6c7..70dabd86 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-api/pom.xml +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-api/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-x13-base-parent - 3.0.2 + 3.1.0 jdplus-x13-base-api diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/pom.xml b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/pom.xml index 0de574fd..de825fc2 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/pom.xml +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-x13-base-parent - 3.0.2 + 3.1.0 jdplus-x13-base-core diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/main/java/jdplus/x13/base/core/x11/X11Kernel.java b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/main/java/jdplus/x13/base/core/x11/X11Kernel.java index 1497fa9e..2f8ab70b 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/main/java/jdplus/x13/base/core/x11/X11Kernel.java +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/main/java/jdplus/x13/base/core/x11/X11Kernel.java @@ -17,7 +17,6 @@ import jdplus.x13.base.core.x11.pseudoadd.X11CStepPseudoAdd; import jdplus.x13.base.core.x11.pseudoadd.X11DStepPseudoAdd; import java.util.Arrays; -import jdplus.toolkit.base.api.timeseries.TsDomain; import jdplus.toolkit.base.core.data.DataBlock; import jdplus.toolkit.base.core.math.linearfilters.FiniteFilter; import jdplus.toolkit.base.core.math.linearfilters.SymmetricFilter; diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/main/java/jdplus/x13/base/core/x13/extractors/X11Extractor.java b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/main/java/jdplus/x13/base/core/x13/extractors/X11Extractor.java index e60d7f60..0947333c 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/main/java/jdplus/x13/base/core/x13/extractors/X11Extractor.java +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/main/java/jdplus/x13/base/core/x13/extractors/X11Extractor.java @@ -16,6 +16,7 @@ */ package jdplus.x13.base.core.x13.extractors; +import jdplus.sa.base.api.SaDictionaries; import jdplus.toolkit.base.api.information.InformationExtractor; import jdplus.toolkit.base.api.information.InformationMapping; import jdplus.toolkit.base.api.timeseries.TsData; @@ -45,6 +46,7 @@ public X11Extractor() { //// set(SaDictionaries.S_CMP+ SeriesInfo.F_SUFFIX, TsData.class, source->source.getD10a()); // set(SaDictionaries.I_CMP, TsData.class, source -> source.getD13()); + set(SaDictionaries.MODE, String.class, source ->source.getMode().name()); set(X11Dictionaries.B1, TsData.class, source -> source.getB1()); set(X11Dictionaries.B2, TsData.class, source -> source.getB2()); set(X11Dictionaries.B3, TsData.class, source -> source.getB3()); diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/test/java/jdplus/x13/base/core/x11/TrendCrossValidationTest.java b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/test/java/jdplus/x13/base/core/x11/TrendCrossValidationTest.java index 7ca7f97a..818cee9b 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/test/java/jdplus/x13/base/core/x11/TrendCrossValidationTest.java +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-core/src/test/java/jdplus/x13/base/core/x11/TrendCrossValidationTest.java @@ -25,7 +25,7 @@ public void testProd() { double[] cv = TrendCrossValidation.process(DoubleSeq.of(Data.ABS_RETAIL), 12, true, 3, 25, h -> LocalPolynomialFilters.of(h, 3, DiscreteKernel.henderson(h))); // long t0 = System.currentTimeMillis(); // for (int i = 0; i < 1000; ++i) { -// cv = TrendCrossValidation.process(DoubleSeq.of(Data.ABS_RETAIL), 12, true, 3, 25, h -> LocalPolynomialFilters.of(h, 3, DiscreteKernel.biweight(h))); +// cv = TrendCrossValidation.process(DoubleSeq.of(Data.ABS_RETAIL), 12, true, 3, 25, h -> LocalPolynomialFiltersFactory.of(h, 3, DiscreteKernel.biweight(h))); // } // long t1 = System.currentTimeMillis(); // System.out.println(t1 - t0); diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-information/pom.xml b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-information/pom.xml index 4939c533..bbf8018a 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-information/pom.xml +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-information/pom.xml @@ -4,7 +4,7 @@ eu.europa.ec.joinup.sat jdplus-x13-base-parent - 3.0.2 + 3.1.0 jdplus-x13-base-information diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-protobuf/pom.xml b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-protobuf/pom.xml index c2ab4a02..9bff05ba 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-protobuf/pom.xml +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-protobuf/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-x13-base-parent - 3.0.2 + 3.1.0 jdplus-x13-base-protobuf diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/pom.xml b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/pom.xml index f01c249b..39fa4415 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/pom.xml +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-x13-base-parent - 3.0.2 + 3.1.0 jdplus-x13-base-r diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/jdplus/x13/base/r/X13.java b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/jdplus/x13/base/r/X13.java index d3a3be94..f9d51129 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/jdplus/x13/base/r/X13.java +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/jdplus/x13/base/r/X13.java @@ -21,6 +21,7 @@ import jdplus.toolkit.base.api.timeseries.TsData; import jdplus.toolkit.base.api.timeseries.TsDomain; import jdplus.toolkit.base.api.timeseries.regression.ModellingContext; +import jdplus.x13.base.api.x13.X13Dictionaries; import jdplus.x13.base.api.x13.X13Spec; import jdplus.x13.base.protobuf.Spec; import jdplus.x13.base.protobuf.SpecProto; @@ -90,4 +91,7 @@ public byte[] toBuffer(X13Output output) { return X13ProtosUtility.convert(output).toByteArray(); } + public String[] dictionary(){ + return X13Dictionaries.X13DICTIONARY.entries().map(entry->entry.fullName()).toArray(n->new String[n]); + } } diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/jdplus/x13/base/r/X13RevisionHistory.java b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/jdplus/x13/base/r/X13RevisionHistory.java new file mode 100644 index 00000000..bcd3d166 --- /dev/null +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/jdplus/x13/base/r/X13RevisionHistory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.x13.base.r; + +import jdplus.toolkit.base.api.processing.ProcessingLog; +import jdplus.toolkit.base.api.timeseries.TsData; +import jdplus.toolkit.base.api.timeseries.regression.ModellingContext; +import jdplus.toolkit.base.core.timeseries.simplets.analysis.RevisionHistory; +import jdplus.toolkit.base.r.timeseries.Revisions; +import jdplus.x13.base.api.x13.X13Spec; +import jdplus.x13.base.core.x13.X13Kernel; +import jdplus.x13.base.core.x13.X13Results; + +/** + * + * @author palatej + */ +@lombok.experimental.UtilityClass +public class X13RevisionHistory { + + public Revisions revisions(TsData series, X13Spec spec, ModellingContext context) { + X13Kernel kernel = X13Kernel.of(spec, context); + RevisionHistory rh = new RevisionHistory<>(series.getDomain(), d -> kernel.process(TsData.fitToDomain(series, d), ProcessingLog.dummy())); + return new Revisions<>(rh); + } +} diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/module-info.java b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/module-info.java index 07147723..93d86d42 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/module-info.java +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-r/src/main/java/module-info.java @@ -5,11 +5,12 @@ requires static nbbrd.service; requires static org.checkerframework.checker.qual; - requires transitive jdplus.x13.base.api; - requires jdplus.toolkit.base.protobuf; - requires jdplus.x13.base.protobuf; requires jdplus.toolkit.base.core; + requires jdplus.toolkit.base.r; + requires jdplus.toolkit.base.protobuf; + requires transitive jdplus.x13.base.api; requires jdplus.x13.base.core; - + requires jdplus.x13.base.protobuf; + exports jdplus.x13.base.r; -} \ No newline at end of file +} diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-workspace/pom.xml b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-workspace/pom.xml index 032e6c19..1a60283f 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-workspace/pom.xml +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-workspace/pom.xml @@ -4,7 +4,7 @@ eu.europa.ec.joinup.sat jdplus-x13-base-parent - 3.0.2 + 3.1.0 jdplus-x13-base-workspace diff --git a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-xml/pom.xml b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-xml/pom.xml index ea65e6dc..e34c6cc7 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-xml/pom.xml +++ b/jdplus-main-base/jdplus-x13-base-parent/jdplus-x13-base-xml/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-x13-base-parent - 3.0.2 + 3.1.0 jdplus-x13-base-xml diff --git a/jdplus-main-base/jdplus-x13-base-parent/pom.xml b/jdplus-main-base/jdplus-x13-base-parent/pom.xml index 69f2d44c..89f956c0 100644 --- a/jdplus-main-base/jdplus-x13-base-parent/pom.xml +++ b/jdplus-main-base/jdplus-x13-base-parent/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-main-base - 3.0.2 + 3.1.0 jdplus-x13-base-parent diff --git a/jdplus-main-base/pom.xml b/jdplus-main-base/pom.xml index 45b7e629..b58912f9 100644 --- a/jdplus-main-base/pom.xml +++ b/jdplus-main-base/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main - 3.0.2 + 3.1.0 jdplus-main-base diff --git a/jdplus-main-bom/pom.xml b/jdplus-main-bom/pom.xml index 8f649622..4f18bbd2 100644 --- a/jdplus-main-bom/pom.xml +++ b/jdplus-main-bom/pom.xml @@ -7,7 +7,7 @@ eu.europa.ec.joinup.sat jdplus-main - 3.0.2 + 3.1.0 jdplus-main-bom @@ -17,6 +17,10 @@ ${project.parent.artifactId} - ${project.artifactId} ${project.parent.url} + + jdk-17.0.8.1+1 + + @@ -37,7 +41,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.4.1 + 1.5.0 bom ${project.build.directory} @@ -61,7 +65,6 @@ full-release - jdk-17.0.7+7 ${java.bundled.version}-jre @@ -140,7 +143,7 @@ org.jreleaser jdks-maven-plugin - 1.6.0 + 1.8.0 download-windows-jre @@ -241,7 +244,7 @@ org.jreleaser jreleaser-maven-plugin - 1.5.1 + 1.8.0 release-assets diff --git a/jdplus-main-cli/jdplus-main-cli-bin/pom.xml b/jdplus-main-cli/jdplus-main-cli-bin/pom.xml index 1eeced86..378bf040 100644 --- a/jdplus-main-cli/jdplus-main-cli-bin/pom.xml +++ b/jdplus-main-cli/jdplus-main-cli-bin/pom.xml @@ -7,7 +7,7 @@ eu.europa.ec.joinup.sat jdplus-main-cli - 3.0.2 + 3.1.0 jdplus-main-cli-bin diff --git a/jdplus-main-cli/jdplus-main-cli-bin/src/main/java/jdplus/cruncher/App.java b/jdplus-main-cli/jdplus-main-cli-bin/src/main/java/jdplus/cruncher/App.java index 6179840c..9b991f2a 100644 --- a/jdplus-main-cli/jdplus-main-cli-bin/src/main/java/jdplus/cruncher/App.java +++ b/jdplus-main-cli/jdplus-main-cli-bin/src/main/java/jdplus/cruncher/App.java @@ -130,15 +130,18 @@ private static void process(FileWorkspace ws, ModellingContext context, WsaConfi EstimationPolicy policy = new EstimationPolicy(config.getPolicy(), null); List output = createOutputFactories(config); + TsInformationType type = config.refresh ? TsInformationType.Data : TsInformationType.None; for (Entry o : sa.entrySet()) { - process(ws, o.getKey(), o.getValue(), context, output, bundleSize, policy); + process(ws, o.getKey(), o.getValue(), context, output, bundleSize, policy, type); } } - private static void process(FileWorkspace ws, WorkspaceItemDescriptor item, SaItems processing, ModellingContext context, List output, int bundleSize, EstimationPolicy policy) throws IOException { + private static void process(FileWorkspace ws, WorkspaceItemDescriptor item, SaItems processing, ModellingContext context, + List output, int bundleSize, EstimationPolicy policy, TsInformationType type) throws IOException { - System.out.println("Refreshing data"); - TsInformationType type=policy.getPolicy() == EstimationPolicyType.None ? TsInformationType.None : TsInformationType.Data; + if (type != TsInformationType.None) { + System.out.println("Refreshing data"); + } List all = processing.getItems().stream().map(cur -> cur.refresh(policy, type)).collect(Collectors.toList()); SaBatchInformation info = new SaBatchInformation(all.size() > bundleSize ? bundleSize : 0); info.setName(item.getKey().getId()); diff --git a/jdplus-main-cli/jdplus-main-cli-design/pom.xml b/jdplus-main-cli/jdplus-main-cli-design/pom.xml index d9285e36..497a3bec 100644 --- a/jdplus-main-cli/jdplus-main-cli-design/pom.xml +++ b/jdplus-main-cli/jdplus-main-cli-design/pom.xml @@ -7,7 +7,7 @@ eu.europa.ec.joinup.sat jdplus-main-cli - 3.0.2 + 3.1.0 jdplus-main-cli-design diff --git a/jdplus-main-cli/jdplus-sa-cli-plugin/pom.xml b/jdplus-main-cli/jdplus-sa-cli-plugin/pom.xml index 91f81ea2..37083966 100644 --- a/jdplus-main-cli/jdplus-sa-cli-plugin/pom.xml +++ b/jdplus-main-cli/jdplus-sa-cli-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-cli - 3.0.2 + 3.1.0 jdplus-sa-cli-plugin diff --git a/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/pom.xml b/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/pom.xml index b6b7e676..30f2f2f8 100644 --- a/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/pom.xml +++ b/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-cli - 3.0.2 + 3.1.0 jdplus-spreadsheet-cli-plugin @@ -61,31 +61,7 @@ com.github.nbbrd.spreadsheet4j - spreadsheet-xmlss - ${spreadsheet4j.version} - runtime - - - com.github.nbbrd.spreadsheet4j - spreadsheet-od - ${spreadsheet4j.version} - runtime - - - com.github.nbbrd.spreadsheet4j - spreadsheet-xl - ${spreadsheet4j.version} - runtime - - - com.github.nbbrd.spreadsheet4j - spreadsheet-html - ${spreadsheet4j.version} - runtime - - - com.github.nbbrd.spreadsheet4j - spreadsheet-fastexcel + spreadsheet-standalone ${spreadsheet4j.version} runtime diff --git a/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/src/test/java/jdplus/spreadsheet/cli/plugin/SpreadsheetRuntimeDependenciesTest.java b/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/src/test/java/jdplus/spreadsheet/cli/plugin/SpreadsheetRuntimeDependenciesTest.java index 64132de1..2e2c3d55 100644 --- a/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/src/test/java/jdplus/spreadsheet/cli/plugin/SpreadsheetRuntimeDependenciesTest.java +++ b/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/src/test/java/jdplus/spreadsheet/cli/plugin/SpreadsheetRuntimeDependenciesTest.java @@ -23,7 +23,7 @@ public void test() throws IOException { .describedAs("Check runtime dependencies") .satisfies(SpreadsheetRuntimeDependenciesTest::checkSpreadsheet) .satisfies(SpreadsheetRuntimeDependenciesTest::checkSpreadsheet4j) - .hasSize(12); + .hasSize(3); } private static void checkSpreadsheet(List coordinates) { @@ -38,24 +38,8 @@ private static void checkSpreadsheet4j(List coordinates) { assertThatGroupId(coordinates, "com.github.nbbrd.spreadsheet4j") .has(sameVersion()) .extracting(GAV::getArtifactId) - .are(matchingPattern(compile("^spreadsheet-(api|util|xmlss|od|xl|html|fastexcel)$"))) - .hasSize(7); - - assertThatGroupId(coordinates, "com.github.miachm.sods") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("SODS"); - - assertThatGroupId(coordinates, "com.github.rzymek") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("opczip"); - - assertThatGroupId(coordinates, "org.dhatim") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("fastexcel"); - - assertThatGroupId(coordinates, "org.jsoup") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("jsoup"); + .are(matchingPattern(compile("^spreadsheet-(api|standalone)$"))) + .hasSize(2); } @MightBePromoted diff --git a/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/src/test/java/jdplus/spreadsheet/cli/plugin/SpreadsheetStandaloneTest.java b/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/src/test/java/jdplus/spreadsheet/cli/plugin/SpreadsheetStandaloneTest.java new file mode 100644 index 00000000..205cef52 --- /dev/null +++ b/jdplus-main-cli/jdplus-spreadsheet-cli-plugin/src/test/java/jdplus/spreadsheet/cli/plugin/SpreadsheetStandaloneTest.java @@ -0,0 +1,49 @@ +package jdplus.spreadsheet.cli.plugin; + +import ec.util.spreadsheet.Book; +import ec.util.spreadsheet.helpers.ArrayBook; +import ec.util.spreadsheet.helpers.ArraySheet; +import internal.spreadsheet.base.api.SpreadsheetManager; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +public class SpreadsheetStandaloneTest { + + @Test + public void testStandaloneFactories(@TempDir Path temp) { + String[] extensions = {".htm", ".xlsx", ".xml", ".ods"}; + + ArrayBook expected = ArraySheet.copyOf("name1", new Object[][]{ + {"A1", "B1"}, + {"A2", "B2"}, + }).toBook(); + + SpreadsheetManager manager = SpreadsheetManager.ofServiceLoader(); + + for (Path file : Stream.of(extensions).map(ext -> temp.resolve("hello" + ext)).toList()) { + Optional writer = manager.getWriter(file.toFile()); + assertThat(writer).isNotEmpty(); + assertThatCode(() -> writer.orElseThrow().store(file, expected)) + .doesNotThrowAnyException(); + + Optional reader = manager.getReader(file.toFile()); + assertThat(reader).isNotEmpty(); + AtomicReference found = new AtomicReference<>(); + assertThatCode(() -> { + try (Book result = reader.orElseThrow().load(file)) { + found.set(ArrayBook.copyOf(result)); + } + }).doesNotThrowAnyException(); + assertThat(found).hasValue(expected); + } + } +} diff --git a/jdplus-main-cli/jdplus-sql-cli-plugin/pom.xml b/jdplus-main-cli/jdplus-sql-cli-plugin/pom.xml index 72ac8f85..4dfd06e7 100644 --- a/jdplus-main-cli/jdplus-sql-cli-plugin/pom.xml +++ b/jdplus-main-cli/jdplus-sql-cli-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-cli - 3.0.2 + 3.1.0 jdplus-sql-cli-plugin diff --git a/jdplus-main-cli/jdplus-text-cli-plugin/pom.xml b/jdplus-main-cli/jdplus-text-cli-plugin/pom.xml index 2a02dcc6..c6aaca45 100644 --- a/jdplus-main-cli/jdplus-text-cli-plugin/pom.xml +++ b/jdplus-main-cli/jdplus-text-cli-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-cli - 3.0.2 + 3.1.0 jdplus-text-cli-plugin diff --git a/jdplus-main-cli/jdplus-toolkit-cli-plugin/pom.xml b/jdplus-main-cli/jdplus-toolkit-cli-plugin/pom.xml index bec436ca..f4fd9a8e 100644 --- a/jdplus-main-cli/jdplus-toolkit-cli-plugin/pom.xml +++ b/jdplus-main-cli/jdplus-toolkit-cli-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-cli - 3.0.2 + 3.1.0 jdplus-toolkit-cli-plugin diff --git a/jdplus-main-cli/jdplus-toolkit-cli-plugin/src/test/java/jdplus/toolkit/cli/plugin/ToolkitRuntimeDependenciesTest.java b/jdplus-main-cli/jdplus-toolkit-cli-plugin/src/test/java/jdplus/toolkit/cli/plugin/ToolkitRuntimeDependenciesTest.java index 77a3792c..522159e5 100644 --- a/jdplus-main-cli/jdplus-toolkit-cli-plugin/src/test/java/jdplus/toolkit/cli/plugin/ToolkitRuntimeDependenciesTest.java +++ b/jdplus-main-cli/jdplus-toolkit-cli-plugin/src/test/java/jdplus/toolkit/cli/plugin/ToolkitRuntimeDependenciesTest.java @@ -23,7 +23,7 @@ public void test() throws IOException { .describedAs("Check runtime dependencies") .satisfies(ToolkitRuntimeDependenciesTest::checkToolkit) .satisfies(ToolkitRuntimeDependenciesTest::checkJavaIoUtil) - .hasSize(19); + .hasSize(20); } private static void checkToolkit(List coordinates) { @@ -32,6 +32,9 @@ private static void checkToolkit(List coordinates) { .extracting(GAV::getArtifactId) .are(matchingPattern(compile("^jdplus-toolkit-base-\\w+$"))) .hasSize(6); + assertThatGroupId(coordinates, "com.github.ben-manes.caffeine") + .extracting(GAV::getArtifactId) + .containsExactlyInAnyOrder("caffeine"); } private static void checkJavaIoUtil(List coordinates) { diff --git a/jdplus-main-cli/jdplus-tramoseats-cli-plugin/pom.xml b/jdplus-main-cli/jdplus-tramoseats-cli-plugin/pom.xml index cbcfa36c..d31b0f73 100644 --- a/jdplus-main-cli/jdplus-tramoseats-cli-plugin/pom.xml +++ b/jdplus-main-cli/jdplus-tramoseats-cli-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-cli - 3.0.2 + 3.1.0 jdplus-tramoseats-cli-plugin diff --git a/jdplus-main-cli/jdplus-x13-cli-plugin/pom.xml b/jdplus-main-cli/jdplus-x13-cli-plugin/pom.xml index db2dc46f..a0a6ab96 100644 --- a/jdplus-main-cli/jdplus-x13-cli-plugin/pom.xml +++ b/jdplus-main-cli/jdplus-x13-cli-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-cli - 3.0.2 + 3.1.0 jdplus-x13-cli-plugin diff --git a/jdplus-main-cli/pom.xml b/jdplus-main-cli/pom.xml index 03040c01..ccf287d5 100644 --- a/jdplus-main-cli/pom.xml +++ b/jdplus-main-cli/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main - 3.0.2 + 3.1.0 jdplus-main-cli @@ -17,7 +17,7 @@ ${project.parent.url} - 4.7.4 + 4.7.5 @@ -49,7 +49,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.4.1 + 3.5.1 package diff --git a/jdplus-main-desktop/jdplus-main-desktop-bin/pom.xml b/jdplus-main-desktop/jdplus-main-desktop-bin/pom.xml index 580b37bb..434fc5f5 100644 --- a/jdplus-main-desktop/jdplus-main-desktop-bin/pom.xml +++ b/jdplus-main-desktop/jdplus-main-desktop-bin/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-main-desktop - 3.0.2 + 3.1.0 jdplus-main-desktop-bin diff --git a/jdplus-main-desktop/jdplus-main-desktop-bin/src/main/resources/nbdemetra.conf b/jdplus-main-desktop/jdplus-main-desktop-bin/src/main/resources/nbdemetra.conf index c5fcd40c..18588217 100644 --- a/jdplus-main-desktop/jdplus-main-desktop-bin/src/main/resources/nbdemetra.conf +++ b/jdplus-main-desktop/jdplus-main-desktop-bin/src/main/resources/nbdemetra.conf @@ -4,7 +4,7 @@ default_cachedir="${DEFAULT_CACHEDIR_ROOT}/3" # options used by the launcher by default, can be overridden by explicit # command line switches -default_options="--branding nbdemetra -J-Djdk.gtk.version=2.2 -J-Dapple.laf.useScreenMenuBar=true -J-Dapple.awt.graphics.UseQuartz=true -J-Dsun.java2d.noddraw=true -J-Dsun.java2d.dpiaware=true -J-XX:+IgnoreUnrecognizedVMOptions" +default_options="--branding nbdemetra -J-XX:+UseStringDeduplication -J-Xss2m -J-Dapple.laf.useScreenMenuBar=true -J-Dapple.awt.graphics.UseQuartz=true -J-Dsun.java2d.noddraw=true -J-Dsun.java2d.dpiaware=true -J-Dsun.zip.disableMemoryMapping=true -J-Dplugin.manager.check.updates=false -J-Dnetbeans.extbrowser.manual_chrome_plugin_install=yes -J--add-opens=java.base/java.net=ALL-UNNAMED -J--add-opens=java.base/java.lang.ref=ALL-UNNAMED -J--add-opens=java.base/java.lang=ALL-UNNAMED -J--add-opens=java.base/java.security=ALL-UNNAMED -J--add-opens=java.base/java.util=ALL-UNNAMED -J--add-opens=java.base/java.nio=ALL-UNNAMED -J--add-exports=java.base/sun.reflect.annotation=ALL-UNNAMED -J--add-opens=java.prefs/java.util.prefs=ALL-UNNAMED -J--add-opens=java.desktop/javax.swing.plaf.basic=ALL-UNNAMED -J--add-opens=java.desktop/javax.swing.text=ALL-UNNAMED -J--add-opens=java.desktop/javax.swing=ALL-UNNAMED -J--add-opens=java.desktop/java.awt=ALL-UNNAMED -J--add-opens=java.desktop/java.awt.event=ALL-UNNAMED -J--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED -J--add-opens=java.desktop/javax.swing.plaf.synth=ALL-UNNAMED -J--add-opens=java.desktop/com.sun.java.swing.plaf.gtk=ALL-UNNAMED -J--add-opens=java.desktop/sun.awt.shell=ALL-UNNAMED -J--add-opens=java.desktop/sun.awt.im=ALL-UNNAMED -J--add-exports=java.desktop/sun.awt=ALL-UNNAMED -J--add-exports=java.desktop/java.awt.peer=ALL-UNNAMED -J--add-exports=java.desktop/com.sun.beans.editors=ALL-UNNAMED -J--add-exports=java.desktop/sun.swing=ALL-UNNAMED -J--add-exports=java.desktop/sun.awt.im=ALL-UNNAMED -J--add-exports=java.desktop/com.sun.java.swing.plaf.motif=ALL-UNNAMED -J--add-exports=java.desktop/com.apple.eio=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -J--add-modules=jdk.jshell -J--add-opens=jdk.jshell/jdk.jshell=ALL-UNNAMED -J--add-exports=jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED -J--add-exports=jdk.jdeps/com.sun.tools.javap=ALL-UNNAMED -J--add-exports=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED -J--add-exports=java.management/sun.management=ALL-UNNAMED -J-XX:+IgnoreUnrecognizedVMOptions" # for development purposes you may wish to append: -J-Dnetbeans.logger.console=true -J-ea # default location of JDK/JRE, can be overridden by using --jdkhome switch diff --git a/jdplus-main-desktop/jdplus-main-desktop-branding/pom.xml b/jdplus-main-desktop/jdplus-main-desktop-branding/pom.xml index 1e3d4984..cbc57d30 100644 --- a/jdplus-main-desktop/jdplus-main-desktop-branding/pom.xml +++ b/jdplus-main-desktop/jdplus-main-desktop-branding/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-main-desktop - 3.0.2 + 3.1.0 jdplus-main-desktop-branding diff --git a/jdplus-main-desktop/jdplus-main-desktop-design/pom.xml b/jdplus-main-desktop/jdplus-main-desktop-design/pom.xml index 38eb81ef..82aa5531 100644 --- a/jdplus-main-desktop/jdplus-main-desktop-design/pom.xml +++ b/jdplus-main-desktop/jdplus-main-desktop-design/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.sat jdplus-main-desktop - 3.0.2 + 3.1.0 jdplus-main-desktop-design diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/pom.xml b/jdplus-main-desktop/jdplus-sa-desktop-plugin/pom.xml index ed5d44bd..f50959dc 100644 --- a/jdplus-main-desktop/jdplus-sa-desktop-plugin/pom.xml +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-desktop - 3.0.2 + 3.1.0 jdplus-sa-desktop-plugin diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/Actions.java b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/Actions.java index 79749d0a..cb318b2d 100644 --- a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/Actions.java +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/Actions.java @@ -21,6 +21,7 @@ import jdplus.toolkit.desktop.plugin.workspace.nodes.DeleteAction; import jdplus.toolkit.desktop.plugin.workspace.nodes.NewAction; import jdplus.toolkit.desktop.plugin.workspace.nodes.RenameAction; +import jdplus.toolkit.desktop.plugin.workspace.nodes.SaveAction; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -31,7 +32,7 @@ public class Actions { @ActionID(category = "Edit", id = "demetra.desktop.workspace.nodes.RenameAction") @ActionReferences({ - @ActionReference(path = MultiProcessingManager.ITEMPATH, position = 1050) + @ActionReference(path = MultiProcessingManager.ITEMPATH, position = 1150) }) public static RenameAction renameAction() { return new RenameAction(); @@ -40,7 +41,7 @@ public static RenameAction renameAction() { @ActionID(category = "Edit", id = "demetra.desktop.workspace.nodes.CommentAction") @ActionReferences({ - @ActionReference(path = MultiProcessingManager.ITEMPATH, position = 1150) + @ActionReference(path = MultiProcessingManager.ITEMPATH, position = 1200) }) public static CommentAction commentAction() { return new CommentAction(); @@ -49,7 +50,7 @@ public static CommentAction commentAction() { @ActionID(category = "Edit", id = "demetra.desktop.workspace.nodes.DeleteAction") @ActionReferences({ - @ActionReference(path = MultiProcessingManager.ITEMPATH, position = 1100) + @ActionReference(path = MultiProcessingManager.ITEMPATH, position = 1050) }) public static DeleteAction deleteAction() { return new DeleteAction(); @@ -64,4 +65,12 @@ public static NewAction newAction() { return new NewAction(); } + @ActionID(category = "Edit", + id = "demetra.desktop.workspace.nodes.SaveAction") + @ActionReferences({ + @ActionReference(path = MultiProcessingManager.ITEMPATH, position = 1100, separatorAfter=1110) + }) + public static SaveAction saveAction() { + return new SaveAction(); + } } diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/EditRefSpecification.java b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/EditRefSpecification.java index 3288db54..f9fa4cd8 100644 --- a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/EditRefSpecification.java +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/EditRefSpecification.java @@ -42,10 +42,10 @@ id = "demetra.sa.multiprocessing.actions.EditRefSpecification") @ActionRegistration(displayName = "#CTL_EditRefSpecification", lazy = false) @ActionReferences({ - @ActionReference(path = MultiProcessingManager.CONTEXTPATH + Edit.PATH, position = 1510), - @ActionReference(path = MultiProcessingManager.LOCALPATH + Edit.PATH, position = 1510) + @ActionReference(path = MultiProcessingManager.CONTEXTPATH + RefSpecification.PATH , position = 1510), + @ActionReference(path = MultiProcessingManager.LOCALPATH + RefSpecification.PATH, position = 1510) }) -@Messages("CTL_EditRefSpecification=Edit Reference Specification...") +@Messages("CTL_EditRefSpecification=Modify...") public final class EditRefSpecification extends ActiveViewAction { public EditRefSpecification() { diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/RefSpecification.java b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/RefSpecification.java new file mode 100644 index 00000000..80869041 --- /dev/null +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/RefSpecification.java @@ -0,0 +1,48 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package jdplus.sa.desktop.plugin.multiprocessing.actions; + +import jdplus.sa.desktop.plugin.multiprocessing.ui.MultiProcessingManager; +import jdplus.toolkit.desktop.plugin.ui.Menus; +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import javax.swing.JMenu; +import javax.swing.JMenuItem; + +import org.openide.awt.ActionRegistration; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.awt.ActionID; +import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.Presenter; + +@ActionID(category = "SaProcessing", + id = "demetra.desktop.sa.multiprocessing.actions.RefSpecification") +@ActionRegistration(displayName = "#CTL_RefSpecification", lazy = false) +@ActionReferences({ + @ActionReference(path = MultiProcessingManager.CONTEXTPATH + Edit.PATH, position = 1500, separatorBefore = 1499), + @ActionReference(path = MultiProcessingManager.LOCALPATH + Edit.PATH, position = 1500, separatorBefore = 1499), + @ActionReference(path = "Shortcuts", name = "r") +}) +@Messages("CTL_RefSpecification=Reference specification") +public final class RefSpecification extends AbstractAction implements Presenter.Popup { + + public static final String PATH = Edit.PATH+"/RefSpecification"; + + public RefSpecification() { + super(Bundle.CTL_RefSpecification()); + } + + @Override + public void actionPerformed(ActionEvent e) { + } + + @Override + public JMenuItem getPopupPresenter() { + JMenu menu = new JMenu(this); + Menus.fillMenu(menu, MultiProcessingManager.CONTEXTPATH + PATH); + return menu; + } +} diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/SelectRefSpecification.java b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/SelectRefSpecification.java index 359fffde..8c0811a0 100644 --- a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/SelectRefSpecification.java +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/actions/SelectRefSpecification.java @@ -35,19 +35,19 @@ import org.openide.util.NbBundle.Messages; @ActionID(category = "SaProcessing", - id = "demetra.sa.multiprocessing.actions.RefSpecification") -@ActionRegistration(displayName = "#CTL_RefSpecification", lazy = false) + id = "demetra.sa.multiprocessing.actions.SelectRefSpecification") +@ActionRegistration(displayName = "#CTL_SelectRefSpecification", lazy = false) @ActionReferences({ - @ActionReference(path = MultiProcessingManager.CONTEXTPATH + Edit.PATH, position = 1500, separatorBefore = 1499), - @ActionReference(path = MultiProcessingManager.LOCALPATH + Edit.PATH, position = 1500) + @ActionReference(path = MultiProcessingManager.CONTEXTPATH + RefSpecification.PATH, position = 1505), + @ActionReference(path = MultiProcessingManager.LOCALPATH + RefSpecification.PATH, position = 1505) }) -@Messages("CTL_RefSpecification=Reference Specification...") +@Messages("CTL_SelectRefSpecification=Select...") public final class SelectRefSpecification extends ActiveViewAction { public SelectRefSpecification() { super(SaBatchUI.class); refreshAction(); - putValue(NAME, Bundle.CTL_RefSpecification()); + putValue(NAME, Bundle.CTL_SelectRefSpecification()); } @Override diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/MultiProcessingDocFileRepository.java b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/MultiProcessingDocFileRepository.java index 501a443b..9fcfaf79 100644 --- a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/MultiProcessingDocFileRepository.java +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/MultiProcessingDocFileRepository.java @@ -9,12 +9,6 @@ import jdplus.toolkit.desktop.plugin.workspace.WorkspaceItem; import jdplus.toolkit.desktop.plugin.workspace.WorkspaceItemRepository; import jdplus.sa.base.api.SaItems; -import jdplus.toolkit.base.tsp.TsMeta; - -import java.time.Clock; -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; import org.openide.util.lookup.ServiceProvider; /** @@ -35,10 +29,13 @@ public boolean load(WorkspaceItem item) { @Override public boolean save(WorkspaceItem doc, DemetraVersion version) { MultiProcessingDocument element = doc.getElement(); - Map meta=new HashMap<>(element.getMetadata()); - TsMeta.TIMESTAMP.store(meta, LocalDateTime.now(Clock.systemDefaultZone())); - SaItems current = element.current(meta); - return storeFile(doc, current, version, doc::resetDirty); + MultiProcessingDocument saved = element.save(); + // we update the current document + return storeFile(doc, saved.getInitial(), version, () + -> { + doc.setElement(saved); + doc.resetDirty(); + }); } @Override diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/MultiProcessingDocument.java b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/MultiProcessingDocument.java index 855daf1d..c1f29c82 100644 --- a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/MultiProcessingDocument.java +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/MultiProcessingDocument.java @@ -4,6 +4,8 @@ */ package jdplus.sa.desktop.plugin.multiprocessing.ui; +import java.time.Clock; +import java.time.LocalDateTime; import jdplus.sa.base.api.EstimationPolicy; import jdplus.sa.base.api.EstimationPolicyType; import jdplus.sa.base.api.SaItem; @@ -17,11 +19,14 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Collectors; +import jdplus.toolkit.base.tsp.TsMeta; import org.checkerframework.checker.nullness.qual.NonNull; /** @@ -32,7 +37,7 @@ public class MultiProcessingDocument implements Documented { int curId = 0; - private final Map metadata = Collections.emptyMap(); + private final Map metadata = new LinkedHashMap<>(); private final List current = new ArrayList<>(); @NonNull @@ -65,6 +70,15 @@ public static MultiProcessingDocument open(SaItems initial) { return doc; } + public MultiProcessingDocument save() { + Map meta = new HashMap<>(metadata); + SaItems cur = current(meta); + MultiProcessingDocument saved = open(cur); + saved.metadata.putAll(metadata); + TsMeta.TIMESTAMP.store(saved.metadata, LocalDateTime.now(Clock.systemDefaultZone())); + return saved; + } + @Override public Map getMetadata() { return metadata; @@ -83,8 +97,8 @@ public boolean isProcessed() { public boolean isNew() { return initial.isEmpty(); } - - public boolean isRefreshable(){ + + public boolean isRefreshable() { return !isNew() || hasFrozenItems(); } diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/SaBatchUI.java b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/SaBatchUI.java index fa51ca22..b78acdf5 100644 --- a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/SaBatchUI.java +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/multiprocessing/ui/SaBatchUI.java @@ -4,25 +4,30 @@ */ package jdplus.sa.desktop.plugin.multiprocessing.ui; -import com.google.common.base.Joiner; -import com.google.common.base.Stopwatch; -import com.google.common.base.Strings; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import jdplus.toolkit.desktop.plugin.DemetraBehaviour; -import jdplus.toolkit.desktop.plugin.DemetraIcons; -import jdplus.toolkit.desktop.plugin.TsActionManager; -import jdplus.toolkit.desktop.plugin.TsDynamicProvider; -import jdplus.toolkit.desktop.plugin.TsManager; +import ec.util.grid.swing.XTable; +import ec.util.table.swing.JTables; +import jdplus.sa.base.api.*; +import jdplus.sa.base.information.SaItemsMapping; +import jdplus.sa.desktop.plugin.ui.DemetraSaUI; +import jdplus.sa.desktop.plugin.util.ActionsHelper; +import jdplus.sa.desktop.plugin.util.ActionsHelpers; +import jdplus.toolkit.base.api.processing.ProcQuality; +import jdplus.toolkit.base.api.processing.ProcessingLog.InformationType; +import jdplus.toolkit.base.api.timeseries.*; +import jdplus.toolkit.base.api.timeseries.regression.ModellingContext; +import jdplus.toolkit.base.api.util.MultiLineNameUtil; +import jdplus.toolkit.base.tsp.fixme.Strings; +import jdplus.toolkit.desktop.plugin.*; import jdplus.toolkit.desktop.plugin.components.parts.HasTsCollection; import jdplus.toolkit.desktop.plugin.components.parts.HasTsCollectionSupport; +import jdplus.toolkit.desktop.plugin.concurrent.ThreadPoolSize; +import jdplus.toolkit.desktop.plugin.concurrent.ThreadPriority; +import jdplus.toolkit.desktop.plugin.concurrent.UIExecutors; import jdplus.toolkit.desktop.plugin.datatransfer.DataTransferManager; import jdplus.toolkit.desktop.plugin.datatransfer.DataTransfers; import jdplus.toolkit.desktop.plugin.datatransfer.TransferableXmlInformation; import jdplus.toolkit.desktop.plugin.notification.MessageType; import jdplus.toolkit.desktop.plugin.notification.NotifyUtil; -import jdplus.sa.desktop.plugin.ui.DemetraSaUI; -import jdplus.sa.desktop.plugin.util.ActionsHelper; -import jdplus.sa.desktop.plugin.util.ActionsHelpers; import jdplus.toolkit.desktop.plugin.tsproviders.DataSourceManager; import jdplus.toolkit.desktop.plugin.ui.Menus; import jdplus.toolkit.desktop.plugin.ui.Menus.DynamicPopup; @@ -32,56 +37,12 @@ import jdplus.toolkit.desktop.plugin.util.ListTableModel; import jdplus.toolkit.desktop.plugin.util.NbComponents; import jdplus.toolkit.desktop.plugin.util.PopupMenuAdapter; +import jdplus.toolkit.desktop.plugin.util.Stopwatch; import jdplus.toolkit.desktop.plugin.workspace.DocumentUIServices; import jdplus.toolkit.desktop.plugin.workspace.WorkspaceFactory; import jdplus.toolkit.desktop.plugin.workspace.WorkspaceItem; import jdplus.toolkit.desktop.plugin.workspace.WorkspaceItemManager; import jdplus.toolkit.desktop.plugin.workspace.ui.JSpecSelectionComponent; -import jdplus.toolkit.base.api.processing.ProcQuality; -import jdplus.toolkit.base.api.processing.ProcessingLog.InformationType; -import jdplus.sa.base.api.EstimationPolicyType; -import jdplus.sa.base.api.HasSaEstimation; -import jdplus.sa.base.api.SaDefinition; -import jdplus.sa.base.api.SaEstimation; -import jdplus.sa.base.api.SaItem; -import jdplus.sa.base.api.SaItems; -import jdplus.sa.base.api.SaSpecification; -import jdplus.sa.base.information.SaItemsMapping; -import jdplus.toolkit.base.api.timeseries.Ts; -import jdplus.toolkit.base.api.timeseries.TsCollection; -import jdplus.toolkit.base.api.timeseries.TsData; -import jdplus.toolkit.base.api.timeseries.TsDocument; -import jdplus.toolkit.base.api.timeseries.TsInformationType; -import jdplus.toolkit.base.api.timeseries.regression.ModellingContext; -import jdplus.toolkit.base.api.util.MultiLineNameUtil; -import ec.util.grid.swing.XTable; -import ec.util.table.swing.JTables; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Image; -import java.awt.datatransfer.Transferable; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.beans.BeanInfo; -import java.beans.PropertyChangeListener; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.logging.Level; -import java.util.stream.Collectors; -import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import javax.swing.event.PopupMenuEvent; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.TableModel; -import javax.swing.table.TableRowSorter; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.core.spi.multiview.CloseOperationState; import org.netbeans.core.spi.multiview.MultiViewElement; @@ -95,6 +56,28 @@ import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.PopupMenuEvent; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; +import java.awt.*; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.BeanInfo; +import java.beans.PropertyChangeListener; +import java.util.List; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.logging.Level; +import java.util.stream.Collectors; + /** * @author Philippe Charles * @author Mats Maggi @@ -305,13 +288,10 @@ public void actionPerformed(ActionEvent e) { addPropertyChangeListener(evt -> { switch (evt.getPropertyName()) { case HasTsCollection.DROP_CONTENT_PROPERTY, HasTsCollection.FREEZE_ON_IMPORT_PROPERTY, HasTsCollection.TS_COLLECTION_PROPERTY, HasTsCollection.TS_SELECTION_MODEL_PROPERTY, HasTsCollection.TS_UPDATE_MODE_PROPERTY -> - onCollectionChange(); - case DEFAULT_SPECIFICATION_PROPERTY -> - onDefaultSpecificationChange(); - case PROCESSING_PROPERTY -> - onProcessingChange(); - case SELECTION_PROPERTY -> - onSelectionChange(); + onCollectionChange(); + case DEFAULT_SPECIFICATION_PROPERTY -> onDefaultSpecificationChange(); + case PROCESSING_PROPERTY -> onProcessingChange(); + case SELECTION_PROPERTY -> onSelectionChange(); } }); master.addMouseListener(new DynamicPopup(MultiProcessingManager.LOCALPATH)); @@ -327,7 +307,7 @@ public ExplorerManager getExplorerManager() { } @NbBundle.Messages({ - "undefinedspec.dialog.title=Undefined specification" + "undefinedspec.dialog.title=Undefined specification" }) private void onCollectionChange() { TsCollection coll = getTsCollection(); @@ -509,7 +489,7 @@ public void paste(boolean interactive) { if (dataobj.getTransferDataFlavors().length > 0) { if (pasteTs(dataobj)) { redrawAll(); - + return; } if (pasteSaProcessing(dataobj)) { @@ -527,10 +507,10 @@ private boolean pasteTs(Transferable dataobj) { long count = DataTransferManager.get() .toTsCollectionStream(dataobj) .map(col -> col - .load(TsInformationType.All, TsManager.get()) - .stream() - .map(Ts::freeze) - .collect(TsCollection.toTsCollection()) + .load(TsInformationType.All, TsManager.get()) + .stream() + .map(Ts::freeze) + .collect(TsCollection.toTsCollection()) ) .peek(col -> getElement().add(defaultSpecification, col.toArray(n -> new Ts[n]))) .count(); @@ -750,7 +730,7 @@ public void mouseClicked(MouseEvent e) { return result; } -// private void refreshInfo() { + // private void refreshInfo() { // String ts = getCurrentProcessing().getMeta().get(TsMeta.TIMESTAMP); // if (!Strings.isNullOrEmpty(ts)) { // if (getCurrentProcessing().isDirty()) { @@ -1088,22 +1068,14 @@ protected String getText(SaNode item) { } EstimationPolicyType policy = item.getOutput().getDefinition().getPolicy(); return switch (policy) { - case Fixed -> - "Fixed model"; - case FixedParameters -> - "Reg. coefficients"; - case FreeParameters -> - "Arima parameters"; - case LastOutliers -> - "Last outliers"; - case Outliers_StochasticComponent -> - "Arima model"; - case Complete -> - "Concurrent"; - case None -> - "New"; - default -> - policy.name(); + case Fixed -> "Fixed model"; + case FixedParameters -> "Reg. coefficients"; + case FreeParameters -> "Arima parameters"; + case LastOutliers -> "Last outliers"; + case Outliers_StochasticComponent -> "Arima model"; + case Complete -> "Concurrent"; + case None -> "New"; + default -> policy.name(); }; } } @@ -1118,14 +1090,10 @@ protected String getText(SaNode item) { @Override protected Color getColor(SaNode item) { return switch (item.getStatus()) { - case Unprocessed -> - Color.GRAY; - case Pending -> - Color.ORANGE; - case Valid -> - null; - default -> - Color.RED; + case Unprocessed -> Color.GRAY; + case Pending -> Color.ORANGE; + case Valid -> null; + default -> Color.RED; }; } } @@ -1143,7 +1111,7 @@ static class QualityRenderer extends SimpleRenderer { @Override protected String getText(SaNode item) { - if (!item.isProcessed()) { + if (!item.isProcessed() || item.results() == null) { return null; } ProcQuality quality = item.results().getQuality(); @@ -1152,7 +1120,7 @@ protected String getText(SaNode item) { @Override protected Color getColor(SaNode item) { - return item.isProcessed() ? getColor(item.results().getQuality()) : null; + return item.isProcessed() && item.results() != null ? getColor(item.results().getQuality()) : null; } Color getColor(ProcQuality quality) { @@ -1190,7 +1158,7 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); label.setText(""); SaNode item = (SaNode) value; - if (!item.isProcessed()) { + if (!item.isProcessed() || item.results() == null) { return label; } String[] warnings = item.results().getLog(). @@ -1203,7 +1171,7 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole char[] tmp = new char[warnings.length]; Arrays.fill(tmp, '!'); label.setText(String.valueOf(tmp)); - label.setToolTipText(Joiner.on(". ").join(warnings)); + label.setToolTipText(String.join(". ", warnings)); return label; } } @@ -1301,10 +1269,10 @@ protected Void doInBackground() { } DemetraBehaviour options = DemetraBehaviour.get(); - int nThread = options.getBatchPoolSize().getSize(); - int priority = options.getBatchPriority().getPriority(); + ThreadPoolSize nThread = options.getBatchPoolSize(); + ThreadPriority priority = options.getBatchPriority(); - ExecutorService executorService = Executors.newFixedThreadPool(nThread, new ThreadFactoryBuilder().setDaemon(true).setPriority(priority).build()); + ExecutorService executorService = UIExecutors.newFixedThreadPool(nThread, priority); Stopwatch stopwatch = Stopwatch.createStarted(); try { executorService.invokeAll(tasks); diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvArraysOutputBuddy.java b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvArraysOutputBuddy.java index e494f647..e7d53440 100644 --- a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvArraysOutputBuddy.java +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvArraysOutputBuddy.java @@ -1,54 +1,55 @@ /* -* Copyright 2016 National Bank of Belgium -* - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved + * Copyright 2016 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved * by the European Commission - subsequent versions of the EUPL (the "Licence"); -* You may not use this work except in compliance with the Licence. -* You may obtain a copy of the Licence at: -* + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * * http://ec.europa.eu/idabc/eupl -* - * Unless required by applicable law or agreed to in writing, software + * + * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the Licence for the specific language governing permissions and + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and * limitations under the Licence. */ package jdplus.sa.desktop.plugin.output.impl; -import com.google.common.base.Splitter; -import jdplus.toolkit.desktop.plugin.beans.BeanHandler; -import jdplus.toolkit.desktop.plugin.Config; -import jdplus.toolkit.desktop.plugin.ConfigEditor; -import jdplus.toolkit.desktop.plugin.properties.PropertySheetDialogBuilder; -import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; -import java.beans.IntrospectionException; -import java.io.File; -import java.util.List; -import java.util.stream.Collectors; - +import jdplus.sa.base.api.SaManager; +import jdplus.sa.base.api.SaOutputFactory; +import jdplus.sa.base.csv.CsvArrayOutputConfiguration; +import jdplus.sa.base.csv.CsvArrayOutputFactory; import jdplus.sa.desktop.plugin.output.AbstractOutputNode; import jdplus.sa.desktop.plugin.output.Arrays; import jdplus.sa.desktop.plugin.output.OutputFactoryBuddy; import jdplus.sa.desktop.plugin.output.OutputSelection; -import org.openide.nodes.Sheet; -import org.openide.util.lookup.ServiceProvider; +import jdplus.toolkit.desktop.plugin.Config; +import jdplus.toolkit.desktop.plugin.ConfigEditor; +import jdplus.toolkit.desktop.plugin.Converter; +import jdplus.toolkit.desktop.plugin.actions.Configurable; import jdplus.toolkit.desktop.plugin.actions.Resetable; +import jdplus.toolkit.desktop.plugin.beans.BeanConfigurator; +import jdplus.toolkit.desktop.plugin.beans.BeanEditor; +import jdplus.toolkit.desktop.plugin.beans.BeanHandler; +import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; +import jdplus.toolkit.desktop.plugin.properties.PropertySheetDialogBuilder; import nbbrd.io.text.BooleanProperty; import nbbrd.io.text.Formatter; import nbbrd.io.text.Parser; import nbbrd.io.text.Property; -import jdplus.toolkit.desktop.plugin.beans.BeanEditor; -import jdplus.toolkit.desktop.plugin.Converter; -import jdplus.toolkit.desktop.plugin.actions.Configurable; -import jdplus.toolkit.desktop.plugin.beans.BeanConfigurator; -import jdplus.sa.base.api.SaManager; -import jdplus.sa.base.api.SaOutputFactory; -import jdplus.sa.base.csv.CsvArrayOutputConfiguration; -import jdplus.sa.base.csv.CsvArrayOutputFactory; +import org.openide.nodes.Sheet; +import org.openide.util.lookup.ServiceProvider; + +import java.beans.IntrospectionException; +import java.io.File; +import java.util.List; +import java.util.stream.Collectors; + +import static jdplus.toolkit.base.tsp.fixme.Strings.nullToEmpty; +import static jdplus.toolkit.base.tsp.fixme.Strings.splitToStream; /** - * * @author Philippe Charles */ @ServiceProvider(service = OutputFactoryBuddy.class, position = 1000) @@ -56,8 +57,8 @@ public final class CsvArraysOutputBuddy implements OutputFactoryBuddy, Configura private final BeanConfigurator configurator = createConfigurator(); private CsvArrayOutputConfiguration config = new CsvArrayOutputConfiguration(); - - public CsvArraysOutputBuddy(){ + + public CsvArraysOutputBuddy() { } @Override @@ -130,7 +131,7 @@ public boolean editBean(Object bean) throws IntrospectionException { private static final class CsvArraysOutputConverter implements Converter { -// private final Property presentationParam = Property.of("presentation", CsvLayout.List, Parser.onEnum(CsvLayout.class), Formatter.onEnum()); + // private final Property presentationParam = Property.of("presentation", CsvLayout.List, Parser.onEnum(CsvLayout.class), Formatter.onEnum()); private final Property folderParam = Property.of("folder", new File(""), Parser.onFile(), Formatter.onFile()); private final Property filePrefixParam = Property.of("filePrefix", "series", Parser.onString(), Formatter.onString()); private final Property arraysParam = Property.of("arrays", null, Parser.onString(), Formatter.onString()); @@ -153,7 +154,7 @@ public CsvArrayOutputConfiguration doBackward(Config b) { // result.setPresentation(presentationParam.get(b::getParameter)); result.setFolder(folderParam.get(b::getParameter)); result.setFilePrefix(filePrefixParam.get(b::getParameter)); - result.setArrays(Splitter.on(",").trimResults().splitToList(arraysParam.get(b::getParameter))); + result.setArrays(splitToStream(',', nullToEmpty(arraysParam.get(b::getParameter))).map(String::trim).toList()); result.setFullName(fullNameParam.get(b::getParameter)); return result; } @@ -161,7 +162,7 @@ public CsvArrayOutputConfiguration doBackward(Config b) { private final static class CsvArraysNode extends AbstractOutputNode { - private static CsvArrayOutputConfiguration newConfiguration(){ + private static CsvArrayOutputConfiguration newConfiguration() { CsvArrayOutputConfiguration config = new CsvArrayOutputConfiguration(); config.setArrays(OutputSelection.arraysItems(SaManager.processors())); return config; diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvMatrixOutputBuddy.java b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvMatrixOutputBuddy.java index 4c1424f3..5dbea79f 100644 --- a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvMatrixOutputBuddy.java +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvMatrixOutputBuddy.java @@ -1,54 +1,55 @@ /* * Copyright 2016 National Bank of Belgium * - * Licensed under the EUPL, Version 1.1 or – as soon they will be approved + * Licensed under the EUPL, Version 1.1 or – as soon they will be approved * by the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: - * + * * http://ec.europa.eu/idabc/eupl - * - * Unless required by applicable law or agreed to in writing, software + * + * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and + * See the Licence for the specific language governing permissions and * limitations under the Licence. */ package jdplus.sa.desktop.plugin.output.impl; -import com.google.common.base.Splitter; -import jdplus.toolkit.desktop.plugin.beans.BeanHandler; -import jdplus.toolkit.desktop.plugin.Config; -import jdplus.toolkit.desktop.plugin.ConfigEditor; -import jdplus.toolkit.desktop.plugin.properties.PropertySheetDialogBuilder; -import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; -import java.beans.IntrospectionException; -import java.io.File; -import java.util.List; -import java.util.stream.Collectors; - +import jdplus.sa.base.api.SaManager; +import jdplus.sa.base.api.SaOutputFactory; +import jdplus.sa.base.csv.CsvMatrixOutputConfiguration; +import jdplus.sa.base.csv.CsvMatrixOutputFactory; import jdplus.sa.desktop.plugin.output.AbstractOutputNode; import jdplus.sa.desktop.plugin.output.Matrix; import jdplus.sa.desktop.plugin.output.OutputFactoryBuddy; import jdplus.sa.desktop.plugin.output.OutputSelection; -import org.openide.nodes.Sheet; -import org.openide.util.lookup.ServiceProvider; +import jdplus.toolkit.desktop.plugin.Config; +import jdplus.toolkit.desktop.plugin.ConfigEditor; +import jdplus.toolkit.desktop.plugin.Converter; +import jdplus.toolkit.desktop.plugin.actions.Configurable; import jdplus.toolkit.desktop.plugin.actions.Resetable; +import jdplus.toolkit.desktop.plugin.beans.BeanConfigurator; +import jdplus.toolkit.desktop.plugin.beans.BeanEditor; +import jdplus.toolkit.desktop.plugin.beans.BeanHandler; +import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; +import jdplus.toolkit.desktop.plugin.properties.PropertySheetDialogBuilder; import nbbrd.io.text.BooleanProperty; import nbbrd.io.text.Formatter; import nbbrd.io.text.Parser; import nbbrd.io.text.Property; -import jdplus.toolkit.desktop.plugin.beans.BeanEditor; -import jdplus.toolkit.desktop.plugin.Converter; -import jdplus.toolkit.desktop.plugin.actions.Configurable; -import jdplus.toolkit.desktop.plugin.beans.BeanConfigurator; -import jdplus.sa.base.csv.CsvMatrixOutputConfiguration; -import jdplus.sa.base.csv.CsvMatrixOutputFactory; -import jdplus.sa.base.api.SaManager; -import jdplus.sa.base.api.SaOutputFactory; +import org.openide.nodes.Sheet; +import org.openide.util.lookup.ServiceProvider; + +import java.beans.IntrospectionException; +import java.io.File; +import java.util.List; +import java.util.stream.Collectors; + +import static jdplus.toolkit.base.tsp.fixme.Strings.nullToEmpty; +import static jdplus.toolkit.base.tsp.fixme.Strings.splitToStream; /** - * * @author Mats Maggi */ @ServiceProvider(service = OutputFactoryBuddy.class, position = 1100) @@ -57,9 +58,9 @@ public class CsvMatrixOutputBuddy implements OutputFactoryBuddy, Configurable, C private static final BeanConfigurator configurator = createConfigurator(); private CsvMatrixOutputConfiguration config = new CsvMatrixOutputConfiguration(); - public CsvMatrixOutputBuddy(){ + public CsvMatrixOutputBuddy() { } - + @Override public String getName() { return CsvMatrixOutputFactory.NAME; @@ -149,15 +150,15 @@ public CsvMatrixOutputConfiguration doBackward(Config b) { CsvMatrixOutputConfiguration result = new CsvMatrixOutputConfiguration(); result.setFolder(folderParam.get(b::getParameter)); result.setFileName(fileNameParam.get(b::getParameter)); - result.setItems(Splitter.on(",").trimResults().splitToList(seriesParam.get(b::getParameter))); + result.setItems(splitToStream(",", nullToEmpty(seriesParam.get(b::getParameter))).map(String::trim).toList()); result.setFullName(fullNameParam.get(b::getParameter)); return result; } } public final static class CsvMatrixNode extends AbstractOutputNode { - - private static CsvMatrixOutputConfiguration newConfiguration(){ + + private static CsvMatrixOutputConfiguration newConfiguration() { CsvMatrixOutputConfiguration config = new CsvMatrixOutputConfiguration(); config.setItems(OutputSelection.matrixItems(SaManager.processors())); return config; diff --git a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvOutputBuddy.java b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvOutputBuddy.java index d71211d9..90434d73 100644 --- a/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvOutputBuddy.java +++ b/jdplus-main-desktop/jdplus-sa-desktop-plugin/src/main/java/jdplus/sa/desktop/plugin/output/impl/CsvOutputBuddy.java @@ -1,55 +1,56 @@ /* -* Copyright 2016 National Bank of Belgium -* - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved + * Copyright 2016 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved * by the European Commission - subsequent versions of the EUPL (the "Licence"); -* You may not use this work except in compliance with the Licence. -* You may obtain a copy of the Licence at: -* + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * * http://ec.europa.eu/idabc/eupl -* - * Unless required by applicable law or agreed to in writing, software + * + * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the Licence for the specific language governing permissions and + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and * limitations under the Licence. */ package jdplus.sa.desktop.plugin.output.impl; -import com.google.common.base.Splitter; -import jdplus.toolkit.desktop.plugin.beans.BeanHandler; -import jdplus.toolkit.desktop.plugin.Config; -import jdplus.toolkit.desktop.plugin.ConfigEditor; -import jdplus.toolkit.desktop.plugin.properties.PropertySheetDialogBuilder; -import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; -import java.beans.IntrospectionException; -import java.io.File; -import java.util.List; -import java.util.stream.Collectors; - +import jdplus.sa.base.api.SaManager; +import jdplus.sa.base.api.SaOutputFactory; +import jdplus.sa.base.csv.CsvLayout; +import jdplus.sa.base.csv.CsvOutputConfiguration; +import jdplus.sa.base.csv.CsvOutputFactory; import jdplus.sa.desktop.plugin.output.AbstractOutputNode; import jdplus.sa.desktop.plugin.output.OutputFactoryBuddy; import jdplus.sa.desktop.plugin.output.OutputSelection; import jdplus.sa.desktop.plugin.output.Series; -import org.openide.nodes.Sheet; -import org.openide.util.lookup.ServiceProvider; +import jdplus.toolkit.desktop.plugin.Config; +import jdplus.toolkit.desktop.plugin.ConfigEditor; +import jdplus.toolkit.desktop.plugin.Converter; +import jdplus.toolkit.desktop.plugin.actions.Configurable; import jdplus.toolkit.desktop.plugin.actions.Resetable; +import jdplus.toolkit.desktop.plugin.beans.BeanConfigurator; +import jdplus.toolkit.desktop.plugin.beans.BeanEditor; +import jdplus.toolkit.desktop.plugin.beans.BeanHandler; +import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; +import jdplus.toolkit.desktop.plugin.properties.PropertySheetDialogBuilder; import nbbrd.io.text.BooleanProperty; import nbbrd.io.text.Formatter; import nbbrd.io.text.Parser; import nbbrd.io.text.Property; -import jdplus.toolkit.desktop.plugin.beans.BeanEditor; -import jdplus.toolkit.desktop.plugin.Converter; -import jdplus.toolkit.desktop.plugin.actions.Configurable; -import jdplus.toolkit.desktop.plugin.beans.BeanConfigurator; -import jdplus.sa.base.api.SaManager; -import jdplus.sa.base.api.SaOutputFactory; -import jdplus.sa.base.csv.CsvLayout; -import jdplus.sa.base.csv.CsvOutputConfiguration; -import jdplus.sa.base.csv.CsvOutputFactory; +import org.openide.nodes.Sheet; +import org.openide.util.lookup.ServiceProvider; + +import java.beans.IntrospectionException; +import java.io.File; +import java.util.List; +import java.util.stream.Collectors; + +import static jdplus.toolkit.base.tsp.fixme.Strings.nullToEmpty; +import static jdplus.toolkit.base.tsp.fixme.Strings.splitToStream; /** - * * @author Philippe Charles */ @ServiceProvider(service = OutputFactoryBuddy.class, position = 1000) @@ -57,8 +58,8 @@ public final class CsvOutputBuddy implements OutputFactoryBuddy, Configurable, C private final BeanConfigurator configurator = createConfigurator(); private CsvOutputConfiguration config = new CsvOutputConfiguration(); - - public CsvOutputBuddy(){ + + public CsvOutputBuddy() { } @Override @@ -154,7 +155,7 @@ public CsvOutputConfiguration doBackward(Config b) { result.setPresentation(presentationParam.get(b::getParameter)); result.setFolder(folderParam.get(b::getParameter)); result.setFilePrefix(filePrefixParam.get(b::getParameter)); - result.setSeries(Splitter.on(",").trimResults().splitToList(seriesParam.get(b::getParameter))); + result.setSeries(splitToStream(",", nullToEmpty(seriesParam.get(b::getParameter))).map(String::trim).toList()); result.setFullName(fullNameParam.get(b::getParameter)); return result; } @@ -162,7 +163,7 @@ public CsvOutputConfiguration doBackward(Config b) { private final static class CsvNode extends AbstractOutputNode { - private static CsvOutputConfiguration newConfiguration(){ + private static CsvOutputConfiguration newConfiguration() { CsvOutputConfiguration config = new CsvOutputConfiguration(); config.setSeries(OutputSelection.seriesItems(SaManager.processors())); return config; diff --git a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/pom.xml b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/pom.xml index 5553dcdb..17a1c511 100644 --- a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/pom.xml +++ b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-desktop - 3.0.2 + 3.1.0 jdplus-spreadsheet-desktop-plugin @@ -96,6 +96,11 @@ jdplus-toolkit-desktop-plugin ${project.version} + + eu.europa.ec.joinup.sat + jdplus-sa-desktop-plugin + ${project.version} + @@ -107,27 +112,7 @@ com.github.nbbrd.spreadsheet4j - spreadsheet-xmlss - ${spreadsheet4j.version} - - - com.github.nbbrd.spreadsheet4j - spreadsheet-od - ${spreadsheet4j.version} - - - com.github.nbbrd.spreadsheet4j - spreadsheet-xl - ${spreadsheet4j.version} - - - com.github.nbbrd.spreadsheet4j - spreadsheet-html - ${spreadsheet4j.version} - - - com.github.nbbrd.spreadsheet4j - spreadsheet-fastexcel + spreadsheet-standalone ${spreadsheet4j.version} diff --git a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/ec/util/grid/swing/ext/SheetGridCommand.java b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/ec/util/grid/swing/ext/SheetGridCommand.java index b36a61d0..70f48184 100644 --- a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/ec/util/grid/swing/ext/SheetGridCommand.java +++ b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/ec/util/grid/swing/ext/SheetGridCommand.java @@ -1,36 +1,35 @@ /* * Copyright 2013 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved * by the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: - * + * * http://ec.europa.eu/idabc/eupl - * - * Unless required by applicable law or agreed to in writing, software + * + * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and + * See the Licence for the specific language governing permissions and * limitations under the Licence. */ package ec.util.grid.swing.ext; -import com.google.common.collect.BoundType; -import com.google.common.collect.Range; import ec.util.grid.swing.GridModel; import ec.util.grid.swing.JGrid; import ec.util.spreadsheet.Cell; import ec.util.various.swing.JCommand; -import java.awt.Toolkit; -import java.awt.datatransfer.Transferable; -import org.checkerframework.checker.nullness.qual.NonNull; -import javax.swing.ListSelectionModel; -import jdplus.toolkit.desktop.plugin.datatransfer.DataTransferManager; +import jdplus.toolkit.base.api.data.Range; import jdplus.toolkit.base.api.util.Table; +import jdplus.toolkit.desktop.plugin.datatransfer.DataTransferManager; +import org.checkerframework.checker.nullness.qual.NonNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.datatransfer.Transferable; /** - * * @author Philippe Charles */ public abstract class SheetGridCommand extends JCommand { @@ -98,11 +97,7 @@ private static Table copy2(GridModel model, Range r, Range if (model.getRowCount() == 0 || model.getColumnCount() == 0) { return new Table<>(0, 0); } - int firstRow = r.hasLowerBound() ? (r.lowerBoundType().equals(BoundType.CLOSED) ? r.lowerEndpoint() : (r.lowerEndpoint() + 1)) : 0; - int lastRow = r.hasUpperBound() ? (r.upperBoundType().equals(BoundType.CLOSED) ? r.upperEndpoint() : (r.upperEndpoint() - 1)) : (model.getRowCount() - 1); - int firstColumn = c.hasLowerBound() ? (c.lowerBoundType().equals(BoundType.CLOSED) ? c.lowerEndpoint() : (c.lowerEndpoint() + 1)) : 0; - int lastColumn = c.hasUpperBound() ? (c.upperBoundType().equals(BoundType.CLOSED) ? c.upperEndpoint() : (c.upperEndpoint() - 1)) : (model.getColumnCount() - 1); - return copy(model, firstRow, firstColumn, lastRow, lastColumn, rowHeader, columnHeader); + return copy(model, r.start(), c.start(), r.end() - 1, c.end() - 1, rowHeader, columnHeader); } private static final class CopyAllCommand extends SheetGridCommand { @@ -118,7 +113,7 @@ public CopyAllCommand(boolean rowHeader, boolean columnHeader) { @Override public Table toTable(JGrid grid) { GridModel model = grid.getModel(); - return copy2(model, Range.all(), Range.all(), rowHeader, columnHeader); + return copy2(model, Range.of(0, model.getRowCount()), Range.of(0, model.getColumnCount()), rowHeader, columnHeader); } } @@ -137,7 +132,7 @@ public Table toTable(JGrid grid) { ListSelectionModel r = grid.getRowSelectionModel(); ListSelectionModel c = grid.getColumnSelectionModel(); return !r.isSelectionEmpty() && !c.isSelectionEmpty() - ? copy2(grid.getModel(), Range.closed(r.getMinSelectionIndex(), r.getMaxSelectionIndex()), Range.closed(c.getMinSelectionIndex(), c.getMaxSelectionIndex()), rowHeader, columnHeader) + ? copy2(grid.getModel(), Range.of(r.getMinSelectionIndex(), r.getMaxSelectionIndex() + 1), Range.of(c.getMinSelectionIndex(), c.getMaxSelectionIndex() + 1), rowHeader, columnHeader) : new Table<>(0, 0); } } diff --git a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/internal/spreadsheet/desktop/plugin/SpreadSheetDataTransferBeanHandler.java b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/internal/spreadsheet/desktop/plugin/SpreadSheetDataTransferBeanHandler.java index d605ebfa..d04c96bc 100644 --- a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/internal/spreadsheet/desktop/plugin/SpreadSheetDataTransferBeanHandler.java +++ b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/internal/spreadsheet/desktop/plugin/SpreadSheetDataTransferBeanHandler.java @@ -2,6 +2,8 @@ import jdplus.toolkit.base.tsp.grid.GridReader; import jdplus.toolkit.base.tsp.util.PropertyHandler; +import org.checkerframework.checker.nullness.qual.NonNull; + import java.util.function.BiConsumer; import java.util.function.Function; @@ -30,7 +32,7 @@ final class SpreadSheetDataTransferBeanHandler implements PropertyHandler exportTable; @Override - public SpreadSheetDataTransferBean get(Function properties) { + public @NonNull SpreadSheetDataTransferBean get(@NonNull Function properties) { SpreadSheetDataTransferBean result = new SpreadSheetDataTransferBean(); result.setImportTs(importTs.get(properties)); result.setTsReader(tsReader.get(properties)); @@ -43,7 +45,7 @@ public SpreadSheetDataTransferBean get(Function properties, SpreadSheetDataTransferBean value) { + public void set(@NonNull BiConsumer properties, SpreadSheetDataTransferBean value) { if (value != null) { importTs.set(properties, value.isImportTs()); tsReader.set(properties, value.getTsReader()); diff --git a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/SpreadSheetBasicFileHandler.java b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/SpreadSheetBasicFileHandler.java index 986fbaa9..dd6dacd6 100644 --- a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/SpreadSheetBasicFileHandler.java +++ b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/SpreadSheetBasicFileHandler.java @@ -16,7 +16,7 @@ */ package jdplus.spreadsheet.desktop.plugin; -import com.google.common.base.Stopwatch; +import jdplus.toolkit.desktop.plugin.util.Stopwatch; import jdplus.toolkit.desktop.plugin.util.NbComponents; import ec.util.desktop.Desktop; import ec.util.desktop.DesktopManager; diff --git a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetTsSave.java b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetTsSave.java index 9e26e193..81ca42d9 100644 --- a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetTsSave.java +++ b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetTsSave.java @@ -29,8 +29,8 @@ import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; import ec.util.spreadsheet.Book; import ec.util.spreadsheet.helpers.ArraySheet; -import ec.util.various.swing.OnAnyThread; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnAnyThread; +import nbbrd.design.swing.OnEDT; import java.io.File; import java.io.IOException; import java.util.List; diff --git a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/sa/SpreadsheetOutputBuddy.java b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/sa/SpreadsheetOutputBuddy.java new file mode 100644 index 00000000..7bcccd2f --- /dev/null +++ b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/main/java/jdplus/spreadsheet/desktop/plugin/sa/SpreadsheetOutputBuddy.java @@ -0,0 +1,223 @@ +/* + * Copyright 2016 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * http://ec.europa.eu/idabc/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.spreadsheet.desktop.plugin.sa; + +import jdplus.sa.base.api.SaOutputFactory; +import jdplus.sa.desktop.plugin.output.AbstractOutputNode; +import jdplus.sa.desktop.plugin.output.OutputFactoryBuddy; +import jdplus.sa.desktop.plugin.output.Series; +import jdplus.spreadsheet.base.api.sa.SpreadsheetOutputConfiguration; +import jdplus.spreadsheet.base.api.sa.SpreadsheetOutputConfiguration.SpreadsheetLayout; +import jdplus.spreadsheet.base.api.sa.SpreadsheetOutputFactory; +import jdplus.toolkit.desktop.plugin.Config; +import jdplus.toolkit.desktop.plugin.ConfigEditor; +import jdplus.toolkit.desktop.plugin.Converter; +import jdplus.toolkit.desktop.plugin.actions.Configurable; +import jdplus.toolkit.desktop.plugin.actions.Resetable; +import jdplus.toolkit.desktop.plugin.beans.BeanConfigurator; +import jdplus.toolkit.desktop.plugin.beans.BeanEditor; +import jdplus.toolkit.desktop.plugin.beans.BeanHandler; +import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; +import jdplus.toolkit.desktop.plugin.properties.PropertySheetDialogBuilder; +import nbbrd.io.text.BooleanProperty; +import nbbrd.io.text.Formatter; +import nbbrd.io.text.Parser; +import nbbrd.io.text.Property; +import org.openide.nodes.Sheet; +import org.openide.util.lookup.ServiceProvider; + +import java.beans.IntrospectionException; +import java.io.File; +import java.util.List; + +import static jdplus.toolkit.base.tsp.fixme.Strings.nullToEmpty; +import static jdplus.toolkit.base.tsp.fixme.Strings.splitToStream; + +/** + * @author Philippe Charles + */ +@ServiceProvider(service = OutputFactoryBuddy.class, position = 1300) +public final class SpreadsheetOutputBuddy implements OutputFactoryBuddy, Configurable, ConfigEditor, Resetable { + + private final BeanConfigurator configurator = createConfigurator(); + private SpreadsheetOutputConfiguration config = new SpreadsheetOutputConfiguration(); + + @Override + public String getName() { + return SpreadsheetOutputFactory.NAME; + } + + @Override + public AbstractOutputNode createNode() { + return new SpreadsheetNode(config); + } + + @Override + public AbstractOutputNode createNodeFor(Object properties) { + return properties instanceof SpreadsheetOutputConfiguration ? new SpreadsheetNode((SpreadsheetOutputConfiguration) properties) : null; + } + + @Override + public Config getConfig() { + return configurator.getConfig(this); + } + + @Override + public void setConfig(Config config) throws IllegalArgumentException { + configurator.setConfig(this, config); + } + + @Override + public Config editConfig(Config config) throws IllegalArgumentException { + return configurator.editConfig(config); + } + + @Override + public void configure() { + Configurable.configure(this, this); + } + + @Override + public void reset() { + config = new SpreadsheetOutputConfiguration(); + } + + private static BeanConfigurator createConfigurator() { + return new BeanConfigurator<>(new SpreadsheetOutputBeanHandler(), new SpreadsheetOutputConverter(), new SpreadsheetOutputBeanEditor()); + } + + private static final class SpreadsheetOutputBeanHandler implements BeanHandler { + + @Override + public SpreadsheetOutputConfiguration load(SpreadsheetOutputBuddy resource) { + return resource.config.clone(); + } + + @Override + public void store(SpreadsheetOutputBuddy resource, SpreadsheetOutputConfiguration bean) { + resource.config = bean; + } + } + + private static final class SpreadsheetOutputBeanEditor implements BeanEditor { + + @Override + public boolean editBean(Object bean) throws IntrospectionException { + return new PropertySheetDialogBuilder() + .title("Edit spreadsheet output config") + .editNode(new SpreadsheetNode((SpreadsheetOutputConfiguration) bean)); + } + } + + private static final class SpreadsheetOutputConverter implements Converter { + + private final BooleanProperty saveModelParam = BooleanProperty.of("saveModel", false); + private final BooleanProperty verticalOrientationParam = BooleanProperty.of("verticalOrientation", true); + private final Property layoutParam = Property.of("layout", SpreadsheetLayout.BySeries, Parser.onEnum(SpreadsheetLayout.class), Formatter.onEnum()); + private final Property folderParam = Property.of("folder", new File(""), Parser.onFile(), Formatter.onFile()); + private final Property fileNameParam = Property.of("fileName", "series", Parser.onString(), Formatter.onString()); + private final Property seriesParam = Property.of("series", "y,t,sa,s,i,ycal", Parser.onString(), Formatter.onString()); + private final BooleanProperty fullNameParam = BooleanProperty.of("fullName", true); + + @Override + public Config doForward(SpreadsheetOutputConfiguration a) { + Config.Builder result = Config.builder("outputs", "csv", "3.0"); + saveModelParam.set(result::parameter, a.isSaveModel()); + verticalOrientationParam.set(result::parameter, a.isVerticalOrientation()); + layoutParam.set(result::parameter, a.getLayout()); + folderParam.set(result::parameter, a.getFolder()); + fileNameParam.set(result::parameter, a.getFileName()); + seriesParam.set(result::parameter, String.join(",", a.getSeries())); + fullNameParam.set(result::parameter, a.isFullName()); + return result.build(); + } + + @Override + public SpreadsheetOutputConfiguration doBackward(Config b) { + SpreadsheetOutputConfiguration result = new SpreadsheetOutputConfiguration(); + result.setSaveModel(saveModelParam.get(b::getParameter)); + result.setVerticalOrientation(verticalOrientationParam.get(b::getParameter)); + result.setLayout(layoutParam.get(b::getParameter)); + result.setFolder(folderParam.get(b::getParameter)); + result.setFileName(fileNameParam.get(b::getParameter)); + result.setSeries(splitToStream(',', nullToEmpty(seriesParam.get(b::getParameter))).map(String::trim).toList()); + result.setFullName(fullNameParam.get(b::getParameter)); + return result; + } + } + + private final static class SpreadsheetNode extends AbstractOutputNode { + + public SpreadsheetNode(SpreadsheetOutputConfiguration config) { + super(config); + setDisplayName(SpreadsheetOutputFactory.NAME); + } + + @Override + protected Sheet createSheet() { + SpreadsheetOutputConfiguration config = getLookup().lookup(SpreadsheetOutputConfiguration.class); + + Sheet sheet = super.createSheet(); + + NodePropertySetBuilder b = new NodePropertySetBuilder(); + + b.reset("Location"); + b.withFile() + .select("folder", config::getFolder, config::setFolder) + .directories(true) + .display("Folder") + .description("Base output folder. Will be extended by the workspace and processing names") + .add(); + b.with(String.class) + .select("FileName", config::getFileName, config::setFileName) + .display("File name") + .add(); + sheet.put(b.build()); + + b.reset("Layout"); + b.withEnum(SpreadsheetLayout.class) + .select("layout", config::getLayout, config::setLayout) + .display("Layout") + .add(); + b.withBoolean() + .select("verticalOrientation", config::isVerticalOrientation, config::setVerticalOrientation) + .display("Vertical orientation") + .add(); + b.withBoolean() + .select("fullName", config::isFullName, config::setFullName) + .display("Full series name") + .description("If true, the fully qualified name of the series will be used (workbook + sheet + name). " + + "If false, only the name of the series will be displayed.") + .add(); + sheet.put(b.build()); + + b.reset("Content"); + b.with(List.class) + .select("Series", config::getSeries, config::setSeries) + .editor(Series.class) + .add(); + sheet.put(b.build()); + + return sheet; + } + + @Override + public SaOutputFactory getFactory() { + return new SpreadsheetOutputFactory(getLookup().lookup(SpreadsheetOutputConfiguration.class)); + } + } +} diff --git a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/test/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetRuntimeDependenciesTest.java b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/test/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetRuntimeDependenciesTest.java index e2801134..528c66ed 100644 --- a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/test/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetRuntimeDependenciesTest.java +++ b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/test/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetRuntimeDependenciesTest.java @@ -23,7 +23,7 @@ public void test() throws IOException { .describedAs("Check runtime dependencies") .satisfies(SpreadsheetRuntimeDependenciesTest::checkSpreadsheet) .satisfies(SpreadsheetRuntimeDependenciesTest::checkSpreadsheet4j) - .hasSize(12); + .hasSize(3); } private static void checkSpreadsheet(List coordinates) { @@ -38,24 +38,8 @@ private static void checkSpreadsheet4j(List coordinates) { assertThatGroupId(coordinates, "com.github.nbbrd.spreadsheet4j") .has(sameVersion()) .extracting(GAV::getArtifactId) - .are(matchingPattern(compile("^spreadsheet-(api|util|xmlss|od|xl|html|fastexcel)$"))) - .hasSize(7); - - assertThatGroupId(coordinates, "com.github.miachm.sods") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("SODS"); - - assertThatGroupId(coordinates, "com.github.rzymek") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("opczip"); - - assertThatGroupId(coordinates, "org.dhatim") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("fastexcel"); - - assertThatGroupId(coordinates, "org.jsoup") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("jsoup"); + .are(matchingPattern(compile("^spreadsheet-(api|standalone)$"))) + .hasSize(2); } @MightBePromoted diff --git a/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/test/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetStandaloneTest.java b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/test/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetStandaloneTest.java new file mode 100644 index 00000000..cc997c43 --- /dev/null +++ b/jdplus-main-desktop/jdplus-spreadsheet-desktop-plugin/src/test/java/jdplus/spreadsheet/desktop/plugin/SpreadsheetStandaloneTest.java @@ -0,0 +1,49 @@ +package jdplus.spreadsheet.desktop.plugin; + +import ec.util.spreadsheet.Book; +import ec.util.spreadsheet.helpers.ArrayBook; +import ec.util.spreadsheet.helpers.ArraySheet; +import internal.spreadsheet.base.api.SpreadsheetManager; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +public class SpreadsheetStandaloneTest { + + @Test + public void testStandaloneFactories(@TempDir Path temp) { + String[] extensions = {".htm", ".xlsx", ".xml", ".ods"}; + + ArrayBook expected = ArraySheet.copyOf("name1", new Object[][]{ + {"A1", "B1"}, + {"A2", "B2"}, + }).toBook(); + + SpreadsheetManager manager = SpreadsheetManager.ofServiceLoader(); + + for (Path file : Stream.of(extensions).map(ext -> temp.resolve("hello" + ext)).toList()) { + Optional writer = manager.getWriter(file.toFile()); + assertThat(writer).isNotEmpty(); + assertThatCode(() -> writer.orElseThrow().store(file, expected)) + .doesNotThrowAnyException(); + + Optional reader = manager.getReader(file.toFile()); + assertThat(reader).isNotEmpty(); + AtomicReference found = new AtomicReference<>(); + assertThatCode(() -> { + try (Book result = reader.orElseThrow().load(file)) { + found.set(ArrayBook.copyOf(result)); + } + }).doesNotThrowAnyException(); + assertThat(found).hasValue(expected); + } + } +} diff --git a/jdplus-main-desktop/jdplus-sql-desktop-plugin/pom.xml b/jdplus-main-desktop/jdplus-sql-desktop-plugin/pom.xml index 7c9f2e2f..adf337f3 100644 --- a/jdplus-main-desktop/jdplus-sql-desktop-plugin/pom.xml +++ b/jdplus-main-desktop/jdplus-sql-desktop-plugin/pom.xml @@ -4,7 +4,7 @@ eu.europa.ec.joinup.sat jdplus-main-desktop - 3.0.2 + 3.1.0 jdplus-sql-desktop-plugin diff --git a/jdplus-main-desktop/jdplus-text-desktop-plugin/pom.xml b/jdplus-main-desktop/jdplus-text-desktop-plugin/pom.xml index 05bc1542..6c030feb 100644 --- a/jdplus-main-desktop/jdplus-text-desktop-plugin/pom.xml +++ b/jdplus-main-desktop/jdplus-text-desktop-plugin/pom.xml @@ -4,7 +4,7 @@ eu.europa.ec.joinup.sat jdplus-main-desktop - 3.0.2 + 3.1.0 jdplus-text-desktop-plugin diff --git a/jdplus-main-desktop/jdplus-text-desktop-plugin/src/main/java/jdplus/text/desktop/plugin/TxtTsSave.java b/jdplus-main-desktop/jdplus-text-desktop-plugin/src/main/java/jdplus/text/desktop/plugin/TxtTsSave.java index 9a0192af..4b89a32f 100644 --- a/jdplus-main-desktop/jdplus-text-desktop-plugin/src/main/java/jdplus/text/desktop/plugin/TxtTsSave.java +++ b/jdplus-main-desktop/jdplus-text-desktop-plugin/src/main/java/jdplus/text/desktop/plugin/TxtTsSave.java @@ -25,8 +25,8 @@ import jdplus.toolkit.desktop.plugin.NamedServiceSupport; import jdplus.toolkit.desktop.plugin.Persistable; import jdplus.toolkit.desktop.plugin.datatransfer.ts.TxtDataTransfer; -import ec.util.various.swing.OnAnyThread; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnAnyThread; +import nbbrd.design.swing.OnEDT; import internal.text.base.api.TxtFileFilter; import nbbrd.io.text.Formatter; import nbbrd.service.ServiceProvider; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/pom.xml b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/pom.xml index e6a24154..439f3e32 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/pom.xml +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-desktop - 3.0.2 + 3.1.0 jdplus-toolkit-desktop-plugin @@ -182,8 +182,8 @@ com.miglayout - miglayout - 3.7.4 + miglayout-swing + 11.2 org.tros @@ -202,17 +202,6 @@ - - com.google.guava - guava - 31.1-jre - - - jsr305 - com.google.code.findbugs - - - com.github.nbbrd.java-io-util java-io-base @@ -276,7 +265,6 @@ internal.* - com.google.* org.apache.commons.* nbbrd.io.* internal.io.* diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ColorSchemeManager.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ColorSchemeManager.java index 07d4ec71..bee7e3b8 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ColorSchemeManager.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ColorSchemeManager.java @@ -7,7 +7,7 @@ import ec.util.chart.ColorScheme; import ec.util.chart.impl.SmartColorScheme; import ec.util.chart.swing.SwingColorSchemeSupport; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/NamedService.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/NamedService.java index 59655670..e5526885 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/NamedService.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/NamedService.java @@ -16,7 +16,7 @@ */ package jdplus.toolkit.desktop.plugin; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.openide.nodes.Sheet; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionManager.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionManager.java index 22b78341..29bf4790 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionManager.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionManager.java @@ -21,7 +21,7 @@ import jdplus.toolkit.desktop.plugin.util.LazyGlobalService; import jdplus.toolkit.base.api.timeseries.Ts; import jdplus.toolkit.base.api.timeseries.TsCollection; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import nbbrd.design.MightBePromoted; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionOpenSpi.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionOpenSpi.java index d9c91c19..bf1a06d7 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionOpenSpi.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionOpenSpi.java @@ -18,7 +18,7 @@ import jdplus.toolkit.desktop.plugin.util.NetBeansServiceBackend; import jdplus.toolkit.base.api.timeseries.Ts; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import nbbrd.service.Quantifier; import nbbrd.service.ServiceDefinition; import org.checkerframework.checker.nullness.qual.NonNull; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionSaveSpi.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionSaveSpi.java index 01ea9efa..3d521b9b 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionSaveSpi.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionSaveSpi.java @@ -7,7 +7,7 @@ import jdplus.toolkit.desktop.plugin.util.NetBeansServiceBackend; import jdplus.toolkit.base.api.timeseries.TsCollection; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import nbbrd.service.Quantifier; import nbbrd.service.ServiceDefinition; import org.checkerframework.checker.nullness.qual.NonNull; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionSaveSpiSupport.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionSaveSpiSupport.java index 2bc14599..62fd48d7 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionSaveSpiSupport.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsActionSaveSpiSupport.java @@ -5,7 +5,7 @@ import jdplus.toolkit.desktop.plugin.util.SingleFileExporter; import jdplus.toolkit.base.api.timeseries.TsCollection; import jdplus.toolkit.base.api.timeseries.TsInformationType; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import java.beans.IntrospectionException; import java.io.File; import java.util.List; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsDynamicProvider.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsDynamicProvider.java index 7ecd7e13..08248098 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsDynamicProvider.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsDynamicProvider.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.UUID; import nbbrd.service.ServiceProvider; +import org.checkerframework.checker.nullness.qual.NonNull; /** * @@ -65,7 +66,7 @@ public void close() { } @Override - public TsCollection getTsCollection(TsMoniker moniker, TsInformationType type) throws IOException, IllegalArgumentException { + public @NonNull TsCollection getTsCollection(@NonNull TsMoniker moniker, @NonNull TsInformationType type) throws IOException, IllegalArgumentException { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @@ -77,7 +78,7 @@ private Ts invalidTs(TsMoniker moniker, String cause) { } @Override - public Ts getTs(TsMoniker moniker, TsInformationType type) throws IOException, IllegalArgumentException { + public @NonNull Ts getTs(@NonNull TsMoniker moniker, @NonNull TsInformationType type) throws IOException, IllegalArgumentException { synchronized (DOCUMENTS) { if (moniker.getSource().equals(DYNAMIC)) { String[] items = moniker.getId().split("@"); @@ -110,7 +111,7 @@ public Ts getTs(TsMoniker moniker, TsInformationType type) throws IOException, I } @Override - public String getSource() { + public @NonNull String getSource() { return DYNAMIC; } diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsListener.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsListener.java index cfe02548..db1234d3 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsListener.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsListener.java @@ -1,6 +1,6 @@ package jdplus.toolkit.desktop.plugin; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import org.checkerframework.checker.nullness.qual.NonNull; import java.util.EventListener; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsManager.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsManager.java index 9d04a8cc..bc4e6786 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsManager.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/TsManager.java @@ -23,8 +23,8 @@ import jdplus.toolkit.base.tsp.DataSourceFactory; import jdplus.toolkit.base.tsp.DataSourceListener; import jdplus.toolkit.base.tsp.DataSourceProvider; -import ec.util.various.swing.OnAnyThread; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnAnyThread; +import nbbrd.design.swing.OnEDT; import org.checkerframework.checker.nullness.qual.NonNull; import org.openide.util.WeakListeners; @@ -171,16 +171,16 @@ private void notifyUpdateListeners() { private final class DataSourceListenerImpl implements DataSourceListener { @Override - public void opened(DataSource ds) { + public void opened(@NonNull DataSource ds) { } @Override - public void closed(DataSource ds) { + public void closed(@NonNull DataSource ds) { } @OnAnyThread @Override - public void changed(DataSource ds) { + public void changed(@NonNull DataSource ds) { Optional provider = getProvider(DataSourceProvider.class, ds); if (provider.isPresent()) { TsManager.this.notify(dataSetMoniker -> isRelated(provider.orElseThrow(), ds, dataSetMoniker)); @@ -196,7 +196,7 @@ private boolean isRelated(DataSourceProvider provider, DataSource dataSource, Ts } @Override - public void allClosed(String string) { + public void allClosed(@NonNull String string) { } } diff --git a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/IOExceptionUtil.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/actions/Repaintable.java similarity index 56% rename from jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/IOExceptionUtil.java rename to jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/actions/Repaintable.java index cb37b7d5..c86627c1 100644 --- a/jdplus-main-base/jdplus-toolkit-base-parent/jdplus-toolkit-base-tsp/src/test/java/_util/IOExceptionUtil.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/actions/Repaintable.java @@ -1,40 +1,33 @@ /* - * Copyright 2017 National Bank of Belgium - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved + * Copyright 2019 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved * by the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: - * + * * http://ec.europa.eu/idabc/eupl - * - * Unless required by applicable law or agreed to in writing, software + * + * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and + * See the Licence for the specific language governing permissions and * limitations under the Licence. */ -package _util; +package jdplus.toolkit.desktop.plugin.actions; -import java.io.Closeable; -import java.io.IOException; -import java.util.function.Supplier; +import lombok.NonNull; +import org.openide.nodes.Node; /** - * * @author Philippe Charles */ -public final class IOExceptionUtil { +public interface Repaintable { - public static Closeable asCloseable(Supplier factory) { - return () -> { - throw factory.get(); - }; - } - - public static final class FirstIO extends IOException { - } + void repaint(); - public static final class SecondIO extends IOException { + static void repaintNode(@NonNull Node node) { + Repaintable repaintable = node.getLookup().lookup(Repaintable.class); + if (repaintable != null) repaintable.repaint(); } } diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/actions/SaveNodeAction.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/actions/SaveNodeAction.java new file mode 100644 index 00000000..6b20b695 --- /dev/null +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/actions/SaveNodeAction.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * http://ec.europa.eu/idabc/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.desktop.plugin.core.actions; + +import java.io.IOException; +import jdplus.toolkit.desktop.plugin.actions.AbilityNodeAction; +import org.netbeans.api.actions.Openable; +import org.openide.awt.ActionID; +import org.openide.awt.ActionRegistration; +import org.openide.util.NbBundle.Messages; + +import java.util.stream.Stream; +import org.netbeans.api.actions.Savable; +import org.openide.util.Exceptions; + +/** + * + * @author Philippe Charles + */ +@ActionID(category = "File", id = SaveNodeAction.ID) +@ActionRegistration(displayName = "#SaveNodeAction", lazy = false) +@Messages("SaveNodeAction=Save") +public final class SaveNodeAction extends AbilityNodeAction { + + public static final String ID = "demetra.desktop.core.actions.SaveNodeAction"; + + public SaveNodeAction() { + super(Savable.class); + } + + @Override + protected void performAction(Stream items) { + items.forEach(savable -> { + try { + savable.save(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + }); + } + + @Override + public String getName() { + return Bundle.SaveNodeAction(); + } +} diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/completion/CharsetAutoCompletionService.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/completion/CharsetAutoCompletionService.java index c6f98ec9..d033898d 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/completion/CharsetAutoCompletionService.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/completion/CharsetAutoCompletionService.java @@ -1,7 +1,6 @@ package jdplus.toolkit.desktop.plugin.core.completion; import jdplus.toolkit.desktop.plugin.completion.AutoCompletionSpi; -import jdplus.toolkit.base.api.util.List2; import ec.util.completion.AutoCompletionSource; import ec.util.completion.ExtAutoCompletionSource; import ec.util.completion.swing.CustomListCellRenderer; @@ -51,7 +50,7 @@ private static AutoCompletionSource charsetSource() { } private static List getCharsets() { - return List2.copyOf(Charset.availableCharsets().values()); + return List.copyOf(Charset.availableCharsets().values()); } private static List getCharsets(List allValues, String term) { diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/datatransfer/TsDragRenderer.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/datatransfer/TsDragRenderer.java index 9225c4db..735bd224 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/datatransfer/TsDragRenderer.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/datatransfer/TsDragRenderer.java @@ -4,24 +4,21 @@ */ package jdplus.toolkit.desktop.plugin.core.datatransfer; -import com.google.common.base.Suppliers; +import jdplus.toolkit.base.api.timeseries.Ts; import jdplus.toolkit.base.api.timeseries.TsCollection; -import jdplus.toolkit.desktop.plugin.util.TransferHandlers; import jdplus.toolkit.desktop.plugin.components.JTsChart; -import jdplus.toolkit.base.api.timeseries.Ts; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Font; +import jdplus.toolkit.desktop.plugin.util.Collections2; +import jdplus.toolkit.desktop.plugin.util.TransferHandlers; + +import javax.swing.*; +import java.awt.*; import java.awt.image.BufferedImage; import java.util.List; import java.util.function.Supplier; -import static javax.swing.BorderFactory.*; -import javax.swing.JLabel; -import javax.swing.JPanel; + +import static javax.swing.BorderFactory.createEmptyBorder; /** - * * @author Philippe Charles */ public abstract class TsDragRenderer { @@ -42,7 +39,7 @@ public static TsDragRenderer asCount() { private static class ChartRenderer extends TsDragRenderer { - final Supplier supplier = Suppliers.memoize(ChartRenderer::createChart); + final Supplier supplier = Collections2.memoize(ChartRenderer::createChart); @Override public Component getTsDragRendererComponent(List selection) { diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarAction.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarAction.java index bf5ad51d..14eb32df 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarAction.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarAction.java @@ -16,9 +16,11 @@ */ package jdplus.toolkit.desktop.plugin.core.star; +import jdplus.toolkit.base.tsp.DataSource; +import jdplus.toolkit.desktop.plugin.actions.Repaintable; import jdplus.toolkit.desktop.plugin.nodes.SingleNodeAction; import jdplus.toolkit.desktop.plugin.star.StarListManager; -import jdplus.toolkit.base.tsp.DataSource; +import lombok.NonNull; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -46,20 +48,16 @@ public StarAction() { } @Override - protected boolean enable(Node activatedNode) { - Optional dataSource = getDataSource(activatedNode); - if (dataSource.isPresent()) { - updateDisplayName(dataSource.orElseThrow()); - return true; - } - return false; + protected boolean enable(@NonNull Node activatedNode) { + return !getDataSource(activatedNode).stream().peek(this::updateActionName).toList().isEmpty(); } @Override - protected void performAction(Node activatedNode) { + protected void performAction(@NonNull Node activatedNode) { getDataSource(activatedNode).ifPresent(dataSource -> { StarListManager.get().toggle(dataSource); - updateDisplayName(dataSource); + updateActionName(dataSource); + Repaintable.repaintNode(activatedNode); }); } @@ -68,7 +66,7 @@ public String getName() { return Bundle.starAction_add(); } - private void updateDisplayName(DataSource dataSource) { + private void updateActionName(DataSource dataSource) { putValue(NAME, StarListManager.get().isStarred(dataSource) ? Bundle.starAction_remove() : Bundle.starAction_add()); } diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarAnnotator.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarAnnotator.java index 043ea440..ccd74cdb 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarAnnotator.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarAnnotator.java @@ -8,6 +8,7 @@ import jdplus.toolkit.desktop.plugin.nodes.NodeAnnotatorSpi; import jdplus.toolkit.desktop.plugin.star.StarListManager; import jdplus.toolkit.base.tsp.DataSource; +import lombok.NonNull; import org.openide.nodes.Node; import org.openide.util.ImageUtilities; import org.openide.util.lookup.ServiceProvider; @@ -18,7 +19,7 @@ * @author Philippe Charles */ @ServiceProvider(service = NodeAnnotatorSpi.class) -public class StarAnnotator implements NodeAnnotatorSpi { +public final class StarAnnotator implements NodeAnnotatorSpi { boolean isStarred(Node node) { DataSource dataSource = node.getLookup().lookup(DataSource.class); @@ -26,19 +27,16 @@ boolean isStarred(Node node) { } @Override - public Image annotateIcon(Node node, Image image) { + public @NonNull Image annotateIcon(@NonNull Node node, @NonNull Image image) { if (isStarred(node)) { Image badge = DemetraIcons.BULLET_STAR.getImageIcon().getImage(); return ImageUtilities.mergeImages(image, badge, 10, 0); - -// String ressource = !starred ? "ec/nbdemetra/ui/nodes/star-empty.png" : "ec/nbdemetra/ui/nodes/star.png"; -// return ImageUtilities.loadImage(ressource, true); } return image; } @Override - public String annotateName(Node node, String name) { + public @NonNull String annotateName(@NonNull Node node, @NonNull String name) { return name; } } diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarStep.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarStep.java new file mode 100644 index 00000000..f5cf4da5 --- /dev/null +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/star/StarStep.java @@ -0,0 +1,93 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package jdplus.toolkit.desktop.plugin.core.star; + +import jdplus.toolkit.base.tsp.DataSource; +import jdplus.toolkit.desktop.plugin.TsManager; +import jdplus.toolkit.desktop.plugin.star.StarListManager; +import jdplus.toolkit.desktop.plugin.util.InstallerStep; +import nbbrd.design.VisibleForTesting; +import nbbrd.io.text.Formatter; +import nbbrd.io.text.Parser; +import org.openide.util.NbPreferences; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; +import java.util.stream.Stream; + +import static java.util.Collections.emptyList; +import static java.util.Comparator.reverseOrder; +import static jdplus.toolkit.base.api.util.Collections2.streamOf; + +/** + * @author Philippe Charles + */ +@lombok.extern.java.Log +public class StarStep extends InstallerStep { + + @Override + public void restore() { + TsManager tsManager = TsManager.get(); + StarListManager stars = StarListManager.get(); + loadSources(getStarNode()) + .forEach(dataSource -> { + stars.add(dataSource); + tsManager.open(dataSource); + }); + } + + @Override + public void close() { + StarListManager stars = StarListManager.get(); + storeSources(getStarNode(), stars); + } + + private static Preferences getStarNode() { + return NbPreferences.forModule(StarStep.class).node("Star"); + } + + private static final String DATASOURCE_PROPERTY = "StarDataSource"; + + @VisibleForTesting + static Iterable loadSources(Preferences prefs) { + try { + return Stream.of(prefs.childrenNames()) + .map(pathName -> prefs.node(pathName).get(DATASOURCE_PROPERTY, null)) + .map(Parser.of(DataSource::parse)::parse) + .filter(Objects::nonNull) + .toList(); + } catch (BackingStoreException ex) { + log.log(Level.WARNING, "Can't load stared data sources", ex); + return emptyList(); + } + } + + @VisibleForTesting + static void storeSources(Preferences prefs, Iterable dataSources) { + try { + for (String i : prefs.childrenNames()) { + prefs.node(i).removeNode(); + } + Supplier pathName = getPathNameSupplier(); + streamOf(dataSources) + .map(Formatter.of(DataSource::toString)::formatAsString) + .filter(Objects::nonNull) + .forEach(o -> prefs.node(pathName.get()).put(DATASOURCE_PROPERTY, o)); + prefs.flush(); + } catch (BackingStoreException ex) { + log.log(Level.WARNING, "Can't store stared data sources", ex); + } + } + + @VisibleForTesting + static Supplier getPathNameSupplier() { + AtomicInteger index = new AtomicInteger(); + return () -> String.valueOf(index.getAndIncrement()); + } +} diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tools/JTsGridTopComponent.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tools/JTsGridTopComponent.java index e589282a..6528e2f4 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tools/JTsGridTopComponent.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tools/JTsGridTopComponent.java @@ -14,6 +14,7 @@ import static jdplus.toolkit.desktop.plugin.components.JTsGrid.REVERSE_ACTION; import static jdplus.toolkit.desktop.plugin.components.JTsGrid.TRANSPOSE_ACTION; import java.awt.BorderLayout; +import java.util.Set; import javax.swing.*; import org.netbeans.api.settings.ConvertAsProperties; import org.netbeans.core.spi.multiview.CloseOperationState; @@ -74,7 +75,6 @@ private void initComponents() { @Override public void open() { super.open(); - WindowManager.getDefault().getModes(); Mode mode = WindowManager.getDefault().findMode("tsnavigator"); if (mode != null) { mode.dockInto(this); diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tools/JTsTableTopComponent.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tools/JTsTableTopComponent.java index 731366b5..9fcd2834 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tools/JTsTableTopComponent.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tools/JTsTableTopComponent.java @@ -62,7 +62,6 @@ private void initComponents() { @Override public void open() { super.open(); - WindowManager.getDefault().getModes(); Mode mode = WindowManager.getDefault().findMode("tsnavigator"); if (mode != null) { mode.dockInto(this); diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/ts/actions/LockDocument.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/ts/actions/LockDocument.java new file mode 100644 index 00000000..7d0235db --- /dev/null +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/ts/actions/LockDocument.java @@ -0,0 +1,75 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.desktop.plugin.core.ts.actions; + +import static javax.swing.Action.NAME; +import jdplus.toolkit.base.api.timeseries.TsDocument; +import jdplus.toolkit.desktop.plugin.ui.ActiveViewAction; +import jdplus.toolkit.desktop.plugin.workspace.WorkspaceFactory; +import jdplus.toolkit.desktop.plugin.workspace.ui.WorkspaceTsTopComponent; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.awt.ActionRegistration; +import org.openide.util.NbBundle; + +/** + * + * @author palatej + */ +@ActionID(category = "Processing", + id = "demetra.desktop.core.ts.actions.LockDocument") +@ActionRegistration(displayName = "#CTL_LockDocument", lazy = false) +@ActionReferences({ + @ActionReference(path = WorkspaceFactory.TSCONTEXTPATH, position = 1500), + @ActionReference(path = "Shortcuts", name = "L") +}) +@NbBundle.Messages("CTL_LockDocument=Lock") +public final class LockDocument extends ActiveViewAction { + + private boolean locked; + + public LockDocument() { + super(WorkspaceTsTopComponent.class); + putValue(NAME, Bundle.CTL_LockDocument()); + refreshAction(); + } + + @Override + protected void refreshAction() { + enabled=false; + locked=false; + WorkspaceTsTopComponent> cur = context(); + if (cur != null) { + enabled = true; + TsDocument element = cur.getDocument().getElement(); + locked = element.isLocked(); + } + if (locked) { + putValue(NAME, "Unlock"); + } + else { + putValue(NAME, "Lock"); + } + } + + @Override + protected void process(WorkspaceTsTopComponent cur) { + WorkspaceTsTopComponent> tcur = cur; + tcur.getDocument().getElement().setLocked(!locked); + } +} diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/ts/actions/RefreshTs.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/ts/actions/RefreshTs.java new file mode 100644 index 00000000..72256922 --- /dev/null +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/ts/actions/RefreshTs.java @@ -0,0 +1,71 @@ +/* + * Copyright 2022 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.desktop.plugin.core.ts.actions; + +import jdplus.toolkit.base.api.timeseries.TsDocument; +import jdplus.toolkit.base.api.timeseries.TsFactory; +import jdplus.toolkit.base.api.timeseries.TsInformationType; +import jdplus.toolkit.desktop.plugin.ui.ActiveViewAction; +import jdplus.toolkit.desktop.plugin.workspace.WorkspaceFactory; +import jdplus.toolkit.desktop.plugin.workspace.WorkspaceItem; +import jdplus.toolkit.desktop.plugin.workspace.ui.WorkspaceTsTopComponent; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.awt.ActionRegistration; +import org.openide.util.NbBundle.Messages; + +@ActionID(category = "Processing", + id = "demetra.desktop.core.ts.actions.RefreshTs") +@ActionRegistration(displayName = "#CTL_RefreshTs", lazy = false) +@ActionReferences({ + @ActionReference(path = WorkspaceFactory.TSCONTEXTPATH, position = 1510), + @ActionReference(path = "Shortcuts", name = "R") +}) +@Messages("CTL_RefreshTs=Refresh Data") +public final class RefreshTs extends ActiveViewAction { + + public RefreshTs() { + super(WorkspaceTsTopComponent.class); + putValue(NAME, Bundle.CTL_RefreshTs()); + refreshAction(); + } + + @Override + protected void refreshAction() { + enabled = false; + WorkspaceTsTopComponent> cur = context(); + if (cur != null) { + enabled = true; + TsDocument element = cur.getDocument().getElement(); + enabled = element.isFrozen(); + } + } + + @Override + protected void process(WorkspaceTsTopComponent cur) { + if (cur != null) { + enabled = true; + WorkspaceItem wcur = cur.getDocument(); + TsDocument element = (TsDocument) wcur.getElement(); + element.refreshTs(TsFactory.getDefault(), TsInformationType.Data); + WorkspaceFactory.Event ev = new WorkspaceFactory.Event(wcur.getOwner(), wcur.getId(), WorkspaceFactory.Event.ITEMCHANGED, null); + WorkspaceFactory.getInstance().notifyEvent(ev); + wcur.setDirty(); + } + } +} diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/DataSourceNode.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/DataSourceNode.java index 0fcfcb1c..79d260e8 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/DataSourceNode.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/DataSourceNode.java @@ -16,11 +16,18 @@ */ package jdplus.toolkit.desktop.plugin.core.tsproviders; +import jdplus.toolkit.base.api.timeseries.TsCollection; +import jdplus.toolkit.base.api.timeseries.TsInformationType; +import jdplus.toolkit.base.tsp.DataSet; +import jdplus.toolkit.base.tsp.DataSource; +import jdplus.toolkit.base.tsp.DataSourceLoader; +import jdplus.toolkit.base.tsp.DataSourceProvider; import jdplus.toolkit.desktop.plugin.Config; import jdplus.toolkit.desktop.plugin.TsCollectable; import jdplus.toolkit.desktop.plugin.TsManager; import jdplus.toolkit.desktop.plugin.actions.Reloadable; import jdplus.toolkit.desktop.plugin.actions.Renameable; +import jdplus.toolkit.desktop.plugin.actions.Repaintable; import jdplus.toolkit.desktop.plugin.core.actions.CloseNodeAction; import jdplus.toolkit.desktop.plugin.core.actions.ReloadNodeAction; import jdplus.toolkit.desktop.plugin.core.actions.RenameNodeAction; @@ -36,12 +43,6 @@ import jdplus.toolkit.desktop.plugin.star.StarListManager; import jdplus.toolkit.desktop.plugin.tsproviders.DataSourceManager; import jdplus.toolkit.desktop.plugin.tsproviders.DataSourceProviderBuddyUtil; -import jdplus.toolkit.base.api.timeseries.TsInformationType; -import jdplus.toolkit.base.api.timeseries.TsCollection; -import jdplus.toolkit.base.tsp.DataSet; -import jdplus.toolkit.base.tsp.DataSource; -import jdplus.toolkit.base.tsp.DataSourceLoader; -import jdplus.toolkit.base.tsp.DataSourceProvider; import org.checkerframework.checker.nullness.qual.NonNull; import org.netbeans.api.actions.Closable; import org.netbeans.api.actions.Editable; @@ -106,6 +107,7 @@ private DataSourceNode(DataSource dataSource, InstanceContent abilities) { { abilities.add(new NameableImpl()); abilities.add(new TsCollectableImpl()); + abilities.add(new RepaintableImpl()); abilities.add(new ReloadableImpl()); if (TsManager.get().getProvider(DataSourceLoader.class, dataSource).isPresent()) { abilities.add(new EditableImpl()); @@ -212,6 +214,15 @@ protected Node createExceptionNode(Exception ex) { } } + private final class RepaintableImpl implements Repaintable { + + @Override + public void repaint() { + fireIconChange(); + fireOpenedIconChange(); + } + } + private final class ReloadableImpl implements Reloadable { @Override diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/PasteProvidersNodeAction.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/PasteProvidersNodeAction.java index 1bbdca35..eb01e875 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/PasteProvidersNodeAction.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/PasteProvidersNodeAction.java @@ -19,8 +19,6 @@ import jdplus.toolkit.desktop.plugin.TsManager; import jdplus.toolkit.desktop.plugin.datatransfer.DataSourceTransferManager; import jdplus.toolkit.desktop.plugin.datatransfer.DataTransfers; -import jdplus.toolkit.base.tsp.DataSource; -import jdplus.toolkit.base.tsp.DataSourceLoader; import org.openide.awt.ActionID; import org.openide.awt.ActionRegistration; import org.openide.nodes.Node; @@ -35,17 +33,11 @@ public final class PasteProvidersNodeAction extends NodeAction { public static final String ID = "demetra.desktop.core.tsproviders.PasteProvidersAction"; - private static void pasteDataSource(DataSource source) { - TsManager.get() - .getProvider(DataSourceLoader.class, source) - .ifPresent(loader -> loader.open(source)); - } - @Override protected void performAction(Node[] activatedNodes) { DataSourceTransferManager.get() .getDataSource(DataTransfers.systemClipboardAsTransferable()) - .ifPresent(PasteProvidersNodeAction::pasteDataSource); + .ifPresent(source -> TsManager.get().open(source)); } @Override diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/ProviderNode.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/ProviderNode.java index 74aff9cf..858e1bf4 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/ProviderNode.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/ProviderNode.java @@ -172,22 +172,22 @@ protected Node createNodeForKey(DataSource key) { } @Override - public void opened(DataSource dataSource) { + public void opened(@NonNull DataSource dataSource) { refresh(true); } @Override - public void closed(DataSource dataSource) { + public void closed(@NonNull DataSource dataSource) { refresh(true); } @Override - public void changed(DataSource dataSource) { + public void changed(@NonNull DataSource dataSource) { refresh(true); } @Override - public void allClosed(String providerName) { + public void allClosed(@NonNull String providerName) { refresh(true); } } diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/ProvidersNode.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/ProvidersNode.java index 323917c8..b5723919 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/ProvidersNode.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/core/tsproviders/ProvidersNode.java @@ -16,6 +16,11 @@ */ package jdplus.toolkit.desktop.plugin.core.tsproviders; +import jdplus.toolkit.base.api.timeseries.TsProvider; +import jdplus.toolkit.base.tsp.DataSource; +import jdplus.toolkit.base.tsp.DataSourceListener; +import jdplus.toolkit.base.tsp.DataSourceLoader; +import jdplus.toolkit.base.tsp.DataSourceProvider; import jdplus.toolkit.desktop.plugin.Config; import jdplus.toolkit.desktop.plugin.DemetraBehaviour; import jdplus.toolkit.desktop.plugin.TsManager; @@ -25,11 +30,7 @@ import jdplus.toolkit.desktop.plugin.interchange.Importable; import jdplus.toolkit.desktop.plugin.nodes.Nodes; import jdplus.toolkit.desktop.plugin.tsproviders.DataSourceProviderBuddyUtil; -import jdplus.toolkit.base.api.timeseries.TsProvider; -import jdplus.toolkit.base.tsp.DataSource; -import jdplus.toolkit.base.tsp.DataSourceListener; -import jdplus.toolkit.base.tsp.DataSourceLoader; -import jdplus.toolkit.base.tsp.DataSourceProvider; +import org.checkerframework.checker.nullness.qual.NonNull; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -172,28 +173,28 @@ public void propertyChange(PropertyChangeEvent evt) { // @Override - public void opened(DataSource dataSource) { + public void opened(@NonNull DataSource dataSource) { if (!DemetraBehaviour.get().isShowTsProviderNodes()) { refresh(true); } } @Override - public void closed(DataSource dataSource) { + public void closed(@NonNull DataSource dataSource) { if (!DemetraBehaviour.get().isShowTsProviderNodes()) { refresh(true); } } @Override - public void changed(DataSource dataSource) { + public void changed(@NonNull DataSource dataSource) { if (!DemetraBehaviour.get().isShowTsProviderNodes()) { refresh(true); } } @Override - public void allClosed(String providerName) { + public void allClosed(@NonNull String providerName) { if (!DemetraBehaviour.get().isShowTsProviderNodes()) { refresh(true); } @@ -230,10 +231,7 @@ public PasteTypeImpl(Transferable t) { @Override public Transferable paste() throws IOException { - DataSourceTransferManager.get() - .getDataSource(t).ifPresent(source -> TsManager.get() - .getProvider(DataSourceLoader.class, source) - .ifPresent(dataSourceLoader -> dataSourceLoader.open(source))); + DataSourceTransferManager.get().getDataSource(t).ifPresent(source -> TsManager.get().open(source)); return null; } } diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/DataTransferManager.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/DataTransferManager.java index 109ba036..9e7f49cb 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/DataTransferManager.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/DataTransferManager.java @@ -24,7 +24,7 @@ import jdplus.toolkit.desktop.plugin.util.LazyGlobalService; import jdplus.toolkit.base.api.timeseries.*; import jdplus.toolkit.base.api.util.Table; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import nbbrd.design.VisibleForTesting; import nbbrd.io.function.IOFunction; import org.checkerframework.checker.nullness.qual.NonNull; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/DataTransferSpi.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/DataTransferSpi.java index f84c8eb1..c9b20c08 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/DataTransferSpi.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/DataTransferSpi.java @@ -20,8 +20,8 @@ import jdplus.toolkit.desktop.plugin.util.NetBeansServiceBackend; import jdplus.toolkit.base.api.timeseries.TsCollection; import jdplus.toolkit.base.api.util.Table; -import ec.util.various.swing.OnAnyThread; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnAnyThread; +import nbbrd.design.swing.OnEDT; import nbbrd.service.Quantifier; import nbbrd.service.ServiceDefinition; import nbbrd.service.ServiceSorter; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/MultiTransferable.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/MultiTransferable.java index cbe61b59..9a16442a 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/MultiTransferable.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/datatransfer/MultiTransferable.java @@ -16,7 +16,7 @@ */ package jdplus.toolkit.desktop.plugin.datatransfer; -import ec.util.various.swing.OnAnyThread; +import nbbrd.design.swing.OnAnyThread; import nbbrd.io.function.IOFunction; import java.awt.datatransfer.DataFlavor; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/descriptors/DateSelectorUI.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/descriptors/DateSelectorUI.java index 450882d7..ff0d78ed 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/descriptors/DateSelectorUI.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/descriptors/DateSelectorUI.java @@ -134,17 +134,17 @@ public void setStart(LocalDate day) { public LocalDate getEnd() { if (core.getD1().equals(LocalDateTime.MAX)){ if (domain != null){ - return domain.getLastPeriod().end().toLocalDate(); + return domain.getLastPeriod().end().toLocalDate().minusDays(1); }else{ return LocalDate.now(Clock.systemDefaultZone()); } } - return core.getD1().toLocalDate(); + return core.getD1().toLocalDate().minusDays(1); } public void setEnd(LocalDate day) { core=core.toBuilder() - .d1(day.atStartOfDay()) + .d1(day.plusDays(1).atStartOfDay()) .build(); callback.accept(core); } @@ -242,7 +242,7 @@ private EnhancedPropertyDescriptor startDesc() { @NbBundle.Messages({ "tsPeriodSelectorUI.endDesc.name=End", - "tsPeriodSelectorUI.endDesc.desc=End of the time span. Only complete periods will be taken into account" + "tsPeriodSelectorUI.endDesc.desc=End of the time span (included). Only complete periods will be taken into account" }) private EnhancedPropertyDescriptor endDesc() { TimeSelector.SelectionType type = core.getType(); diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/Exportable.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/Exportable.java index e36de6b3..51baffd7 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/Exportable.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/Exportable.java @@ -17,7 +17,7 @@ package jdplus.toolkit.desktop.plugin.interchange; import jdplus.toolkit.desktop.plugin.Config; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import org.checkerframework.checker.nullness.qual.NonNull; /** diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/Importable.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/Importable.java index c7b5feae..197a7e80 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/Importable.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/Importable.java @@ -17,7 +17,7 @@ package jdplus.toolkit.desktop.plugin.interchange; import jdplus.toolkit.desktop.plugin.Config; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import org.checkerframework.checker.nullness.qual.NonNull; /** diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/InterchangeSpi.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/InterchangeSpi.java index 5ee6aa67..42bde29a 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/InterchangeSpi.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/interchange/InterchangeSpi.java @@ -18,7 +18,7 @@ import jdplus.toolkit.desktop.plugin.NamedService; import jdplus.toolkit.desktop.plugin.util.NetBeansServiceBackend; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import nbbrd.service.Quantifier; import nbbrd.service.ServiceDefinition; import nbbrd.service.ServiceSorter; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/nodes/FailSafeChildFactory.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/nodes/FailSafeChildFactory.java index 4deef11c..dac6716f 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/nodes/FailSafeChildFactory.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/nodes/FailSafeChildFactory.java @@ -16,8 +16,8 @@ */ package jdplus.toolkit.desktop.plugin.nodes; -import ec.util.various.swing.OnAnyThread; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnAnyThread; +import nbbrd.design.swing.OnEDT; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.openide.nodes.ChildFactory; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/star/StarListManager.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/star/StarListManager.java index 5d0fd77f..9fa8a183 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/star/StarListManager.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/star/StarListManager.java @@ -1,9 +1,9 @@ package jdplus.toolkit.desktop.plugin.star; import jdplus.main.desktop.design.GlobalService; -import jdplus.toolkit.desktop.plugin.util.LazyGlobalService; import jdplus.toolkit.base.tsp.DataSource; -import ec.util.various.swing.OnEDT; +import jdplus.toolkit.desktop.plugin.util.LazyGlobalService; +import nbbrd.design.swing.OnEDT; import org.checkerframework.checker.nullness.qual.NonNull; import java.util.HashSet; @@ -30,16 +30,26 @@ public void clear() { } @OnEDT - public void toggle(DataSource item) { - if (list.contains(item)) - list.remove(item); + public void toggle(DataSource dataSource) { + if (list.contains(dataSource)) + list.remove(dataSource); else - list.add(item); + list.add(dataSource); + } + + @OnEDT + public void add(DataSource dataSource) { + list.add(dataSource); + } + + @OnEDT + public void remove(DataSource dataSource) { + list.remove(dataSource); } @OnEDT @Override - public Iterator iterator() { + public @lombok.NonNull Iterator iterator() { return list.iterator(); } diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/star/StarStep.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/star/StarStep.java deleted file mode 100644 index cb43adcb..00000000 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/star/StarStep.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package jdplus.toolkit.desktop.plugin.star; - -import jdplus.toolkit.desktop.plugin.util.InstallerStep; -import jdplus.toolkit.base.api.timeseries.TsFactory; -import jdplus.toolkit.base.api.timeseries.TsProvider; -import jdplus.toolkit.base.tsp.DataSource; -import jdplus.toolkit.base.tsp.DataSourceLoader; -import nbbrd.io.text.Formatter; -import nbbrd.io.text.Parser; -import org.openide.util.NbPreferences; - -import java.util.Comparator; -import java.util.logging.Level; -import java.util.prefs.BackingStoreException; -import java.util.prefs.Preferences; -import java.util.stream.Stream; - -/** - * @author Philippe Charles - */ -@lombok.extern.java.Log -public class StarStep extends InstallerStep { - - static final String DATASOURCE_PROPERTY = "StarDataSource"; - final Preferences prefs = NbPreferences.forModule(StarStep.class).node("Star"); - - @Override - public void restore() { - StarListManager.get().clear(); - Parser parser = Parser.of(DataSource::parse); - try { - Stream.of(prefs.childrenNames()) - .sorted(Comparator.reverseOrder()) - .forEach(o -> { - Preferences node = prefs.node(o); - String tmp = node.get(DATASOURCE_PROPERTY, null); - if (tmp == null) { - return; - } - java.util.Optional dataSource = parser.parseValue(tmp); - if (dataSource.isPresent()) { - StarListManager.get().toggle(dataSource.orElseThrow()); - } - }); - } catch (BackingStoreException ex) { - log.log(Level.WARNING, "Can't get star items", ex); - } - - for (DataSource o : StarListManager.get()) { - java.util.Optional provider = TsFactory.getDefault().getProvider(o.getProviderName()); - if (provider.isPresent()) { - DataSourceLoader loader = (DataSourceLoader) provider.orElseThrow(); - loader.open(o); - } - } - } - - @Override - public void close() { - // clear the backing store - Formatter formatter = Formatter.of(DataSource::toString); - int i = 0; - for (DataSource o : StarListManager.get()) { - Preferences node = prefs.node(String.valueOf(i++)); - node.put(DATASOURCE_PROPERTY, formatter.formatValueAsString(o).orElseThrow()); - } - try { - prefs.flush(); - } catch (BackingStoreException ex) { - log.log(Level.WARNING, "Can't flush storage", ex); - } - } -} diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/mru/MruProvidersStep.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/mru/MruProvidersStep.java index 45e587bf..6a677bb2 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/mru/MruProvidersStep.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/mru/MruProvidersStep.java @@ -12,6 +12,7 @@ import java.util.prefs.Preferences; import jdplus.toolkit.base.tsp.DataSource; +import org.checkerframework.checker.nullness.qual.NonNull; import org.openide.util.Lookup; import org.openide.util.NbPreferences; @@ -59,22 +60,22 @@ protected void onClose(Lookup.Result lookup) { static class Listener implements DataSourceListener { @Override - public void opened(DataSource dataSource) { + public void opened(@NonNull DataSource dataSource) { TsManager.get() .getProvider(DataSourceProvider.class, dataSource) .ifPresent(provider -> MruList.getProvidersInstance().add(new SourceId(dataSource, provider.getDisplayName(dataSource)))); } @Override - public void closed(DataSource ds) { + public void closed(@NonNull DataSource ds) { } @Override - public void changed(DataSource ds) { + public void changed(@NonNull DataSource ds) { } @Override - public void allClosed(String string) { + public void allClosed(@NonNull String string) { } } } diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/mru/ProviderMruAction.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/mru/ProviderMruAction.java index 2b346d0d..1887dd61 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/mru/ProviderMruAction.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/mru/ProviderMruAction.java @@ -16,10 +16,11 @@ */ package jdplus.toolkit.desktop.plugin.ui.mru; -import jdplus.toolkit.desktop.plugin.TsManager; -import jdplus.toolkit.desktop.plugin.tsproviders.DataSourceManager; import jdplus.toolkit.base.tsp.DataSource; import jdplus.toolkit.base.tsp.DataSourceLoader; +import jdplus.toolkit.desktop.plugin.TsManager; +import jdplus.toolkit.desktop.plugin.tsproviders.DataSourceManager; +import lombok.NonNull; import org.openide.awt.*; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.Presenter; @@ -114,19 +115,14 @@ boolean isLoadable(DataSource dataSource) { } } + @lombok.RequiredArgsConstructor private static final class OpenDataSource extends AbstractAction { - private final DataSource dataSource; - - public OpenDataSource(DataSource DataSource) { - this.dataSource = DataSource; - } + private final @NonNull DataSource dataSource; @Override public void actionPerformed(ActionEvent e) { - TsManager.get() - .getProvider(DataSourceLoader.class, dataSource) - .ifPresent(o -> o.open(dataSource)); + TsManager.get().open(dataSource); } } } diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/processing/DefaultProcessingViewer.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/processing/DefaultProcessingViewer.java index f06442f4..48fb861f 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/processing/DefaultProcessingViewer.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/ui/processing/DefaultProcessingViewer.java @@ -237,8 +237,11 @@ private void initApplySpecView() { @Override public void actionPerformed(ActionEvent e) { S pspec = specDescriptor.getCore(); + S ospec = doc.getSpecification(); doc.set(pspec); updateButtons(BUTTON_APPLY); + dirty = false; + DefaultProcessingViewer.this.firePropertyChange(SPEC_CHANGED, ospec, pspec); updateResults(); } }}; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/Caches.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/Caches.java deleted file mode 100644 index 872ab8f7..00000000 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/Caches.java +++ /dev/null @@ -1,34 +0,0 @@ -package jdplus.toolkit.desktop.plugin.util; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import java.time.Duration; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; -import org.checkerframework.checker.nullness.qual.NonNull; - -@lombok.experimental.UtilityClass -public class Caches { - - @NonNull - public static Cache ttlCache(@NonNull Duration duration) { - return CacheBuilder.newBuilder() - .expireAfterWrite(duration.toNanos(), TimeUnit.NANOSECONDS) - .build(); - } - - @NonNull - public static ConcurrentMap ttlCacheAsMap(@NonNull Duration duration) { - return Caches.ttlCache(duration).asMap(); - } - - @NonNull - public static Cache softValuesCache() { - return CacheBuilder.newBuilder().softValues().build(); - } - - @NonNull - public static ConcurrentMap softValuesCacheAsMap() { - return Caches.softValuesCache().asMap(); - } -} diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/FontAwesomeUtils.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/FontAwesomeUtils.java index 50f9de17..3c3d81b8 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/FontAwesomeUtils.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/FontAwesomeUtils.java @@ -17,7 +17,7 @@ package jdplus.toolkit.desktop.plugin.util; import ec.util.various.swing.FontAwesome; -import ec.util.various.swing.OnEDT; +import nbbrd.design.swing.OnEDT; import org.checkerframework.checker.nullness.qual.NonNull; import javax.swing.*; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/Installer.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/Installer.java index d74b0e32..6ff9fb1d 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/Installer.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/Installer.java @@ -20,7 +20,7 @@ import jdplus.toolkit.desktop.plugin.DemetraUI; import jdplus.toolkit.desktop.plugin.Persistable; import jdplus.toolkit.desktop.plugin.TsManager; -import jdplus.toolkit.desktop.plugin.star.StarStep; +import jdplus.toolkit.desktop.plugin.core.star.StarStep; import jdplus.toolkit.desktop.plugin.tsproviders.DataSourceProviderBuddy; import jdplus.toolkit.desktop.plugin.ui.mru.MruProvidersStep; import jdplus.toolkit.desktop.plugin.ui.mru.MruWorkspacesStep; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/KeyStrokes.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/KeyStrokes.java index e6e07823..ebf0ca0d 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/KeyStrokes.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/KeyStrokes.java @@ -1,23 +1,21 @@ /* * Copyright 2013 National Bank of Belgium * - * Licensed under the EUPL, Version 1.1 or – as soon they will be approved + * Licensed under the EUPL, Version 1.1 or – as soon they will be approved * by the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * - * Unless required by applicable law or agreed to in writing, software + * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and + * See the Licence for the specific language governing permissions and * limitations under the Licence. */ package jdplus.toolkit.desktop.plugin.util; -import jdplus.toolkit.base.api.util.List2; - import javax.swing.*; import javax.swing.text.DefaultEditorKit; import java.awt.*; @@ -27,7 +25,6 @@ import java.util.function.Supplier; /** - * * @author Philippe Charles */ public final class KeyStrokes { @@ -101,7 +98,7 @@ public Map> get() { .map(Map.Entry::getKey) .distinct() .sorted(orderingUsingKeyTextLength()) - .collect(List2.toUnmodifiableList()); + .toList(); result.put(o, !tmp.isEmpty() ? tmp : Collections.singletonList(getFallback(o))); } return result; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/Stopwatch.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/Stopwatch.java new file mode 100644 index 00000000..cfe21abb --- /dev/null +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/util/Stopwatch.java @@ -0,0 +1,99 @@ +package jdplus.toolkit.desktop.plugin.util; + +import lombok.AccessLevel; +import lombok.NonNull; +import nbbrd.design.MightBePromoted; +import nbbrd.design.StaticFactoryMethod; + +import java.util.Locale; +import java.util.concurrent.TimeUnit; +import java.util.function.LongSupplier; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +@lombok.RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public final class Stopwatch { + + private final LongSupplier ticker = System::nanoTime; + private boolean isRunning = false; + private long elapsedNanos = 0; + private long startTick = 0; + + @StaticFactoryMethod + public static @NonNull Stopwatch createStarted() { + return new Stopwatch().start(); + } + + public boolean isRunning() { + return isRunning; + } + + public @NonNull Stopwatch reset() { + isRunning = false; + elapsedNanos = 0L; + return this; + } + + public @NonNull Stopwatch start() { + if (isRunning) { + throw new IllegalStateException("This stopwatch is already running."); + } + isRunning = true; + startTick = ticker.getAsLong(); + return this; + } + + public @NonNull Stopwatch stop() { + if (!isRunning) { + throw new IllegalStateException("This stopwatch is already stopped."); + } + isRunning = false; + elapsedNanos += ticker.getAsLong() - startTick; + return this; + } + + public long elapsed(@NonNull TimeUnit timeUnit) { + return timeUnit.convert(elapsedNanos(), TimeUnit.NANOSECONDS); + } + + @Override + public String toString() { + long nanos = elapsedNanos(); + TimeUnit unit = chooseUnit(nanos); + double value = (double) nanos / (double) TimeUnit.NANOSECONDS.convert(1L, unit); + return formatCompact4Digits(value) + " " + abbreviate(unit); + } + + private long elapsedNanos() { + return isRunning ? ticker.getAsLong() - startTick + elapsedNanos : elapsedNanos; + } + + private static TimeUnit chooseUnit(long nanos) { + return reverseStream(TimeUnit.values()) + .filter(unit -> unit.convert(nanos, TimeUnit.NANOSECONDS) > 0L) + .findFirst() + .orElse(TimeUnit.NANOSECONDS); + } + + private static String abbreviate(TimeUnit unit) { + return switch (unit) { + case NANOSECONDS -> "ns"; + case MICROSECONDS -> "μs"; + case MILLISECONDS -> "ms"; + case SECONDS -> "s"; + case MINUTES -> "min"; + case HOURS -> "h"; + case DAYS -> "d"; + }; + } + + private static String formatCompact4Digits(double value) { + return String.format(Locale.ROOT, "%.4g", value); + } + + @MightBePromoted + private static Stream reverseStream(T[] array) { + return IntStream.rangeClosed(1, array.length) + .mapToObj(i -> array[array.length - i]); + } +} \ No newline at end of file diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/WorkspaceItem.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/WorkspaceItem.java index efad7291..24a76655 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/WorkspaceItem.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/WorkspaceItem.java @@ -145,10 +145,6 @@ public Status getStatus() { return status_; } - void setStatus(Status status) { - status_ = status; - } - public T getElement() { load(); return element_; @@ -199,6 +195,13 @@ public boolean close(DemetraVersion version) { } } + public boolean save(DemetraVersion version) { + if (!status_.canBeSaved()) { + return false; + } + return owner_.getRepository().saveItem(this, version); + } + public boolean reload() { if (!status_.hasStorage()) { return false; diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/nodes/SaveAction.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/nodes/SaveAction.java new file mode 100644 index 00000000..af35fd6e --- /dev/null +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/nodes/SaveAction.java @@ -0,0 +1,73 @@ +/* + * Copyright 2013 National Bank of Belgium + * + * Licensed under the EUPL, Version 1.1 or – as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * http://ec.europa.eu/idabc/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ +package jdplus.toolkit.desktop.plugin.workspace.nodes; + +import jdplus.toolkit.base.api.DemetraVersion; +import jdplus.toolkit.desktop.plugin.nodes.SingleNodeAction; +import jdplus.toolkit.desktop.plugin.workspace.WorkspaceFactory; +import jdplus.toolkit.desktop.plugin.workspace.WorkspaceItem; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; +import org.openide.awt.ActionID; +import org.openide.awt.ActionRegistration; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle.Messages; + +@ActionID(category = "Edit", + id = "demetra.desktop.workspace.nodes.SaveAction") +@ActionRegistration( + displayName = "#CTL_SaveAction", lazy = false) +@Messages("CTL_SaveAction=Save") +public final class SaveAction extends SingleNodeAction { + + public static final String SAVE_MESSAGE = "Are you sure you want to save this item?"; + + public SaveAction() { + super(ItemWsNode.class); + } + + @Override + protected void performAction(ItemWsNode context) { + WorkspaceItem cur = context.getItem(); + if (cur != null && !cur.isReadOnly()) { + NotifyDescriptor nd = new NotifyDescriptor.Confirmation(SAVE_MESSAGE, NotifyDescriptor.OK_CANCEL_OPTION); + if (DialogDisplayer.getDefault().notify(nd) != NotifyDescriptor.OK_OPTION) { + return; + } + if (cur.save(DemetraVersion.JD3)) { + WorkspaceFactory.Event ev = new WorkspaceFactory.Event(cur.getOwner(), cur.getId(), WorkspaceFactory.Event.SAVE); + WorkspaceFactory.getInstance().notifyEvent(ev); + } + } + } + + @Override + protected boolean enable(ItemWsNode context) { + WorkspaceItem cur = context.getItem(); + return cur != null && !cur.isReadOnly(); + } + + @Override + public String getName() { + return Bundle.CTL_SaveAction(); + } + + @Override + public HelpCtx getHelpCtx() { + return null; + } +} diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/ui/WorkspaceTsTopComponent.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/ui/WorkspaceTsTopComponent.java index 8f87c8f2..9d7b4d4c 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/ui/WorkspaceTsTopComponent.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/java/jdplus/toolkit/desktop/plugin/workspace/ui/WorkspaceTsTopComponent.java @@ -33,7 +33,7 @@ public abstract class WorkspaceTsTopComponent> extend protected WorkspaceTsTopComponent(WorkspaceItem doc) { super(doc); } - + protected abstract TsProcessingViewer initViewer(); public void updateUserInterfaceContext() { @@ -72,27 +72,28 @@ public void refresh() { @Override public void componentOpened() { super.componentOpened(); - panel=initViewer(); + WorkspaceItem d = getDocument(); + TsDynamicProvider.onDocumentOpened(d.getElement()); + panel = initViewer(); add(panel); panel.refreshHeader(); - WorkspaceItem d = getDocument(); panel.addPropertyChangeListener((PropertyChangeEvent arg0) -> { switch (arg0.getPropertyName()) { case DefaultProcessingViewer.INPUT_CHANGED -> { - Object nval=arg0.getNewValue(); - if (nval instanceof Ts ts){ + Object nval = arg0.getNewValue(); + if (nval instanceof Ts ts) { setTs(ts); } } case DefaultProcessingViewer.SPEC_CHANGED -> { WorkspaceFactory.Event ev = new WorkspaceFactory.Event(d.getOwner(), d.getId(), WorkspaceFactory.Event.ITEMCHANGED, WorkspaceTsTopComponent.this); WorkspaceFactory.getInstance().notifyEvent(ev); + d.setDirty(); } - + } }); - TsDynamicProvider.onDocumentOpened(panel.getDocument()); // TODO add custom code on component opening } @@ -107,7 +108,7 @@ public void componentClosed() { } @Override - public boolean hasContextMenu(){ + public boolean hasContextMenu() { return true; } @@ -128,7 +129,7 @@ public void setTs(Ts ts) { if (TsManager.isDynamic(ts)) { cts = ts.freeze(); } else { - cts = ts.load(TsInformationType.All, TsManager.get()); + cts = ts.load(TsInformationType.All, TsManager.get()).freeze(); } panel.getDocument().set(cts); panel.updateButtons(null); diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/resources/jdplus/toolkit/desktop/plugin/layer.xml b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/resources/jdplus/toolkit/desktop/plugin/layer.xml index c50418b0..1cf4211a 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/resources/jdplus/toolkit/desktop/plugin/layer.xml +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/resources/jdplus/toolkit/desktop/plugin/layer.xml @@ -24,5 +24,10 @@ + + + + + diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/resources/jdplus/toolkit/desktop/plugin/layout/tsnavigatorWsmode.xml b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/resources/jdplus/toolkit/desktop/plugin/layout/tsnavigatorWsmode.xml new file mode 100644 index 00000000..d65f9683 --- /dev/null +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/main/resources/jdplus/toolkit/desktop/plugin/layout/tsnavigatorWsmode.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/test/java/jdplus/toolkit/desktop/plugin/ToolkitRuntimeDependenciesTest.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/test/java/jdplus/toolkit/desktop/plugin/ToolkitRuntimeDependenciesTest.java index b0add7a7..c72fb94e 100644 --- a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/test/java/jdplus/toolkit/desktop/plugin/ToolkitRuntimeDependenciesTest.java +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/test/java/jdplus/toolkit/desktop/plugin/ToolkitRuntimeDependenciesTest.java @@ -25,8 +25,7 @@ public void test() throws IOException { .satisfies(ToolkitRuntimeDependenciesTest::checkJavaIoUtil) .satisfies(ToolkitRuntimeDependenciesTest::checkJavaDesktopUtil) .satisfies(ToolkitRuntimeDependenciesTest::checkExternalSwingComponents) - .satisfies(ToolkitRuntimeDependenciesTest::checkGuava) - .hasSize(35); + .hasSize(32); } private static void checkToolkit(List coordinates) { @@ -35,6 +34,9 @@ private static void checkToolkit(List coordinates) { .extracting(GAV::getArtifactId) .are(matchingPattern(compile("^jdplus-toolkit-base-\\w+$"))) .hasSize(6); + assertThatGroupId(coordinates, "com.github.ben-manes.caffeine") + .extracting(GAV::getArtifactId) + .containsExactlyInAnyOrder("caffeine"); } private static void checkJavaIoUtil(List coordinates) { @@ -89,7 +91,7 @@ private static void checkJavaDesktopUtil(List coordinates) { private static void checkExternalSwingComponents(List coordinates) { assertThatGroupId(coordinates, "com.miglayout") .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("miglayout"); + .containsExactlyInAnyOrder("miglayout-swing", "miglayout-core"); assertThatGroupId(coordinates, "org.tros") .extracting(GAV::getArtifactId) @@ -104,21 +106,6 @@ private static void checkExternalSwingComponents(List coordinates .containsExactlyInAnyOrder("swing-layout"); } - // FIXME: remove Guava dependency - private static void checkGuava(List coordinates) { - assertThatGroupId(coordinates, "com.google.guava") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("guava", "failureaccess", "listenablefuture"); - - assertThatGroupId(coordinates, "com.google.errorprone") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("error_prone_annotations"); - - assertThatGroupId(coordinates, "com.google.j2objc") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("j2objc-annotations"); - } - @MightBePromoted private static ListAssert assertThatGroupId(List coordinates, String groupId) { return assertThat(coordinates) diff --git a/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/test/java/jdplus/toolkit/desktop/plugin/core/star/StarStepTest.java b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/test/java/jdplus/toolkit/desktop/plugin/core/star/StarStepTest.java new file mode 100644 index 00000000..39a2f171 --- /dev/null +++ b/jdplus-main-desktop/jdplus-toolkit-desktop-plugin/src/test/java/jdplus/toolkit/desktop/plugin/core/star/StarStepTest.java @@ -0,0 +1,102 @@ +package jdplus.toolkit.desktop.plugin.core.star; + +import jdplus.toolkit.base.tsp.DataSource; +import nbbrd.design.MightBePromoted; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.prefs.AbstractPreferences; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; + +import static java.util.Collections.emptyList; +import static org.assertj.core.api.Assertions.assertThat; + +public class StarStepTest { + + @Test + public void testGetPathNameSupplier() { + Supplier pathNameSupplier = StarStep.getPathNameSupplier(); + assertThat(pathNameSupplier.get()).isEqualTo("0"); + assertThat(pathNameSupplier.get()).isEqualTo("1"); + assertThat(pathNameSupplier.get()).isEqualTo("2"); + } + + @Test + public void testLoadStore() { + Preferences prefs = new MockedPreferences(null, ""); + + assertThat(StarStep.loadSources(prefs)) + .isEmpty(); + + List dataSources = List.of(DataSource.of("p1", "v1"), DataSource.of("p2", "v1")); + + StarStep.storeSources(prefs, dataSources); + assertThat(StarStep.loadSources(prefs)) + .containsExactlyElementsOf(dataSources); + + StarStep.storeSources(prefs, emptyList()); + assertThat(StarStep.loadSources(prefs)) + .isEmpty(); + } + + @MightBePromoted + private static final class MockedPreferences extends AbstractPreferences { + + private final Map data = new HashMap<>(); + private final Map children = new HashMap<>(); + + public MockedPreferences(MockedPreferences parent, String name) { + super(parent, name); + } + + @Override + protected void putSpi(String key, String value) { + data.put(key, value); + } + + @Override + protected String getSpi(String key) { + return data.get(key); + } + + @Override + protected void removeSpi(String key) { + data.remove(key); + } + + @Override + protected void removeNodeSpi() throws BackingStoreException { + Preferences parent = parent(); + if (parent instanceof MockedPreferences) { + ((MockedPreferences) parent).children.remove(name()); + } + } + + @Override + protected String[] keysSpi() throws BackingStoreException { + return data.keySet().toArray(String[]::new); + } + + @Override + protected String[] childrenNamesSpi() throws BackingStoreException { + return children.keySet().toArray(String[]::new); + } + + @Override + protected AbstractPreferences childSpi(String name) { + return children.computeIfAbsent(name, x -> new MockedPreferences(this, x)); + } + + @Override + protected void syncSpi() throws BackingStoreException { + } + + @Override + protected void flushSpi() throws BackingStoreException { + } + } +} diff --git a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/pom.xml b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/pom.xml index d004c070..5db71c22 100644 --- a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/pom.xml +++ b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-desktop - 3.0.2 + 3.1.0 jdplus-tramoseats-desktop-plugin diff --git a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/anomalydetection/ui/CheckLastTopComponent.java b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/anomalydetection/ui/CheckLastTopComponent.java index a7859caf..6492f066 100644 --- a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/anomalydetection/ui/CheckLastTopComponent.java +++ b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/anomalydetection/ui/CheckLastTopComponent.java @@ -16,7 +16,7 @@ */ package jdplus.tramoseats.desktop.plugin.anomalydetection.ui; -import com.google.common.base.Stopwatch; +import jdplus.toolkit.desktop.plugin.util.Stopwatch; import jdplus.toolkit.desktop.plugin.DemetraBehaviour; import jdplus.toolkit.desktop.plugin.DemetraIcons; import jdplus.tramoseats.desktop.plugin.anomalydetection.AnomalyItem; diff --git a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/anomalydetection/ui/OutliersTopComponent.java b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/anomalydetection/ui/OutliersTopComponent.java index f40f1b40..e0b08c72 100644 --- a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/anomalydetection/ui/OutliersTopComponent.java +++ b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/anomalydetection/ui/OutliersTopComponent.java @@ -16,7 +16,7 @@ */ package jdplus.tramoseats.desktop.plugin.anomalydetection.ui; -import com.google.common.base.Stopwatch; +import jdplus.toolkit.desktop.plugin.util.Stopwatch; import jdplus.toolkit.desktop.plugin.notification.MessageType; import jdplus.toolkit.desktop.plugin.notification.NotifyUtil; import jdplus.toolkit.desktop.plugin.DemetraIcons; diff --git a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramo/descriptors/BasicSpecUI.java b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramo/descriptors/BasicSpecUI.java index 27a58f21..900079b4 100644 --- a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramo/descriptors/BasicSpecUI.java +++ b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramo/descriptors/BasicSpecUI.java @@ -26,7 +26,7 @@ public BasicSpecUI(TramoSpecRoot root) { } public DateSelectorUI getSpan() { - return new DateSelectorUI(core() .getTransform().getSpan(), UserInterfaceContext.INSTANCE.getDomain(), isRo(), selector->updateSpan(selector)); + return new DateSelectorUI(core().getTransform().getSpan(), UserInterfaceContext.INSTANCE.getDomain(), isRo(), selector->updateSpan(selector)); } public void updateSpan(TimeSelector span){ diff --git a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramo/documents/TramoDocFileRepository.java b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramo/documents/TramoDocFileRepository.java index 90facfeb..a17bda17 100644 --- a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramo/documents/TramoDocFileRepository.java +++ b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramo/documents/TramoDocFileRepository.java @@ -27,6 +27,7 @@ public final class TramoDocFileRepository extends AbstractFileItemRepository< Tr @Override public boolean load(WorkspaceItem item) { return loadFile(item, (TramoDocument o) -> { + o.setLocked(true); item.setElement(o); item.resetDirty(); }); diff --git a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/documents/TramoSeatsDocFileRepository.java b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/documents/TramoSeatsDocFileRepository.java index 22508601..f9272866 100644 --- a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/documents/TramoSeatsDocFileRepository.java +++ b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/documents/TramoSeatsDocFileRepository.java @@ -27,6 +27,7 @@ public final class TramoSeatsDocFileRepository extends AbstractFileItemRepositor @Override public boolean load(WorkspaceItem item) { return loadFile(item, (TramoSeatsDocument o) -> { + o.setLocked(true); item.setElement(o); item.resetDirty(); }); diff --git a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/JTramoSeatsSummary.java b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/JTramoSeatsSummary.java index c19fb8d0..a80f9b0b 100644 --- a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/JTramoSeatsSummary.java +++ b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/JTramoSeatsSummary.java @@ -98,7 +98,8 @@ public JTramoSeatsSummary() { public void set(TramoSeatsDocument doc) { doc_ = doc; - + chart_.setTsCollection(TsCollection.EMPTY); + siPanel_.reset(); if (doc_ == null || doc_.getResult() == null) { return; } @@ -114,17 +115,14 @@ public void set(TramoSeatsDocument doc) { Disposables.disposeAndRemoveAll(document_).add(TsViewToolkit.getHtmlViewer(document)); String[] lowSeries = lowSeries(); - chart_.setTsCollection( - Arrays.stream(lowSeries).map(s->getMainSeries(s)).collect(TsCollection.toTsCollection()) - ); + TsCollection ncoll = Arrays.stream(lowSeries).map(s->getMainSeries(s)).collect(TsCollection.toTsCollection()); + chart_.setTsCollection(ncoll); if (seats != null) { TsData seas = doc_.getResult().getData(Dictionary.concatenate(SaDictionaries.DECOMPOSITION, SaDictionaries.S_CMP), TsData.class); TsData irr = doc_.getResult().getData(Dictionary.concatenate(SaDictionaries.DECOMPOSITION, SaDictionaries.I_CMP), TsData.class); siPanel_.setData(seas, irr, doc_.getResult().getFinals().getMode()); - } else { - siPanel_.reset(); - } + } } private Ts getMainSeries(String str) { diff --git a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/TramoSeatsUIFactory.java b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/TramoSeatsUIFactory.java index db18cb72..5764e985 100644 --- a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/TramoSeatsUIFactory.java +++ b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/TramoSeatsUIFactory.java @@ -12,6 +12,7 @@ import jdplus.tramoseats.base.api.tramoseats.TramoSeatsSpec; import java.awt.Color; import javax.swing.Icon; +import javax.swing.SwingUtilities; import jdplus.tramoseats.base.core.tramoseats.TramoSeatsDocument; import org.openide.util.ImageUtilities; import org.openide.util.lookup.ServiceProvider; diff --git a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/TramoSeatsViewFactory.java b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/TramoSeatsViewFactory.java index 1cbeaf9e..c586455f 100644 --- a/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/TramoSeatsViewFactory.java +++ b/jdplus-main-desktop/jdplus-tramoseats-desktop-plugin/src/main/java/jdplus/tramoseats/desktop/plugin/tramoseats/ui/TramoSeatsViewFactory.java @@ -471,14 +471,14 @@ public static class PreprocessingDetFactory extends ProcDocumentItemFactory source, new GenericTableUI(false, - SaDictionaries.PREPROCESSING, ModellingDictionary.YCAL, - SaDictionaries.PREPROCESSING, ModellingDictionary.Y_LIN, - SaDictionaries.PREPROCESSING, ModellingDictionary.DET, - SaDictionaries.PREPROCESSING, ModellingDictionary.CAL, - SaDictionaries.PREPROCESSING, ModellingDictionary.TDE, - SaDictionaries.PREPROCESSING, ModellingDictionary.EE, - SaDictionaries.PREPROCESSING, ModellingDictionary.OUT, - SaDictionaries.PREPROCESSING, ModellingDictionary.FULL_RES)); + ModellingDictionary.YCAL, + ModellingDictionary.Y_LIN, + ModellingDictionary.DET, + ModellingDictionary.CAL, + ModellingDictionary.TDE, + ModellingDictionary.EE, + ModellingDictionary.OUT, + ModellingDictionary.FULL_RES)); } @Override diff --git a/jdplus-main-desktop/jdplus-x13-desktop-plugin/pom.xml b/jdplus-main-desktop/jdplus-x13-desktop-plugin/pom.xml index f24e32d6..8c20da08 100644 --- a/jdplus-main-desktop/jdplus-x13-desktop-plugin/pom.xml +++ b/jdplus-main-desktop/jdplus-x13-desktop-plugin/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main-desktop - 3.0.2 + 3.1.0 jdplus-x13-desktop-plugin diff --git a/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/regarima/documents/RegArimaDocFileRepository.java b/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/regarima/documents/RegArimaDocFileRepository.java index d1b911ae..f20d4d57 100644 --- a/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/regarima/documents/RegArimaDocFileRepository.java +++ b/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/regarima/documents/RegArimaDocFileRepository.java @@ -27,6 +27,7 @@ public final class RegArimaDocFileRepository extends AbstractFileItemRepository< @Override public boolean load(WorkspaceItem item) { return loadFile(item, (RegArimaDocument o) -> { + o.setLocked(true); item.setElement(o); item.resetDirty(); }); diff --git a/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/x13/documents/X13DocFileRepository.java b/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/x13/documents/X13DocFileRepository.java index ab292e78..fe7c47f2 100644 --- a/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/x13/documents/X13DocFileRepository.java +++ b/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/x13/documents/X13DocFileRepository.java @@ -27,6 +27,7 @@ public final class X13DocFileRepository extends AbstractFileItemRepository< X13D @Override public boolean load(WorkspaceItem item) { return loadFile(item, (X13Document o) -> { + o.setLocked(true); item.setElement(o); item.resetDirty(); }); diff --git a/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/x13/ui/X13ViewFactory.java b/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/x13/ui/X13ViewFactory.java index 5d1b47a0..86e233ed 100644 --- a/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/x13/ui/X13ViewFactory.java +++ b/jdplus-main-desktop/jdplus-x13-desktop-plugin/src/main/java/jdplus/x13/desktop/plugin/x13/ui/X13ViewFactory.java @@ -42,7 +42,6 @@ import jdplus.toolkit.base.api.information.Explorable; import jdplus.toolkit.base.api.information.InformationSet; import jdplus.toolkit.base.api.modelling.ModellingDictionary; -import jdplus.toolkit.base.api.modelling.SeriesInfo; import jdplus.toolkit.base.api.processing.ProcDiagnostic; import jdplus.toolkit.desktop.plugin.html.core.HtmlInformationSet; import jdplus.toolkit.desktop.plugin.html.modelling.HtmlRegSarima; @@ -81,7 +80,6 @@ import jdplus.toolkit.base.core.timeseries.simplets.analysis.MovingProcessing; import jdplus.toolkit.base.core.timeseries.simplets.analysis.RevisionHistory; import jdplus.toolkit.base.core.timeseries.simplets.analysis.SlidingSpans; -import jdplus.x13.base.api.x11.X11Spec; import jdplus.x13.base.core.x11.X11Results; import jdplus.x13.base.core.x13.X13Document; import jdplus.x13.base.core.x13.X13Factory; @@ -465,14 +463,14 @@ public PreprocessingDetFactory() { super(X13Document.class, SaViews.PREPROCESSING_DET, source -> source.getResult().getPreprocessing() == null ? null : source, new GenericTableUI(false, - SaDictionaries.PREPROCESSING, ModellingDictionary.YCAL, - SaDictionaries.PREPROCESSING, ModellingDictionary.Y_LIN, - SaDictionaries.PREPROCESSING, ModellingDictionary.DET, - SaDictionaries.PREPROCESSING, ModellingDictionary.CAL, - SaDictionaries.PREPROCESSING, ModellingDictionary.TDE, - SaDictionaries.PREPROCESSING, ModellingDictionary.EE, - SaDictionaries.PREPROCESSING, ModellingDictionary.OUT, - SaDictionaries.PREPROCESSING, ModellingDictionary.FULL_RES)); + ModellingDictionary.YCAL, + ModellingDictionary.Y_LIN, + ModellingDictionary.DET, + ModellingDictionary.CAL, + ModellingDictionary.TDE, + ModellingDictionary.EE, + ModellingDictionary.OUT, + ModellingDictionary.FULL_RES)); } @Override diff --git a/jdplus-main-desktop/pom.xml b/jdplus-main-desktop/pom.xml index 23ad349e..a5660811 100644 --- a/jdplus-main-desktop/pom.xml +++ b/jdplus-main-desktop/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main - 3.0.2 + 3.1.0 jdplus-main-desktop @@ -21,7 +21,7 @@ nbdemetra - RELEASE180 + RELEASE190 diff --git a/pom.xml b/pom.xml index 9735a08a..f22ff70f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.sat jdplus-main - 3.0.2 + 3.1.0 pom ${project.artifactId} @@ -48,21 +48,21 @@ ${project.artifactId} - 1.18.28 - 1.6.1 + 1.18.30 + 1.7.0 1.4.0 - 3.33.0 + 3.39.0 - 5.9.2 + 5.10.0 3.24.2 2.2.4 - 3.21.12 - 0.0.23 + 3.24.4 + 0.0.26 1.0.3 - 2.5.2 + 2.5.7 @@ -127,7 +127,7 @@ org.apache.maven.plugins maven-clean-plugin - 3.2.0 + 3.3.1 org.apache.maven.plugins @@ -165,10 +165,15 @@ 3.1.2 + + org.apache.maven.plugins + maven-dependency-plugin + 3.6.0 + org.apache.maven.plugins maven-enforcer-plugin - 3.3.0 + 3.4.1 org.gaul @@ -178,12 +183,12 @@ de.thetaphi forbiddenapis - 3.5.1 + 3.6 com.github.nbbrd.heylogs heylogs-maven-plugin - 0.5.0 + 0.7.0 org.xolstice.maven.plugins @@ -203,7 +208,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.5.0 + 3.6.0 org.simplify4u.plugins @@ -215,11 +220,6 @@ nexus-staging-maven-plugin 1.6.13 - - org.apache.maven.plugins - maven-dependency-plugin - 3.6.0 - org.apache.maven.plugins maven-assembly-plugin @@ -317,7 +317,7 @@ org.codehaus.mojo extra-enforcer-rules - 1.6.2 + 1.7.0 org.kordamp.maven @@ -339,9 +339,7 @@ 3.6.0 - - true - + project.artifactId @@ -566,17 +564,4 @@ - - - - jdemetra-snapshots - https://oss.sonatype.org/content/repositories/snapshots/ - - false - - - true - - -