diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1ee2e3b..1ab9369 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-ea-maven.yml b/.github/workflows/java-ea-maven.yml index 6ec751a..7906c03 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 f1197e5..411b138 100644 --- a/.github/workflows/java-maven.yml +++ b/.github/workflows/java-maven.yml @@ -1,10 +1,10 @@ -name: Java with Maven +name: Java8+ with Maven 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, 'nbbrd/') && 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, 'nbbrd/') && 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 77764be..613257d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,29 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [3.1.0] - 2023-10-16 + +This is a feature release of SDMX extensions for JDemetra+ v3. +[JDemetra+ v3.1.1 or later](https://github.com/jdemetra/jdplus-main) version is required to run it. + +### Added + +- Allow configuration by environment variables + +### Fixed + +- Fix favicons transparency, cache and loading +- Fix dimensions and attributes autocompletion + +### Changed + +- Bump sdmx-dl from 3.0.0-beta.11 to [3.0.0-beta.12](https://github.com/nbbrd/sdmx-dl/releases/tag/v3.0.0-beta.12) + ## [3.0.0] - 2023-06-14 This is the **initial release** of SDMX extensions for JDemetra+ v3. [JDemetra+ v3.0.2 or later](https://github.com/jdemetra/jdplus-main) version is required to run it. -[Unreleased]: https://github.com/nbbrd/jdplus-sdmx/compare/v3.0.0...HEAD +[Unreleased]: https://github.com/nbbrd/jdplus-sdmx/compare/v3.1.0...HEAD +[3.1.0]: https://github.com/nbbrd/jdplus-sdmx/compare/v3.0.0...v3.1.0 [3.0.0]: https://github.com/nbbrd/jdplus-sdmx/releases/tag/v3.0.0 diff --git a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/pom.xml b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/pom.xml index 92daf5e..79866ac 100644 --- a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/pom.xml +++ b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/pom.xml @@ -7,7 +7,7 @@ com.github.nbbrd.jdplus-sdmx jdplus-sdmx-base-parent - 3.0.0 + 3.1.0 jdplus-sdmx-base-api diff --git a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxCubeConnection.java b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxCubeConnection.java index 246a322..b957c05 100644 --- a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxCubeConnection.java +++ b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxCubeConnection.java @@ -25,6 +25,7 @@ import jdplus.toolkit.base.tsp.cube.CubeId; import jdplus.toolkit.base.tsp.cube.CubeSeries; import jdplus.toolkit.base.tsp.cube.CubeSeriesWithData; +import lombok.NonNull; import nbbrd.design.VisibleForTesting; import sdmxdl.*; import sdmxdl.ext.SdmxCubeUtil; @@ -45,22 +46,23 @@ @lombok.RequiredArgsConstructor public final class SdmxCubeConnection implements CubeConnection { - public static SdmxCubeConnection of(Connection connection, DataflowRef ref, List dimensions, String labelAttribute, String sourceLabel) throws IOException { - Dataflow flow = connection.getFlow(ref); - DataStructure dsd = connection.getStructure(ref); + public static SdmxCubeConnection of(Connection connection, FlowRef ref, List dimensions, String labelAttribute, String sourceLabel, boolean displayCodes) throws IOException { + Flow flow = connection.getFlow(ref); + Structure dsd = connection.getStructure(ref); CubeId root = getOrLoadRoot(dimensions, dsd); - return new SdmxCubeConnection(connection, flow, dsd, root, labelAttribute, sourceLabel); + return new SdmxCubeConnection(connection, flow, dsd, root, labelAttribute, sourceLabel, displayCodes); } private final Connection connection; - private final Dataflow flow; - private final DataStructure dsd; + private final Flow flow; + private final Structure dsd; private final CubeId root; private final String labelAttribute; private final String sourceLabel; + private final boolean displayCodes; @Override - public Optional testConnection() { + public @NonNull Optional testConnection() { try { connection.testConnection(); return Optional.empty(); @@ -70,12 +72,12 @@ public Optional testConnection() { } @Override - public CubeId getRoot() { + public @NonNull CubeId getRoot() { return root; } @Override - public Stream getAllSeries(CubeId ref) throws IOException { + public @NonNull Stream getAllSeries(@NonNull CubeId ref) throws IOException { KeyConverter converter = KeyConverter.of(dsd, ref); return SdmxCubeUtil .getAllSeries(connection, flow.getRef(), converter.toKey(ref)) @@ -83,7 +85,7 @@ public Stream getAllSeries(CubeId ref) throws IOException { } @Override - public Stream getAllSeriesWithData(CubeId ref) throws IOException { + public @NonNull Stream getAllSeriesWithData(@NonNull CubeId ref) throws IOException { KeyConverter converter = KeyConverter.of(dsd, ref); return SdmxCubeUtil .getAllSeriesWithData(connection, flow.getRef(), converter.toKey(ref)) @@ -91,7 +93,7 @@ public Stream getAllSeriesWithData(CubeId ref) throws IOExce } @Override - public Optional getSeries(CubeId id) throws IOException { + public @NonNull Optional getSeries(@NonNull CubeId id) throws IOException { KeyConverter converter = KeyConverter.of(dsd, id); return SdmxCubeUtil .getSeries(connection, flow.getRef(), converter.toKey(id)) @@ -99,7 +101,7 @@ public Optional getSeries(CubeId id) throws IOException { } @Override - public Optional getSeriesWithData(CubeId ref) throws IOException { + public @NonNull Optional getSeriesWithData(@NonNull CubeId ref) throws IOException { KeyConverter converter = KeyConverter.of(dsd, ref); return SdmxCubeUtil .getSeriesWithData(connection, flow.getRef(), converter.toKey(ref)) @@ -107,7 +109,7 @@ public Optional getSeriesWithData(CubeId ref) throws IOExcep } @Override - public Stream getChildren(CubeId ref) throws IOException { + public @NonNull Stream getChildren(@NonNull CubeId ref) throws IOException { KeyConverter converter = KeyConverter.of(dsd, ref); String dimensionId = ref.getDimensionId(ref.getLevel()); int dimensionIndex = SdmxCubeUtil.getDimensionIndexById(dsd, dimensionId).orElseThrow(RuntimeException::new); @@ -118,12 +120,12 @@ public Stream getChildren(CubeId ref) throws IOException { } @Override - public String getDisplayName() { + public @NonNull String getDisplayName() { return String.format(Locale.ROOT, "%s ~ %s", sourceLabel, flow.getName()); } @Override - public String getDisplayName(CubeId id) { + public @NonNull String getDisplayName(CubeId id) { if (id.isVoid()) { return "All"; } @@ -131,11 +133,13 @@ public String getDisplayName(CubeId id) { } @Override - public String getDisplayNodeName(CubeId id) { + public @NonNull String getDisplayNodeName(CubeId id) { if (id.isVoid()) { return "All"; } - return getDisplayNodeName(dsd, id); + return displayCodes + ? getDimensionCodeId(id) + : getDimensionCodeLabel(id, dsd); } @Override @@ -152,7 +156,12 @@ private static CubeSeriesWithData cubeSeriesWithDataOf(KeyConverter converter, S return new CubeSeriesWithData(converter.fromKey(series.getKey()), series.getMeta().get(labelAttribute), series.getMeta(), getData(series)); } - private static String getDisplayNodeName(DataStructure dsd, CubeId ref) { + private static String getDimensionCodeId(CubeId ref) { + int index = ref.getLevel() - 1; + return ref.getDimensionValue(index); + } + + private static String getDimensionCodeLabel(CubeId ref, Structure dsd) { if (ref.isRoot()) { return "Invalid reference '" + dump(ref) + "'"; } @@ -169,7 +178,7 @@ private static String dump(CubeId ref) { } @VisibleForTesting - static Key getKey(DataStructure dsd, CubeId ref) { + static Key getKey(Structure dsd, CubeId ref) { if (ref.isRoot()) { return Key.ALL; } @@ -186,11 +195,11 @@ static Key getKey(DataStructure dsd, CubeId ref) { @lombok.RequiredArgsConstructor static final class KeyConverter { - static KeyConverter of(DataStructure dsd, CubeId ref) { + static KeyConverter of(Structure dsd, CubeId ref) { return new KeyConverter(dsd, new CubeIdBuilder(dsd, ref)); } - final DataStructure dsd; + final Structure dsd; final CubeIdBuilder builder; public Key toKey(CubeId a) { @@ -208,7 +217,7 @@ private static final class CubeIdBuilder { private final int[] indices; private final String[] dimValues; - CubeIdBuilder(DataStructure dsd, CubeId ref) { + CubeIdBuilder(Structure dsd, CubeId ref) { this.ref = ref; this.indices = new int[ref.getDepth()]; for (int i = 0; i < indices.length; i++) { @@ -271,13 +280,13 @@ private static TsUnit getTsUnit(Obs obs) { } } - private static CubeId getOrLoadRoot(List dimensions, DataStructure dsd) { + private static CubeId getOrLoadRoot(List dimensions, Structure dsd) { return dimensions.isEmpty() ? CubeId.root(loadDefaultDimIds(dsd)) : CubeId.root(dimensions); } - private static List loadDefaultDimIds(DataStructure dsd) { + private static List loadDefaultDimIds(Structure dsd) { return dsd .getDimensions() .stream() diff --git a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxCubeItems.java b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxCubeItems.java index 146ec46..5d78ba5 100644 --- a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxCubeItems.java +++ b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxCubeItems.java @@ -18,7 +18,7 @@ import jdplus.sdmx.base.api.file.SdmxFileBean; import jdplus.toolkit.base.tsp.HasFilePaths; -import sdmxdl.file.SdmxFileSource; +import sdmxdl.file.FileSource; import java.io.File; import java.io.FileNotFoundException; @@ -29,16 +29,12 @@ @lombok.experimental.UtilityClass public class SdmxCubeItems { - public static SdmxFileSource resolveFileSet(HasFilePaths paths, SdmxFileBean bean) throws FileNotFoundException { - SdmxFileSource.Builder result = SdmxFileSource.builder().data(paths.resolveFilePath(bean.getFile())); + public static FileSource resolveFileSet(HasFilePaths paths, SdmxFileBean bean) throws FileNotFoundException { + FileSource.Builder result = FileSource.builder().data(paths.resolveFilePath(bean.getFile())); File structure = bean.getStructureFile(); if (structure != null && !structure.toString().isEmpty()) { result.structure(paths.resolveFilePath(structure)); } - String dialect = bean.getDialect(); - if (dialect != null && !dialect.isEmpty()) { - result.dialect(dialect); - } return result.build(); } } diff --git a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxPropertiesSupport.java b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxPropertiesSupport.java index 1098c61..dd9c950 100644 --- a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxPropertiesSupport.java +++ b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/internal/sdmx/base/api/SdmxPropertiesSupport.java @@ -18,6 +18,9 @@ import jdplus.sdmx.base.api.HasSdmxProperties; import lombok.AccessLevel; +import lombok.NonNull; +import nbbrd.io.function.IORunnable; +import sdmxdl.Languages; import sdmxdl.SdmxManager; import java.util.concurrent.atomic.AtomicReference; @@ -27,21 +30,25 @@ * @author Philippe Charles */ @lombok.AllArgsConstructor(access = AccessLevel.PRIVATE) -public final class SdmxPropertiesSupport implements HasSdmxProperties { +public final class SdmxPropertiesSupport> implements HasSdmxProperties { - public static HasSdmxProperties of(Supplier defaultManager, Runnable onManagerChange) { - return new SdmxPropertiesSupport( - defaultManager, - new AtomicReference<>(defaultManager.get()), - onManagerChange); + public static > HasSdmxProperties of(Supplier defaultManager, Runnable onManagerChange) { + return new SdmxPropertiesSupport<>( + defaultManager, new AtomicReference<>(defaultManager.get()), onManagerChange, + () -> Languages.ANY, new AtomicReference<>(Languages.ANY), IORunnable.noOp().asUnchecked() + ); } private final Supplier defaultManager; private final AtomicReference manager; private final Runnable onManagerChange; + private final Supplier defaultLanguages; + private final AtomicReference languages; + private final Runnable onLanguagesChange; + @Override - public M getSdmxManager() { + public @NonNull M getSdmxManager() { return manager.get(); } @@ -52,4 +59,17 @@ public void setSdmxManager(M manager) { onManagerChange.run(); } } + + @Override + public @NonNull Languages getLanguages() { + return languages.get(); + } + + @Override + public void setLanguages(Languages languages) { + Languages old = this.languages.get(); + if (this.languages.compareAndSet(old, languages != null ? languages : defaultLanguages.get())) { + onLanguagesChange.run(); + } + } } diff --git a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/HasSdmxProperties.java b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/HasSdmxProperties.java index 1b263f8..440af67 100644 --- a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/HasSdmxProperties.java +++ b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/HasSdmxProperties.java @@ -16,19 +16,23 @@ */ package jdplus.sdmx.base.api; +import lombok.NonNull; import nbbrd.design.ThreadSafe; -import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import sdmxdl.Languages; import sdmxdl.SdmxManager; /** * @author Philippe Charles */ @ThreadSafe -public interface HasSdmxProperties { +public interface HasSdmxProperties> { - @NonNull - M getSdmxManager(); + @NonNull M getSdmxManager(); void setSdmxManager(@Nullable M manager); + + @NonNull Languages getLanguages(); + + void setLanguages(@Nullable Languages languages); } diff --git a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/file/SdmxFileBean.java b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/file/SdmxFileBean.java index a1943d1..f0841ea 100644 --- a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/file/SdmxFileBean.java +++ b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/file/SdmxFileBean.java @@ -31,6 +31,7 @@ public final class SdmxFileBean implements FileBean { private File file; private File structureFile; + @Deprecated private String dialect; private List dimensions; private String labelAttribute; diff --git a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/file/SdmxFileProvider.java b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/file/SdmxFileProvider.java index b142a15..4a13e98 100644 --- a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/file/SdmxFileProvider.java +++ b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/file/SdmxFileProvider.java @@ -16,23 +16,24 @@ */ package jdplus.sdmx.base.api.file; -import jdplus.toolkit.base.api.timeseries.TsProvider; +import internal.sdmx.base.api.SdmxCubeConnection; +import internal.sdmx.base.api.SdmxCubeItems; +import internal.sdmx.base.api.SdmxPropertiesSupport; import jdplus.sdmx.base.api.HasSdmxProperties; +import jdplus.toolkit.base.api.timeseries.TsProvider; import jdplus.toolkit.base.tsp.*; import jdplus.toolkit.base.tsp.cube.CubeConnection; import jdplus.toolkit.base.tsp.cube.CubeSupport; import jdplus.toolkit.base.tsp.stream.HasTsStream; import jdplus.toolkit.base.tsp.stream.TsStreamAsProvider; import jdplus.toolkit.base.tsp.util.ResourcePool; -import internal.sdmx.base.api.SdmxCubeConnection; -import internal.sdmx.base.api.SdmxCubeItems; -import internal.sdmx.base.api.SdmxPropertiesSupport; +import lombok.NonNull; import nbbrd.io.Resource; import nbbrd.service.ServiceProvider; import sdmxdl.Connection; -import sdmxdl.DataflowRef; +import sdmxdl.FlowRef; import sdmxdl.file.SdmxFileManager; -import sdmxdl.file.SdmxFileSource; +import sdmxdl.file.FileSource; import java.io.File; import java.io.IOException; @@ -82,12 +83,12 @@ public SdmxFileProvider() { } @Override - public String getDisplayName() { + public @NonNull String getDisplayName() { return "SDMX Files"; } @Override - public String getFileDescription() { + public @NonNull String getFileDescription() { return "SDMX file"; } @@ -97,34 +98,34 @@ public boolean accept(File pathname) { } @Override - public String getDisplayName(DataSource dataSource) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSource dataSource) throws IllegalArgumentException { return getSourceLabel(decodeBean(dataSource)); } @Override - public String getDisplayName(DataSet dataSet) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull DataSet dataSet) throws IllegalArgumentException { return cubeSupport.getDisplayName(dataSet); } @Override - public String getDisplayName(IOException exception) throws IllegalArgumentException { + public @NonNull String getDisplayName(@NonNull IOException exception) throws IllegalArgumentException { return cubeSupport.getDisplayName(exception); } @Override - public String getDisplayNodeName(DataSet dataSet) throws IllegalArgumentException { + public @NonNull String getDisplayNodeName(@NonNull DataSet dataSet) throws IllegalArgumentException { return cubeSupport.getDisplayNodeName(dataSet); } private static CubeConnection openConnection(DataSource dataSource, HasSdmxProperties properties, HasFilePaths paths, SdmxFileParam param) throws IOException { SdmxFileBean bean = param.get(dataSource); - SdmxFileSource files = SdmxCubeItems.resolveFileSet(paths, bean); + FileSource files = SdmxCubeItems.resolveFileSet(paths, bean); - DataflowRef flow = files.asDataflowRef(); + FlowRef flow = files.asDataflowRef(); - Connection conn = properties.getSdmxManager().getConnection(files); + Connection conn = properties.getSdmxManager().getConnection(files, properties.getLanguages()); try { - return SdmxCubeConnection.of(conn, flow, bean.getDimensions(), bean.getLabelAttribute(), getSourceLabel(bean)); + return SdmxCubeConnection.of(conn, flow, bean.getDimensions(), bean.getLabelAttribute(), getSourceLabel(bean), false); } catch (IOException ex) { Resource.ensureClosed(ex, conn); throw ex; diff --git a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/web/SdmxWebProvider.java b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/web/SdmxWebProvider.java index 63668bc..17ae313 100644 --- a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/web/SdmxWebProvider.java +++ b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/main/java/jdplus/sdmx/base/api/web/SdmxWebProvider.java @@ -16,33 +16,26 @@ */ package jdplus.sdmx.base.api.web; -import jdplus.toolkit.base.api.timeseries.Ts; -import jdplus.toolkit.base.api.timeseries.TsInformationType; -import jdplus.toolkit.base.api.timeseries.TsProvider; +import internal.sdmx.base.api.SdmxCubeConnection; +import internal.sdmx.base.api.SdmxPropertiesSupport; import jdplus.sdmx.base.api.HasSdmxProperties; +import jdplus.toolkit.base.api.timeseries.TsProvider; import jdplus.toolkit.base.tsp.*; -import jdplus.toolkit.base.tsp.DataSet; import jdplus.toolkit.base.tsp.cube.BulkCubeConnection; import jdplus.toolkit.base.tsp.cube.CubeConnection; import jdplus.toolkit.base.tsp.cube.CubeSupport; 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.ShortLivedCachingLoader; import jdplus.toolkit.base.tsp.util.ResourcePool; -import internal.sdmx.base.api.SdmxCubeConnection; -import internal.sdmx.base.api.SdmxPropertiesSupport; import nbbrd.io.Resource; import nbbrd.service.ServiceProvider; -import org.checkerframework.checker.nullness.qual.NonNull; -import sdmxdl.*; +import sdmxdl.Connection; +import sdmxdl.FlowRef; import sdmxdl.web.SdmxWebManager; import java.io.IOException; -import java.util.Comparator; -import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; -import java.util.stream.IntStream; /** * @author Philippe Charles @@ -83,12 +76,12 @@ public SdmxWebProvider() { this.mutableListSupport = HasDataSourceMutableList.of(NAME, pool::remove); this.monikerSupport = HasDataMoniker.usingUri(NAME); this.beanSupport = HasDataSourceBean.of(NAME, param, param.getVersion()); - this.cubeSupport = CubeSupport.of(NAME, pool.asFactory(o -> openConnection(o, properties, param)), param::getCubeIdParam); + this.cubeSupport = CubeSupport.of(NAME, pool.asFactory(o -> openConnection(o, properties, param, displayCodes.get())), param::getCubeIdParam); this.tsSupport = TsStreamAsProvider.of(NAME, cubeSupport, monikerSupport, pool::clear); } @Override - public String getDisplayName() { + public @lombok.NonNull String getDisplayName() { return "SDMX Web Services"; } @@ -103,50 +96,15 @@ public void setDisplayCodes(boolean displayCodes) { } } - @NonNull - public Ts getTs(@NonNull SdmxWebBean bean, @NonNull Key key, @NonNull TsInformationType type) throws IOException { - String[] dimsInNaturalOrder = dimsInNaturalOrder(getSdmxManager(), bean.getSource(), DataflowRef.parse(bean.getFlow())); - - if (!Key.ALL.equals(key) && key.size() != dimsInNaturalOrder.length) { - throw new IllegalArgumentException("Invalid key '" + key + "'"); - } - - // we need to sort dimensions by wildcard in key because of provider issue - Comparator c = (l, r) -> key.isWildcard(l) ? (key.isWildcard(r) ? 0 : 1) : (key.isWildcard(r) ? -1 : 0); - List sortedDims = IntStream.range(0, dimsInNaturalOrder.length).boxed() - .sorted(c.thenComparingInt(o -> o)) - .map(o -> dimsInNaturalOrder[o]) - .collect(Collectors.toList()); - bean.setDimensions(sortedDims); - - DataSet.Builder b = DataSet.builder(encodeBean(bean), key.isSeries() ? DataSet.Kind.SERIES : DataSet.Kind.COLLECTION); - if (!Key.ALL.equals(key)) { - IntStream.range(0, dimsInNaturalOrder.length) - .filter(o -> !key.isWildcard(o)) - .forEach(o -> b.parameter(dimsInNaturalOrder[o], key.get(o))); - } - return getTs(toMoniker(b.build()), type); - } - - private static String[] dimsInNaturalOrder(SdmxWebManager supplier, String source, DataflowRef flow) throws IOException { - try (Connection c = supplier.getConnection(source)) { - return c.getStructure(flow) - .getDimensions() - .stream() - .map(Dimension::getId) - .toArray(String[]::new); - } - } - - private static CubeConnection openConnection(DataSource source, HasSdmxProperties properties, SdmxWebParam param) throws IOException { + private static CubeConnection openConnection(DataSource source, HasSdmxProperties properties, SdmxWebParam param, boolean displayCodes) throws IOException { SdmxWebBean bean = param.get(source); - DataflowRef flow = DataflowRef.parse(bean.getFlow()); + FlowRef flow = FlowRef.parse(bean.getFlow()); - Connection conn = properties.getSdmxManager().getConnection(bean.getSource()); + Connection conn = properties.getSdmxManager().getConnection(bean.getSource(), properties.getLanguages()); try { - CubeConnection result = SdmxCubeConnection.of(conn, flow, bean.getDimensions(), bean.getLabelAttribute(), bean.getSource()); - return BulkCubeConnection.of(result, bean.getCache(), IOCacheFactoryLoader.get()); + CubeConnection result = SdmxCubeConnection.of(conn, flow, bean.getDimensions(), bean.getLabelAttribute(), bean.getSource(), displayCodes); + return BulkCubeConnection.of(result, bean.getCache(), ShortLivedCachingLoader.get()); } catch (IOException ex) { Resource.ensureClosed(ex, conn); throw ex; diff --git a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/test/java/_demo/SdmxFakeWebDemo.java b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/test/java/_demo/SdmxFakeWebDemo.java index 621a387..7bc60bc 100644 --- a/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/test/java/_demo/SdmxFakeWebDemo.java +++ b/jdplus-sdmx-base/jdplus-sdmx-base-parent/jdplus-sdmx-base-api/src/test/java/_demo/SdmxFakeWebDemo.java @@ -23,7 +23,7 @@ import sdmxdl.Feature; import sdmxdl.web.SdmxWebManager; import tests.sdmxdl.api.RepoSamples; -import tests.sdmxdl.web.MockedDriver; +import tests.sdmxdl.web.spi.MockedDriver; import java.io.IOException; import java.util.EnumSet; diff --git a/jdplus-sdmx-base/jdplus-sdmx-base-parent/pom.xml b/jdplus-sdmx-base/jdplus-sdmx-base-parent/pom.xml index 4e6234c..c44acee 100644 --- a/jdplus-sdmx-base/jdplus-sdmx-base-parent/pom.xml +++ b/jdplus-sdmx-base/jdplus-sdmx-base-parent/pom.xml @@ -5,7 +5,7 @@ com.github.nbbrd.jdplus-sdmx jdplus-sdmx-base - 3.0.0 + 3.1.0 jdplus-sdmx-base-parent diff --git a/jdplus-sdmx-base/pom.xml b/jdplus-sdmx-base/pom.xml index 42594bd..083c0eb 100644 --- a/jdplus-sdmx-base/pom.xml +++ b/jdplus-sdmx-base/pom.xml @@ -6,7 +6,7 @@ com.github.nbbrd.jdplus-sdmx jdplus-sdmx - 3.0.0 + 3.1.0 jdplus-sdmx-base diff --git a/jdplus-sdmx-bom/pom.xml b/jdplus-sdmx-bom/pom.xml index 4b47a23..68b82d4 100644 --- a/jdplus-sdmx-bom/pom.xml +++ b/jdplus-sdmx-bom/pom.xml @@ -7,7 +7,7 @@ com.github.nbbrd.jdplus-sdmx jdplus-sdmx - 3.0.0 + 3.1.0 jdplus-sdmx-bom @@ -20,13 +20,18 @@ - com.github.nbbrd.jdplus-sdmx - jdplus-sdmx-cli-plugin + ${project.groupId} + jdplus-sdmx-base ${project.version} - com.github.nbbrd.jdplus-sdmx - jdplus-sdmx-desktop-plugin + ${project.groupId} + jdplus-sdmx-cli + ${project.version} + + + ${project.groupId} + jdplus-sdmx-desktop ${project.version} @@ -37,7 +42,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.4.1 + 1.5.0 bom ${project.build.directory} @@ -84,7 +89,7 @@ org.jreleaser jreleaser-maven-plugin - 1.5.1 + 1.8.0 release-assets diff --git a/jdplus-sdmx-cli/jdplus-sdmx-cli-plugin/pom.xml b/jdplus-sdmx-cli/jdplus-sdmx-cli-plugin/pom.xml index 7e72c9c..b4c8172 100644 --- a/jdplus-sdmx-cli/jdplus-sdmx-cli-plugin/pom.xml +++ b/jdplus-sdmx-cli/jdplus-sdmx-cli-plugin/pom.xml @@ -6,7 +6,7 @@ com.github.nbbrd.jdplus-sdmx jdplus-sdmx-cli - 3.0.0 + 3.1.0 jdplus-sdmx-cli-plugin diff --git a/jdplus-sdmx-cli/pom.xml b/jdplus-sdmx-cli/pom.xml index d43ac03..680483e 100644 --- a/jdplus-sdmx-cli/pom.xml +++ b/jdplus-sdmx-cli/pom.xml @@ -6,7 +6,7 @@ com.github.nbbrd.jdplus-sdmx jdplus-sdmx - 3.0.0 + 3.1.0 jdplus-sdmx-cli diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/pom.xml b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/pom.xml index cbd27b0..476ef7d 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/pom.xml +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/pom.xml @@ -6,7 +6,7 @@ com.github.nbbrd.jdplus-sdmx jdplus-sdmx-desktop - 3.0.0 + 3.1.0 jdplus-sdmx-desktop-plugin @@ -100,6 +100,10 @@ org.netbeans.api * + + com.github.nbbrd.java-io-util + * + @@ -113,46 +117,8 @@ com.github.nbbrd.sdmx-dl - sdmx-dl-provider-ri + sdmx-dl-standalone ${sdmx-dl.version} - - - com.github.nbbrd.java-io-util - * - - - - - com.github.nbbrd.sdmx-dl - sdmx-dl-format-kryo - ${sdmx-dl.version} - - - com.github.nbbrd.java-io-util - * - - - - - com.github.nbbrd.java-net-proxy - java-net-proxy - 1.0.1 - - - io.github.hakky54 - sslcontext-kickstart - 8.0.0 - - - slf4j-api - org.slf4j - - - - - org.slf4j - slf4j-jdk14 - 2.0.7 com.github.nbbrd.java-desktop-util diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/Caches.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/Caches.java new file mode 100644 index 0000000..f5dcc9d --- /dev/null +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/Caches.java @@ -0,0 +1,106 @@ +package internal.sdmx.desktop.plugin; + +import jdplus.toolkit.base.tsp.util.ShortLivedCache; +import jdplus.toolkit.base.tsp.util.ShortLivedCachingLoader; + +import java.time.Duration; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; + +public final class Caches { + + private Caches() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + public static ConcurrentMap asConcurrentMap(ShortLivedCache cache) { + return new ConcurrentMap() { + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEmpty() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsKey(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsValue(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public V get(Object key) { + return cache.get((K) key); + } + + @Override + public V put(K key, V value) { + cache.put(key, value); + return null; + } + + @Override + public V remove(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(Map m) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Set keySet() { + throw new UnsupportedOperationException(); + } + + @Override + public Collection values() { + throw new UnsupportedOperationException(); + } + + @Override + public Set> entrySet() { + throw new UnsupportedOperationException(); + } + }; + } + + public static ConcurrentMap ttlCacheAsMap(Duration duration) { + return asConcurrentMap(ShortLivedCachingLoader.get().ofTtl(duration)); + } +} diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/CustomNetwork.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/CustomNetwork.java deleted file mode 100644 index 6a8ba6d..0000000 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/CustomNetwork.java +++ /dev/null @@ -1,63 +0,0 @@ -package internal.sdmx.desktop.plugin; - -import internal.http.curl.CurlHttpURLConnection; -import java.net.ProxySelector; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLSocketFactory; -import nbbrd.net.proxy.SystemProxySelector; -import nl.altindag.ssl.SSLFactory; -import sdmxdl.web.Network; -import sdmxdl.web.URLConnectionFactory; - -@lombok.Value -@lombok.Builder(toBuilder = true) -public final class CustomNetwork implements Network { - - boolean curlBackend; - boolean autoProxy; - boolean defaultTrustMaterial; - boolean systemTrustMaterial; - - @lombok.NonNull - @lombok.Getter(lazy = true) - private final ProxySelector lazyProxySelector = initProxySelector(); - - @lombok.NonNull - @lombok.Getter(lazy = true) - private final SSLFactory lazySSLFactory = initSSLFactory(); - - private ProxySelector initProxySelector() { - return autoProxy ? SystemProxySelector.ofServiceLoader() : ProxySelector.getDefault(); - } - - private SSLFactory initSSLFactory() { - SSLFactory.Builder result = SSLFactory.builder(); - if (defaultTrustMaterial) { - result.withDefaultTrustMaterial(); - } - if (systemTrustMaterial) { - result.withSystemTrustMaterial(); - } - return result.build(); - } - - @Override - public HostnameVerifier getHostnameVerifier() { - return getLazySSLFactory().getHostnameVerifier(); - } - - @Override - public ProxySelector getProxySelector() { - return getLazyProxySelector(); - } - - @Override - public SSLSocketFactory getSSLSocketFactory() { - return getLazySSLFactory().getSslSocketFactory(); - } - - @Override - public URLConnectionFactory getURLConnectionFactory() { - return curlBackend ? CurlHttpURLConnection::of : URLConnectionFactory.getDefault(); - } -} diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxAutoCompletion.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxAutoCompletion.java index b600e27..c0a7068 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxAutoCompletion.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxAutoCompletion.java @@ -1,168 +1,115 @@ /* * Copyright 2017 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 internal.sdmx.desktop.plugin; -import sdmxdl.Dataflow; -import sdmxdl.DataflowRef; -import sdmxdl.Dimension; -import sdmxdl.LanguagePriorityList; -import sdmxdl.web.SdmxWebManager; -import sdmxdl.web.SdmxWebSource; -import jdplus.toolkit.desktop.plugin.TsManager; -import jdplus.sdmx.base.api.web.SdmxWebProvider; import ec.util.completion.AutoCompletionSource; -import static ec.util.completion.AutoCompletionSource.Behavior.ASYNC; -import static ec.util.completion.AutoCompletionSource.Behavior.NONE; -import static ec.util.completion.AutoCompletionSource.Behavior.SYNC; import ec.util.completion.ExtAutoCompletionSource; import ec.util.completion.swing.CustomListCellRenderer; -import java.io.IOException; -import java.net.Proxy; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; +import internal.sdmx.base.api.SdmxCubeItems; +import jdplus.sdmx.base.api.HasSdmxProperties; +import jdplus.sdmx.base.api.file.SdmxFileBean; +import jdplus.sdmx.base.api.file.SdmxFileProvider; +import jdplus.sdmx.base.api.web.SdmxWebBean; +import jdplus.sdmx.base.api.web.SdmxWebProvider; +import lombok.NonNull; +import sdmxdl.*; +import sdmxdl.file.FileSource; +import sdmxdl.web.SdmxWebManager; +import sdmxdl.web.WebSource; + +import javax.swing.*; +import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Comparator; -import java.util.HashMap; import java.util.List; +import java.util.Optional; import java.util.concurrent.ConcurrentMap; import java.util.function.Predicate; import java.util.function.Supplier; + +import static ec.util.completion.AutoCompletionSource.Behavior.*; import static java.util.stream.Collectors.toList; -import javax.net.ssl.HttpsURLConnection; -import javax.swing.Icon; -import javax.swing.ImageIcon; -import javax.swing.JList; -import javax.swing.ListCellRenderer; -import nbbrd.desktop.favicon.DomainName; -import nbbrd.desktop.favicon.FaviconRef; -import nbbrd.desktop.favicon.FaviconSupport; -import nbbrd.desktop.favicon.URLConnectionFactory; -import org.openide.util.ImageUtilities; -import sdmxdl.Attribute; -import sdmxdl.Connection; -import sdmxdl.SdmxManager; -import sdmxdl.SdmxSource; -import sdmxdl.ext.Registry; -import sdmxdl.ext.spi.Dialect; -import sdmxdl.web.Network; /** - * * @author Philippe Charles */ public abstract class SdmxAutoCompletion { - public abstract AutoCompletionSource getSource(); + public abstract @NonNull AutoCompletionSource getSource(); - public abstract ListCellRenderer getRenderer(); + public abstract @NonNull ListCellRenderer getRenderer(); - public static SdmxAutoCompletion onDialect(Registry registry) { - return new DialectCompletion(registry); + public static @NonNull SdmxAutoCompletion onWebSource(@NonNull SdmxWebProvider provider) { + return new WebSourceCompletion(provider); } - public static SdmxAutoCompletion onWebSource(SdmxWebManager manager) { - return new WebSourceCompletion(manager); + public static @NonNull SdmxAutoCompletion onFlow(@NonNull SdmxWebProvider provider, @NonNull SdmxWebBean bean, @NonNull ConcurrentMap cache) { + return new DataflowCompletion<>(provider, () -> getWebSourceOrNull(bean, provider), cache); } - public static SdmxAutoCompletion onDataflow(SdmxManager manager, Supplier source, ConcurrentMap cache) { - return new DataflowCompletion<>(manager, source, cache); + public static @NonNull SdmxAutoCompletion onDimension(@NonNull SdmxWebProvider provider, @NonNull SdmxWebBean bean, @NonNull ConcurrentMap cache) { + return new DimensionCompletion<>(provider, () -> getWebSourceOrNull(bean, provider), () -> getFlowRefOrNull(bean), cache); } - public static SdmxAutoCompletion onDimension(SdmxManager manager, Supplier source, Supplier flowRef, ConcurrentMap cache) { - return new DimensionCompletion<>(manager, source, flowRef, cache); + public static @NonNull SdmxAutoCompletion onDimension(@NonNull SdmxFileProvider provider, @NonNull SdmxFileBean bean, @NonNull ConcurrentMap cache) { + return new DimensionCompletion<>(provider, () -> getFileSource(bean, provider).orElse(null), () -> getFileSource(bean, provider).map(FileSource::asDataflowRef).orElse(null), cache); } - public static SdmxAutoCompletion onAttribute(SdmxManager manager, Supplier source, Supplier flowRef, ConcurrentMap cache) { - return new AttributeCompletion<>(manager, source, flowRef, cache); + public static @NonNull SdmxAutoCompletion onAttribute(@NonNull SdmxWebProvider provider, @NonNull SdmxWebBean bean, @NonNull ConcurrentMap cache) { + return new AttributeCompletion<>(provider, () -> getWebSourceOrNull(bean, provider), () -> getFlowRefOrNull(bean), cache); } - @lombok.AllArgsConstructor - private static final class DialectCompletion extends SdmxAutoCompletion { - - @lombok.NonNull - private final Registry registry; - - @Override - public AutoCompletionSource getSource() { - return ExtAutoCompletionSource - .builder(this::load) - .behavior(SYNC) - .postProcessor(this::filterAndSort) - .valueToString(Dialect::getName) - .build(); - } - - @Override - public ListCellRenderer getRenderer() { - return CustomListCellRenderer.of(Dialect::getName, Dialect::getDescription); - } - - private List load(String term) { - return registry.getDialects(); - } - - private List filterAndSort(List list, String term) { - return list.stream().filter(getFilter(term)).sorted(getSorter(term)).collect(toList()); - } - - private Predicate getFilter(String term) { - Predicate filter = ExtAutoCompletionSource.basicFilter(term); - return value -> filter.test(value.getDescription()) || filter.test(value.getName()); - } - - private Comparator getSorter(String term) { - return Comparator.comparing(Dialect::getDescription); - } + public static @NonNull SdmxAutoCompletion onAttribute(@NonNull SdmxFileProvider provider, @NonNull SdmxFileBean bean, @NonNull ConcurrentMap cache) { + return new AttributeCompletion<>(provider, () -> getFileSource(bean, provider).orElse(null), () -> getFileSource(bean, provider).map(FileSource::asDataflowRef).orElse(null), cache); } @lombok.AllArgsConstructor private static final class WebSourceCompletion extends SdmxAutoCompletion { - @lombok.NonNull - private final SdmxWebManager manager; + private final @NonNull HasSdmxProperties provider; @Override - public AutoCompletionSource getSource() { + public @NonNull AutoCompletionSource getSource() { return ExtAutoCompletionSource .builder(this::load) .behavior(SYNC) .postProcessor(this::filterAndSort) - .valueToString(SdmxWebSource::getId) + .valueToString(WebSource::getId) .build(); } @Override - public ListCellRenderer getRenderer() { - return new CustomListCellRenderer() { + public @NonNull ListCellRenderer getRenderer() { + return new CustomListCellRenderer() { @Override - protected String getValueAsString(SdmxWebSource value) { - return value.getId() + ": " + manager.getLanguages().select(value.getNames()); + protected @NonNull String getValueAsString(@NonNull WebSource value) { + return value.getId() + ": " + provider.getLanguages().select(value.getNames()); } @Override - protected Icon toIcon(String term, JList list, SdmxWebSource value, int index, boolean isSelected, boolean cellHasFocus) { - return getFavicon(value.getWebsite(), list::repaint); + protected Icon toIcon(String term, JList list, WebSource value, int index, boolean isSelected, boolean cellHasFocus) { + return SdmxIcons.getFavicon(provider.getSdmxManager().getNetworking(), value.getWebsite(), list::repaint); } }; } - private List load(String term) { - return manager + private List load(String term) { + return provider + .getSdmxManager() .getSources() .values() .stream() @@ -170,33 +117,29 @@ private List load(String term) { .collect(toList()); } - private List filterAndSort(List list, String term) { + private List filterAndSort(List list, String term) { return list.stream().filter(getFilter(term)).collect(toList()); } - private Predicate getFilter(String term) { + private Predicate getFilter(String term) { Predicate filter = ExtAutoCompletionSource.basicFilter(term); - LanguagePriorityList langs = manager.getLanguages(); - return value -> filter.test(langs.select(value.getNames())) + return value -> filter.test(provider.getLanguages().select(value.getNames())) || filter.test(value.getId()) || value.getAliases().stream().anyMatch(filter); } } @lombok.AllArgsConstructor - private static final class DataflowCompletion extends SdmxAutoCompletion { + private static final class DataflowCompletion extends SdmxAutoCompletion { - @lombok.NonNull - private final SdmxManager manager; + private final @NonNull HasSdmxProperties> provider; - @lombok.NonNull - private final Supplier source; + private final @NonNull Supplier source; - @lombok.NonNull - private final ConcurrentMap cache; + private final @NonNull ConcurrentMap cache; @Override - public AutoCompletionSource getSource() { + public @NonNull AutoCompletionSource getSource() { return ExtAutoCompletionSource .builder(this::load) .behavior(this::getBehavior) @@ -207,12 +150,12 @@ public AutoCompletionSource getSource() { } @Override - public ListCellRenderer getRenderer() { - return CustomListCellRenderer.of(flow -> flow.getRef() + "
" + flow.getName(), flow -> flow.getRef().toString()); + public @NonNull ListCellRenderer getRenderer() { + return CustomListCellRenderer.of(flow -> flow.getRef() + "
" + flow.getName(), flow -> flow.getRef().toString()); } - private List load(String term) throws Exception { - try ( Connection c = manager.getConnection(source.get())) { + private List load(String term) throws Exception { + try (Connection c = provider.getSdmxManager().getConnection(source.get(), provider.getLanguages())) { return new ArrayList<>(c.getFlows()); } } @@ -221,36 +164,32 @@ private AutoCompletionSource.Behavior getBehavior(String term) { return source.get() != null ? ASYNC : NONE; } - private List filterAndSort(List values, String term) { + private List filterAndSort(List values, String term) { Predicate filter = ExtAutoCompletionSource.basicFilter(term); return values.stream() .filter(o -> filter.test(o.getName()) || filter.test(o.getRef().getId()) || filter.test(o.getDescription())) - .sorted(Comparator.comparing(Dataflow::getName)) + .sorted(Comparator.comparing(Flow::getName)) .collect(toList()); } private String getCacheKey(String term) { - return "Dataflow" + source.get() + manager.getLanguages(); + return "Dataflow" + source.get() + provider.getLanguages(); } } @lombok.AllArgsConstructor - private static final class DimensionCompletion extends SdmxAutoCompletion { + private static final class DimensionCompletion extends SdmxAutoCompletion { - @lombok.NonNull - private final SdmxManager manager; + private final @NonNull HasSdmxProperties> provider; - @lombok.NonNull - private final Supplier source; + private final @NonNull Supplier source; - @lombok.NonNull - private final Supplier flowRef; + private final @NonNull Supplier flowRef; - @lombok.NonNull - private final ConcurrentMap cache; + private final @NonNull ConcurrentMap cache; @Override - public AutoCompletionSource getSource() { + public @NonNull AutoCompletionSource getSource() { return ExtAutoCompletionSource .builder(this::load) .behavior(this::getBehavior) @@ -261,12 +200,12 @@ public AutoCompletionSource getSource() { } @Override - public ListCellRenderer getRenderer() { + public @NonNull ListCellRenderer getRenderer() { return CustomListCellRenderer.of(Dimension::getId, Dimension::getName); } private List load(String term) throws Exception { - try ( Connection c = manager.getConnection(source.get())) { + try (Connection c = provider.getSdmxManager().getConnection(source.get(), provider.getLanguages())) { return new ArrayList<>(c.getStructure(flowRef.get()).getDimensions()); } } @@ -284,29 +223,25 @@ private List filterAndSort(List values, String term) { } private String getCacheKey(String term) { - return "Dimension" + source.get() + flowRef.get() + manager.getLanguages(); + return "Dimension" + source.get() + flowRef.get() + provider.getLanguages(); } } @lombok.AllArgsConstructor - private static final class AttributeCompletion extends SdmxAutoCompletion { + private static final class AttributeCompletion extends SdmxAutoCompletion { - @lombok.NonNull - private final SdmxManager manager; + private final @NonNull HasSdmxProperties> provider; - @lombok.NonNull - private final Supplier source; + private final @NonNull Supplier source; - @lombok.NonNull - private final Supplier flowRef; + private final @NonNull Supplier flowRef; - @lombok.NonNull - private final ConcurrentMap cache; + private final @NonNull ConcurrentMap cache; @Override - public AutoCompletionSource getSource() { + public @NonNull AutoCompletionSource getSource() { return ExtAutoCompletionSource - .builder(o -> load(o)) + .builder(this::load) .behavior(this::getBehavior) .postProcessor(this::filterAndSort) .valueToString(Attribute::getId) @@ -315,12 +250,12 @@ public AutoCompletionSource getSource() { } @Override - public ListCellRenderer getRenderer() { + public @NonNull ListCellRenderer getRenderer() { return CustomListCellRenderer.of(Attribute::getId, Attribute::getName); } private List load(String term) throws Exception { - try ( Connection c = manager.getConnection(source.get())) { + try (Connection c = provider.getSdmxManager().getConnection(source.get(), provider.getLanguages())) { return new ArrayList<>(c.getStructure(flowRef.get()).getAttributes()); } } @@ -338,68 +273,27 @@ private List filterAndSort(List values, String term) { } private String getCacheKey(String term) { - return "Attribute" + source.get() + flowRef.get() + manager.getLanguages(); + return "Attribute" + source.get() + flowRef.get() + provider.getLanguages(); } } - public static ImageIcon getDefaultIcon() { - return ImageUtilities.loadImageIcon("jdplus/sdmx/desktop/plugin/sdmx-logo.png", false); + private static WebSource getWebSourceOrNull(SdmxWebBean bean, SdmxWebProvider provider) { + return provider.getSdmxManager().getSources().get(bean.getSource()); } - public static Icon getFavicon(URL website) { - return website != null - ? FAVICONS.getOrDefault(FaviconRef.of(DomainName.of(website), 16), getDefaultIcon()) - : getDefaultIcon(); - } - - public static Icon getFavicon(URL website, Runnable callback) { - return website != null - ? FAVICONS.getOrDefault(FaviconRef.of(DomainName.of(website), 16), callback, getDefaultIcon()) - : getDefaultIcon(); - } - - public static final FaviconSupport FAVICONS = FaviconSupport - .ofServiceLoader() - .toBuilder() - .client(new ClientOverCustomNetwork()) - .cache(new HashMap<>()) - // .cache(IOCacheFactoryLoader.get().ofTtl(Duration.ofHours(1))) - .build(); - - private static final class ClientOverCustomNetwork implements URLConnectionFactory { - - @Override - public URLConnection openConnection(URL url) throws IOException { - Network network = getNetwork(); - Proxy proxy = selectProxy(network, url); - URLConnection result = network.getURLConnectionFactory().openConnection(url, proxy); - applyHttps(result, network); - return result; - } - - private void applyHttps(URLConnection result, Network network) { - if (result instanceof HttpsURLConnection) { - HttpsURLConnection https = (HttpsURLConnection) result; - https.setHostnameVerifier(network.getHostnameVerifier()); - https.setSSLSocketFactory(network.getSSLSocketFactory()); - } - } - - private Proxy selectProxy(Network network, URL url) throws IOException { - try { - return network.getProxySelector().select(url.toURI()).stream().findFirst().orElse(Proxy.NO_PROXY); - } catch (URISyntaxException ex) { - throw new IOException(ex); - } + private static FlowRef getFlowRefOrNull(SdmxWebBean bean) { + try { + return FlowRef.parse(bean.getFlow()); + } catch (IllegalArgumentException ex) { + return null; } } - private static Network getNetwork() { - return TsManager - .get() - .getProvider(SdmxWebProvider.class) - .map(SdmxWebProvider::getSdmxManager) - .map(SdmxWebManager::getNetwork) - .orElse(Network.getDefault()); + private static Optional getFileSource(SdmxFileBean bean, SdmxFileProvider provider) { + try { + return Optional.of(SdmxCubeItems.resolveFileSet(provider, bean)); + } catch (FileNotFoundException ex) { + return Optional.empty(); + } } } diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxIcons.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxIcons.java new file mode 100644 index 0000000..6e13907 --- /dev/null +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxIcons.java @@ -0,0 +1,96 @@ +package internal.sdmx.desktop.plugin; + +import lombok.AllArgsConstructor; +import lombok.NonNull; +import nbbrd.desktop.favicon.DomainName; +import nbbrd.desktop.favicon.FaviconRef; +import nbbrd.desktop.favicon.FaviconSupport; +import nbbrd.desktop.favicon.URLConnectionFactory; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.openide.util.ImageUtilities; +import sdmxdl.web.WebSource; +import sdmxdl.web.spi.Network; +import sdmxdl.web.spi.Networking; +import sdmxdl.web.spi.SSLFactory; + +import javax.net.ssl.HttpsURLConnection; +import javax.swing.*; +import java.io.IOException; +import java.net.Proxy; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.time.Duration; + +@lombok.experimental.UtilityClass +public class SdmxIcons { + + public static @NonNull ImageIcon getDefaultIcon() { + return ImageUtilities.loadImageIcon("jdplus/sdmx/desktop/plugin/sdmx-logo.png", false); + } + + public static @NonNull Icon getFavicon(@NonNull Networking networking, @Nullable URL website) { + return website != null + ? getFavicons(networking).getOrDefault(FaviconRef.of(DomainName.of(website), 16), getDefaultIcon()) + : getDefaultIcon(); + } + + public static @NonNull Icon getFavicon(@NonNull Networking networking, @Nullable URL website, @NonNull Runnable callback) { + return website != null + ? getFavicons(networking).getOrDefault(FaviconRef.of(DomainName.of(website), 16), callback, getDefaultIcon()) + : getDefaultIcon(); + } + + private static FaviconSupport getFavicons(Networking networking) { + return FAVICONS + .toBuilder() + .client(new FaviconClientOverCustomNetworking(networking)) + .build(); + } + + private static final FaviconSupport FAVICONS = FaviconSupport + .ofServiceLoader() + .toBuilder() + .cache(Caches.ttlCacheAsMap(Duration.ofHours(1))) + .build(); + + @AllArgsConstructor + private static final class FaviconClientOverCustomNetworking implements URLConnectionFactory { + + private final @NonNull Networking networking; + + @Override + public @NonNull URLConnection openConnection(@NonNull URL url) throws IOException { + Network network = networking.getNetwork(asSource(url), null, null); + Proxy proxy = selectProxy(network, url); + URLConnection result = network.getURLConnectionFactory().openConnection(url, proxy); + applyHttps(result, network); + return result; + } + + private static WebSource asSource(URL url) throws IOException { + try { + return WebSource.builder().id("").endpoint(url.toURI()).driver("").build(); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + } + + private static void applyHttps(URLConnection result, Network network) { + if (result instanceof HttpsURLConnection) { + HttpsURLConnection https = (HttpsURLConnection) result; + SSLFactory sslFactory = network.getSSLFactory(); + https.setHostnameVerifier(sslFactory.getHostnameVerifier()); + https.setSSLSocketFactory(sslFactory.getSSLSocketFactory()); + } + } + + private static Proxy selectProxy(Network network, URL url) throws IOException { + try { + return network.getProxySelector().select(url.toURI()).stream().findFirst().orElse(Proxy.NO_PROXY); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + } + } +} diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxWebSourceService.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxWebSourceService.java index 283cfd4..9faa91d 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxWebSourceService.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/internal/sdmx/desktop/plugin/SdmxWebSourceService.java @@ -1,32 +1,33 @@ /* * Copyright 2015 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 internal.sdmx.desktop.plugin; +import ec.util.completion.swing.JAutoCompletion; +import jdplus.sdmx.base.api.web.SdmxWebProvider; import jdplus.toolkit.desktop.plugin.TsManager; import jdplus.toolkit.desktop.plugin.completion.AutoCompletionSpi; -import jdplus.sdmx.base.api.web.SdmxWebProvider; -import ec.util.completion.swing.JAutoCompletion; -import javax.swing.text.JTextComponent; +import lombok.NonNull; import nbbrd.design.DirectImpl; import nbbrd.service.ServiceProvider; -import sdmxdl.web.SdmxWebSource; +import sdmxdl.web.WebSource; + +import javax.swing.text.JTextComponent; /** - * * @author Philippe Charles */ @DirectImpl @@ -34,20 +35,20 @@ public final class SdmxWebSourceService implements AutoCompletionSpi { @Override - public String getPath() { - return SdmxWebSource.class.getName(); + public @NonNull String getPath() { + return WebSource.class.getName(); } @Override - public JAutoCompletion bind(JTextComponent textComponent) { + public @NonNull JAutoCompletion bind(@NonNull JTextComponent textComponent) { JAutoCompletion result = new JAutoCompletion(textComponent); result.setMinLength(0); TsManager.get() .getProvider(SdmxWebProvider.class) - .ifPresent(provider -> { - SdmxAutoCompletion c = SdmxAutoCompletion.onWebSource(provider.getSdmxManager()); - result.setSource(c.getSource()); - result.getList().setCellRenderer(c.getRenderer()); + .map(SdmxAutoCompletion::onWebSource) + .ifPresent(completion -> { + result.setSource(completion.getSource()); + result.getList().setCellRenderer(completion.getRenderer()); }); return result; } diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/Toggle.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/Toggle.java new file mode 100644 index 0000000..ff82b5b --- /dev/null +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/Toggle.java @@ -0,0 +1,16 @@ +package jdplus.sdmx.desktop.plugin; + +import java.util.Properties; + +public enum Toggle { + + DEFAULT, DISABLE, ENABLE; + + public void applyTo(Properties properties, CharSequence key) { + switch (this) { + case DEFAULT -> properties.remove(key.toString()); + case DISABLE -> properties.setProperty(key.toString(), Boolean.toString(false)); + case ENABLE -> properties.setProperty(key.toString(), Boolean.toString(true)); + } + } +} diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileBeanSupport.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileBeanSupport.java index 770ad85..d01c1cc 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileBeanSupport.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileBeanSupport.java @@ -1,39 +1,30 @@ package jdplus.sdmx.desktop.plugin.file; -import com.google.common.base.Joiner; -import com.google.common.base.Splitter; +import internal.sdmx.desktop.plugin.Caches; import internal.sdmx.desktop.plugin.SdmxAutoCompletion; import jdplus.sdmx.base.api.file.SdmxFileBean; import jdplus.sdmx.base.api.file.SdmxFileProvider; import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; import jdplus.toolkit.desktop.plugin.ui.properties.FileLoaderFileFilter; -import jdplus.toolkit.desktop.plugin.util.Caches; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; -import sdmxdl.DataflowRef; import sdmxdl.Dimension; -import sdmxdl.ext.Registry; -import sdmxdl.file.SdmxFileSource; -import java.io.FileNotFoundException; import java.time.Duration; import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import java.util.Optional; import java.util.concurrent.ConcurrentMap; -import java.util.function.Supplier; import java.util.stream.Collectors; - -import static internal.sdmx.base.api.SdmxCubeItems.resolveFileSet; +import java.util.stream.Stream; @lombok.experimental.UtilityClass class SdmxFileBeanSupport { @NbBundle.Messages({ - "bean.cache.description=Mechanism used to improve performance."}) + "bean.cache.description=Mechanism used to improve performance."}) public static List newSheet(SdmxFileBean bean, SdmxFileProvider provider) { - ConcurrentMap autoCompletionCache = Caches.ttlCacheAsMap(Duration.ofMinutes(1)); + ConcurrentMap autoCompletionCache = Caches.ttlCacheAsMap(Duration.ofMinutes(1)); List result = new ArrayList<>(); NodePropertySetBuilder b = new NodePropertySetBuilder(); @@ -43,8 +34,8 @@ public static List newSheet(SdmxFileBean bean, SdmxFileProvider provi } @NbBundle.Messages({ - "bean.file.display=Data file", - "bean.file.description=The path to the sdmx data file.",}) + "bean.file.display=Data file", + "bean.file.description=The path to the sdmx data file.",}) private static NodePropertySetBuilder withSource(NodePropertySetBuilder b, SdmxFileBean bean, SdmxFileProvider provider) { b.withFile() .select("file", bean::getFile, bean::setFile) @@ -58,16 +49,16 @@ private static NodePropertySetBuilder withSource(NodePropertySetBuilder b, SdmxF } @NbBundle.Messages({ - "bean.structureFile.display=Structure file", - "bean.structureFile.description=The path to the sdmx structure file.", - "bean.dialect.display=Dialect", - "bean.dialect.description=The name of the dialect used to parse the sdmx data file.", - "bean.dimensions.display=Dataflow dimensions", - "bean.dimensions.description=An optional comma-separated list of dimensions that defines the order used to hierarchise time series.", - "bean.labelAttribute.display=Series label attribute", - "bean.labelAttribute.description=An optional attribute that carries the label of time series." + "bean.structureFile.display=Structure file", + "bean.structureFile.description=The path to the sdmx structure file.", + "bean.dialect.display=Dialect", + "bean.dialect.description=The name of the dialect used to parse the sdmx data file.", + "bean.dimensions.display=Dataflow dimensions", + "bean.dimensions.description=An optional comma-separated list of dimensions that defines the order used to hierarchise time series.", + "bean.labelAttribute.display=Series label attribute", + "bean.labelAttribute.description=An optional attribute that carries the label of time series." }) - private static NodePropertySetBuilder withOptions(NodePropertySetBuilder b, SdmxFileBean bean, SdmxFileProvider provider, ConcurrentMap autoCompletionCache) { + private static NodePropertySetBuilder withOptions(NodePropertySetBuilder b, SdmxFileBean bean, SdmxFileProvider provider, ConcurrentMap autoCompletionCache) { b.withFile() .select("structureFile", bean::getStructureFile, bean::setStructureFile) .display(Bundle.bean_structureFile_display()) @@ -77,24 +68,12 @@ private static NodePropertySetBuilder withOptions(NodePropertySetBuilder b, Sdmx .directories(false) .add(); - SdmxAutoCompletion dialect = SdmxAutoCompletion.onDialect(Registry.ofServiceLoader()); - - b.withAutoCompletion() - .select("dialect", bean::getDialect, bean::setDialect) - .source(dialect.getSource()) - .cellRenderer(dialect.getRenderer()) - .display(Bundle.bean_dialect_display()) - .description(Bundle.bean_dialect_description()) - .add(); - - Supplier toSource = () -> getFileSource(bean, provider).orElse(null); - Supplier toFlow = () -> getFileSource(bean, provider).map(SdmxFileSource::asDataflowRef).orElse(null); - - SdmxAutoCompletion dimension = SdmxAutoCompletion.onDimension(provider.getSdmxManager(), toSource, toFlow, autoCompletionCache); + SdmxAutoCompletion dimension = SdmxAutoCompletion.onDimension(provider, bean, autoCompletionCache); b.withAutoCompletion() .select(bean, "dimensions", List.class, - Joiner.on(',')::join, Splitter.on(',').trimResults().omitEmptyStrings()::splitToList) + list -> String.join(",", ((List) list)), + text -> Stream.of(text.split(",", -1)).toList()) .source(dimension.getSource()) .cellRenderer(dimension.getRenderer()) .separator(",") @@ -103,7 +82,7 @@ private static NodePropertySetBuilder withOptions(NodePropertySetBuilder b, Sdmx .description(Bundle.bean_dimensions_description()) .add(); - SdmxAutoCompletion attribute = SdmxAutoCompletion.onAttribute(provider.getSdmxManager(), toSource, toFlow, autoCompletionCache); + SdmxAutoCompletion attribute = SdmxAutoCompletion.onAttribute(provider, bean, autoCompletionCache); b.withAutoCompletion() .select("labelAttribute", bean::getLabelAttribute, bean::setLabelAttribute) @@ -114,12 +93,4 @@ private static NodePropertySetBuilder withOptions(NodePropertySetBuilder b, Sdmx .add(); return b; } - - private static Optional getFileSource(SdmxFileBean bean, SdmxFileProvider provider) { - try { - return Optional.of(resolveFileSet(provider, bean)); - } catch (FileNotFoundException ex) { - return Optional.empty(); - } - } } diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileConfiguration.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileConfiguration.java index 7b0b08f..d249c1f 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileConfiguration.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileConfiguration.java @@ -1,20 +1,22 @@ package jdplus.sdmx.desktop.plugin.file; +import internal.sdmx.desktop.plugin.SdmxIcons; +import jdplus.toolkit.base.tsp.util.PropertyHandler; import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; -import jdplus.toolkit.desktop.plugin.util.Caches; import jdplus.toolkit.desktop.plugin.util.Persistence; -import jdplus.toolkit.base.tsp.util.PropertyHandler; -import java.time.Clock; -import java.util.Locale; -import java.util.function.BiConsumer; import nbbrd.design.MightBeGenerated; +import org.openide.awt.NotificationDisplayer; import org.openide.awt.StatusDisplayer; import org.openide.nodes.Sheet; -import sdmxdl.LanguagePriorityList; -import sdmxdl.ext.Cache; +import sdmxdl.Languages; +import sdmxdl.file.FileSource; import sdmxdl.file.SdmxFileManager; -import sdmxdl.file.SdmxFileSource; -import sdmxdl.provider.ext.MapCache; +import sdmxdl.file.spi.FileCaching; +import standalone_sdmxdl.nbbrd.io.text.Parser; +import standalone_sdmxdl.sdmxdl.format.MemCachingSupport; + +import java.io.IOException; +import java.util.Locale; @lombok.Data public class SdmxFileConfiguration { @@ -38,29 +40,36 @@ public static SdmxFileConfiguration copyOf(SdmxFileConfiguration bean) { public SdmxFileManager toSdmxFileManager() { return SdmxFileManager.ofServiceLoader() .toBuilder() - .languages(toLanguages()) - .eventListener(toEventListener()) - .cache(toCache()) + .onEvent(this::reportEvent) + .onError(this::reportError) + .caching(toCaching()) .build(); } - private LanguagePriorityList toLanguages() throws IllegalArgumentException { - return languages != null ? LanguagePriorityList.parse(languages) : LanguagePriorityList.ANY; + public Languages toLanguages() { + return Parser.of(Languages::parse) + .parseValue(languages) + .orElse(Languages.ANY); } - private BiConsumer toEventListener() { - return (source, message) -> StatusDisplayer.getDefault().setStatusText(message); + + private void reportEvent(FileSource source, String marker, CharSequence message) { + StatusDisplayer.getDefault().setStatusText(message.toString()); + } + + private void reportError(FileSource source, String marker, CharSequence message, IOException error) { + NotificationDisplayer.getDefault().notify(message.toString(), SdmxIcons.getDefaultIcon(), "", null); } - private Cache toCache() { - if (noCache) { - return Cache.noOp(); - } - return MapCache.of( - Caches.softValuesCacheAsMap(), - Caches.softValuesCacheAsMap(), - Clock.systemDefaultZone() - ); + private FileCaching toCaching() { + return noCache + ? FileCaching.noOp() + : MemCachingSupport + .builder() + .id("SHARED_SOFT_MEM") +// .repositoriesOf(Caches.softValuesCacheAsMap()) +// .webMonitorsOf(Caches.softValuesCacheAsMap()) + .build(); } Sheet toSheet() { @@ -91,7 +100,7 @@ Sheet toSheet() { static final Persistence PERSISTENCE = Persistence .builderOf(SdmxFileConfiguration.class) .name("INSTANCE") - .version("VERSION") + .version("20230717") .with(PropertyHandler.onString(LANGUAGES_PROPERTY, DEFAULT_LANGUAGES), SdmxFileConfiguration::getLanguages, SdmxFileConfiguration::setLanguages) .with(PropertyHandler.onBoolean(NO_CACHE_PROPERTY, DEFAULT_NO_CACHE), SdmxFileConfiguration::isNoCache, SdmxFileConfiguration::setNoCache) .build(); diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileProviderBuddy.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileProviderBuddy.java index e3515b4..1f57799 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileProviderBuddy.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/file/SdmxFileProviderBuddy.java @@ -1,22 +1,22 @@ /* * Copyright 2017 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.sdmx.desktop.plugin.file; -import internal.sdmx.desktop.plugin.SdmxAutoCompletion; +import internal.sdmx.desktop.plugin.SdmxIcons; import jdplus.sdmx.base.api.file.SdmxFileBean; import jdplus.sdmx.base.api.file.SdmxFileProvider; import jdplus.toolkit.desktop.plugin.Config; @@ -35,7 +35,6 @@ import java.util.Optional; /** - * * @author Philippe Charles */ @DirectImpl @@ -50,17 +49,20 @@ public SdmxFileProviderBuddy() { } private void updateProvider() { - lookupProvider().ifPresent(provider -> provider.setSdmxManager(configuration.toSdmxFileManager())); + lookupProvider().ifPresent(provider -> { + provider.setSdmxManager(configuration.toSdmxFileManager()); + provider.setLanguages(configuration.toLanguages()); + }); } @Override - public String getProviderName() { + public @lombok.NonNull String getProviderName() { return SdmxFileProvider.NAME; } @Override public Image getIconOrNull(int type, boolean opened) { - return SdmxAutoCompletion.getDefaultIcon().getImage(); + return SdmxIcons.getDefaultIcon().getImage(); } @Override @@ -73,7 +75,7 @@ public void configure() { SdmxFileConfiguration editable = SdmxFileConfiguration.copyOf(configuration); PropertySheetDialogBuilder editor = new PropertySheetDialogBuilder() .title("Configure " + lookupProvider().map(SdmxFileProvider::getDisplayName).orElse("")) - .icon(SdmxAutoCompletion.getDefaultIcon()); + .icon(SdmxIcons.getDefaultIcon()); if (editor.editSheet(editable.toSheet())) { configuration = editable; updateProvider(); @@ -81,12 +83,12 @@ public void configure() { } @Override - public Config getConfig() { + public @lombok.NonNull Config getConfig() { return SdmxFileConfiguration.PERSISTENCE.loadConfig(configuration); } @Override - public void setConfig(Config config) throws IllegalArgumentException { + public void setConfig(@lombok.NonNull Config config) throws IllegalArgumentException { SdmxFileConfiguration.PERSISTENCE.storeConfig(configuration, config); updateProvider(); } diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebBeanSupport.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebBeanSupport.java index 796e804..e08a1dc 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebBeanSupport.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebBeanSupport.java @@ -1,34 +1,31 @@ package jdplus.sdmx.desktop.plugin.web; -import com.google.common.base.Joiner; -import com.google.common.base.Splitter; +import internal.sdmx.desktop.plugin.Caches; import internal.sdmx.desktop.plugin.SdmxAutoCompletion; import jdplus.sdmx.base.api.web.SdmxWebBean; import jdplus.sdmx.base.api.web.SdmxWebProvider; import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; import jdplus.toolkit.desktop.plugin.tsproviders.TsProviderProperties; -import jdplus.toolkit.desktop.plugin.util.Caches; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; -import sdmxdl.DataflowRef; import sdmxdl.Dimension; -import sdmxdl.web.SdmxWebSource; +import sdmxdl.web.WebSource; import java.time.Duration; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.concurrent.ConcurrentMap; -import java.util.function.Supplier; import java.util.stream.Collectors; +import java.util.stream.Stream; @lombok.experimental.UtilityClass class SdmxWebBeanSupport { @NbBundle.Messages({ - "bean.cache.description=Mechanism used to improve performance."}) + "bean.cache.description=Mechanism used to improve performance."}) public static List newSheet(SdmxWebBean bean, SdmxWebProvider provider) { - ConcurrentMap autoCompletionCache = Caches.ttlCacheAsMap(Duration.ofMinutes(1)); + ConcurrentMap autoCompletionCache = Caches.ttlCacheAsMap(Duration.ofMinutes(1)); List result = new ArrayList<>(); NodePropertySetBuilder b = new NodePropertySetBuilder(); @@ -39,21 +36,19 @@ public static List newSheet(SdmxWebBean bean, SdmxWebProvider provide } @NbBundle.Messages({ - "bean.source.display=Provider", - "bean.source.description=The identifier of the service that provides data.", - "bean.flow.display=Dataflow", - "bean.flow.description=The identifier of a specific dataflow.",}) - private static NodePropertySetBuilder withSource(NodePropertySetBuilder b, SdmxWebBean bean, SdmxWebProvider provider, ConcurrentMap autoCompletionCache) { + "bean.source.display=Provider", + "bean.source.description=The identifier of the service that provides data.", + "bean.flow.display=Dataflow", + "bean.flow.description=The identifier of a specific dataflow.",}) + private static NodePropertySetBuilder withSource(NodePropertySetBuilder b, SdmxWebBean bean, SdmxWebProvider provider, ConcurrentMap autoCompletionCache) { b.withAutoCompletion() .select("source", bean::getSource, bean::setSource) - .servicePath(SdmxWebSource.class.getName()) + .servicePath(WebSource.class.getName()) .display(Bundle.bean_source_display()) .description(Bundle.bean_source_description()) .add(); - Supplier toSource = () -> getWebSourceOrNull(bean, provider); - - SdmxAutoCompletion dataflow = SdmxAutoCompletion.onDataflow(provider.getSdmxManager(), toSource, autoCompletionCache); + SdmxAutoCompletion dataflow = SdmxAutoCompletion.onFlow(provider, bean, autoCompletionCache); b.withAutoCompletion() .select("flow", bean::getFlow, bean::setFlow) @@ -67,20 +62,18 @@ private static NodePropertySetBuilder withSource(NodePropertySetBuilder b, SdmxW } @NbBundle.Messages({ - "bean.dimensions.display=Dataflow dimensions", - "bean.dimensions.description=An optional comma-separated list of dimensions that defines the order used to hierarchise time series.", - "bean.labelAttribute.display=Series label attribute", - "bean.labelAttribute.description=An optional attribute that carries the label of time series." + "bean.dimensions.display=Dataflow dimensions", + "bean.dimensions.description=An optional comma-separated list of dimensions that defines the order used to hierarchise time series.", + "bean.labelAttribute.display=Series label attribute", + "bean.labelAttribute.description=An optional attribute that carries the label of time series." }) - private static NodePropertySetBuilder withOptions(NodePropertySetBuilder b, SdmxWebBean bean, SdmxWebProvider provider, ConcurrentMap autoCompletionCache) { - Supplier toSource = () -> getWebSourceOrNull(bean, provider); - Supplier toFlow = () -> getDataflowRefOrNull(bean); - - SdmxAutoCompletion dimension = SdmxAutoCompletion.onDimension(provider.getSdmxManager(), toSource, toFlow, autoCompletionCache); + private static NodePropertySetBuilder withOptions(NodePropertySetBuilder b, SdmxWebBean bean, SdmxWebProvider provider, ConcurrentMap autoCompletionCache) { + SdmxAutoCompletion dimension = SdmxAutoCompletion.onDimension(provider, bean, autoCompletionCache); b.withAutoCompletion() .select(bean, "dimensions", List.class, - Joiner.on(',')::join, Splitter.on(',').trimResults().omitEmptyStrings()::splitToList) + list -> String.join(",", ((List) list)), + text -> Stream.of(text.split(",", -1)).toList()) .source(dimension.getSource()) .cellRenderer(dimension.getRenderer()) .separator(",") @@ -89,7 +82,7 @@ private static NodePropertySetBuilder withOptions(NodePropertySetBuilder b, Sdmx .description(Bundle.bean_dimensions_description()) .add(); - SdmxAutoCompletion attribute = SdmxAutoCompletion.onAttribute(provider.getSdmxManager(), toSource, toFlow, autoCompletionCache); + SdmxAutoCompletion attribute = SdmxAutoCompletion.onAttribute(provider, bean, autoCompletionCache); b.withAutoCompletion() .select("labelAttribute", bean::getLabelAttribute, bean::setLabelAttribute) @@ -106,16 +99,4 @@ private static NodePropertySetBuilder withCache(NodePropertySetBuilder b, SdmxWe TsProviderProperties.addBulkCube(b, bean::getCache, bean::setCache); return b; } - - private static SdmxWebSource getWebSourceOrNull(SdmxWebBean bean, SdmxWebProvider provider) { - return provider.getSdmxManager().getSources().get(bean.getSource()); - } - - private static DataflowRef getDataflowRefOrNull(SdmxWebBean bean) { - try { - return DataflowRef.parse(bean.getFlow()); - } catch (IllegalArgumentException ex) { - return null; - } - } } diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebConfiguration.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebConfiguration.java index 86c089e..2a4f75a 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebConfiguration.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebConfiguration.java @@ -1,27 +1,21 @@ package jdplus.sdmx.desktop.plugin.web; -import internal.sdmx.desktop.plugin.CustomNetwork; -import internal.sdmx.desktop.plugin.SdmxAutoCompletion; +import internal.sdmx.desktop.plugin.SdmxIcons; +import jdplus.sdmx.desktop.plugin.Toggle; import jdplus.toolkit.base.tsp.util.PropertyHandler; -import jdplus.toolkit.desktop.plugin.notification.MessageUtil; import jdplus.toolkit.desktop.plugin.properties.NodePropertySetBuilder; import jdplus.toolkit.desktop.plugin.util.Persistence; import nbbrd.design.MightBeGenerated; import org.openide.awt.NotificationDisplayer; import org.openide.awt.StatusDisplayer; import org.openide.nodes.Sheet; -import sdmxdl.DataRepository; -import sdmxdl.LanguagePriorityList; -import sdmxdl.ext.Cache; -import sdmxdl.format.FileFormat; -import sdmxdl.format.spi.FileFormatProvider; -import sdmxdl.format.spi.FileFormatProviderLoader; -import sdmxdl.format.xml.XmlWebSource; -import sdmxdl.provider.ext.FileCache; -import sdmxdl.provider.ext.VerboseCache; -import sdmxdl.web.MonitorReports; +import sdmxdl.Languages; import sdmxdl.web.SdmxWebManager; -import sdmxdl.web.SdmxWebSource; +import sdmxdl.web.WebSource; +import standalone_sdmxdl.nbbrd.io.text.Parser; +import standalone_sdmxdl.sdmxdl.provider.ri.caching.RiCaching; +import standalone_sdmxdl.sdmxdl.provider.ri.drivers.SourceProperties; +import standalone_sdmxdl.sdmxdl.provider.ri.networking.RiNetworking; import javax.swing.filechooser.FileNameExtensionFilter; import java.io.File; @@ -29,7 +23,7 @@ import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.function.BiConsumer; +import java.util.Properties; @lombok.Data public class SdmxWebConfiguration { @@ -43,24 +37,28 @@ public class SdmxWebConfiguration { private String languages = DEFAULT_LANGUAGES; private static final String CURL_BACKEND_PROPERTY = "curlBackend"; - private static final boolean DEFAULT_CURL_BACKEND = false; - private boolean curlBackend = DEFAULT_CURL_BACKEND; + private static final Toggle DEFAULT_CURL_BACKEND = Toggle.DEFAULT; + private Toggle curlBackend = DEFAULT_CURL_BACKEND; private static final String NO_CACHE_PROPERTY = "noCache"; - private static final boolean DEFAULT_NO_CACHE = false; - private boolean noCache = DEFAULT_NO_CACHE; + private static final Toggle DEFAULT_NO_CACHE = Toggle.DEFAULT; + private Toggle noCache = DEFAULT_NO_CACHE; private static final String AUTO_PROXY_PROPERTY = "autoProxy"; - private static final boolean DEFAULT_AUTO_PROXY = false; - private boolean autoProxy = DEFAULT_AUTO_PROXY; + private static final Toggle DEFAULT_AUTO_PROXY = Toggle.DEFAULT; + private Toggle autoProxy = DEFAULT_AUTO_PROXY; private static final String NO_DEFAULT_SSL_PROPERTY = "noDefaultSSL"; - private static final boolean DEFAULT_NO_DEFAULT_SSL = false; - private boolean noDefaultSSL = DEFAULT_NO_DEFAULT_SSL; + private static final Toggle DEFAULT_NO_DEFAULT_SSL = Toggle.DEFAULT; + private Toggle noDefaultSSL = DEFAULT_NO_DEFAULT_SSL; private static final String NO_SYSTEM_SSL_PROPERTY = "noSystemSSL"; - private static final boolean DEFAULT_NO_SYSTEM_SSL = false; - private boolean noSystemSSL = DEFAULT_NO_SYSTEM_SSL; + private static final Toggle DEFAULT_NO_SYSTEM_SSL = Toggle.DEFAULT; + private Toggle noSystemSSL = DEFAULT_NO_SYSTEM_SSL; + + private static final String DISPLAY_CODES_PROPERTY = "displayCodes"; + private static final boolean DEFAULT_DISPLAY_CODES = false; + private boolean displayCodes = DEFAULT_DISPLAY_CODES; @MightBeGenerated public static SdmxWebConfiguration copyOf(SdmxWebConfiguration bean) { @@ -72,79 +70,47 @@ public static SdmxWebConfiguration copyOf(SdmxWebConfiguration bean) { result.autoProxy = bean.autoProxy; result.noDefaultSSL = bean.noDefaultSSL; result.noSystemSSL = bean.noSystemSSL; + result.displayCodes = bean.displayCodes; return result; } - SdmxWebManager toSdmxWebManager() { - return SdmxWebManager.ofServiceLoader() - .toBuilder() - .languages(toLanguages()) - .eventListener(toEventListener()) - .cache(toCache()) - .network(toNetwork()) - .customSources(toSources()) - .build(); - } - - private LanguagePriorityList toLanguages() throws IllegalArgumentException { - return languages != null ? LanguagePriorityList.parse(languages) : LanguagePriorityList.ANY; - } + public SdmxWebManager toSdmxWebManager() { + Properties properties = System.getProperties(); - private BiConsumer toEventListener() { - return (source, message) -> StatusDisplayer.getDefault().setStatusText(message); - } + curlBackend.applyTo(properties, RiNetworking.CURL_BACKEND_PROPERTY); + noCache.applyTo(properties, RiCaching.NO_CACHE_PROPERTY); + autoProxy.applyTo(properties, RiNetworking.AUTO_PROXY_PROPERTY); + noDefaultSSL.applyTo(properties, RiNetworking.NO_DEFAULT_SSL_PROPERTY); + noSystemSSL.applyTo(properties, RiNetworking.NO_SYSTEM_SSL_PROPERTY); - private Cache toCache() { - if (noCache) { - return Cache.noOp(); - } - Cache cache = getCache(false); - return getVerboseCache(cache, true); - } - - private CustomNetwork toNetwork() { - return CustomNetwork - .builder() - .curlBackend(curlBackend) - .autoProxy(autoProxy) - .defaultTrustMaterial(!noDefaultSSL) - .systemTrustMaterial(!noSystemSSL) + return SdmxWebManager.ofServiceLoader() + .toBuilder() + .onEvent(this::reportEvent) + .onError(this::reportError) + .customSources(getCustomSources()) .build(); } - private List toSources() { - if (sources != null && sources.exists()) { - try { - return XmlWebSource.getParser().parseFile(sources); - } catch (IOException ex) { - MessageUtil.showException("Cannot load custom sources", ex); - } + private static List getCustomSources() { + try { + return SourceProperties.loadCustomSources(); + } catch (IOException e) { + return Collections.emptyList(); } - return Collections.emptyList(); } - private static Cache getCache(boolean noCacheCompression) { - FileFormatProvider formatProvider = FileFormatProviderLoader.load().stream().findFirst().orElseThrow(RuntimeException::new); - FileFormat repositoryFormat = formatProvider.getDataRepositoryFormat(); - FileFormat monitorFormat = formatProvider.getMonitorReportsFormat(); - return FileCache - .builder() - .repositoryFormat(noCacheCompression ? repositoryFormat : FileFormat.gzip(repositoryFormat)) - .monitorFormat(noCacheCompression ? monitorFormat : FileFormat.gzip(monitorFormat)) - .onIOException(SdmxWebConfiguration::reportIOException) - .build(); + public Languages toLanguages() { + return Parser.of(Languages::parse) + .parseValue(languages) + .orElse(Languages.ANY); } - private static void reportIOException(String message, IOException error) { - NotificationDisplayer.getDefault().notify(message, SdmxAutoCompletion.getDefaultIcon(), "", null); + private void reportEvent(WebSource source, String marker, CharSequence message) { + StatusDisplayer.getDefault().setStatusText(message.toString()); } - private static Cache getVerboseCache(Cache delegate, boolean verbose) { - if (verbose) { - BiConsumer listener = (key, hit) -> StatusDisplayer.getDefault().setStatusText((hit ? "Hit " : "Miss ") + key); - return new VerboseCache(delegate, listener, listener); - } - return delegate; + private void reportError(WebSource source, String marker, CharSequence message, IOException error) { + NotificationDisplayer.getDefault().notify(message.toString(), SdmxIcons.getDefaultIcon(), "", null); } Sheet toSheet() { @@ -168,27 +134,27 @@ Sheet toSheet() { result.put(b.build()); b.reset("Network"); - b.withBoolean() + b.withEnum(Toggle.class) .select(this, CURL_BACKEND_PROPERTY) .display("Curl backend") .description("Use curl backend instead of JDK") .add(); - b.withBoolean() + b.withEnum(Toggle.class) .select(this, NO_CACHE_PROPERTY) .display("No cache") .description("Disable caching") .add(); - b.withBoolean() + b.withEnum(Toggle.class) .select(this, AUTO_PROXY_PROPERTY) .display("Auto proxy") .description("Enable automatic proxy detection") .add(); - b.withBoolean() + b.withEnum(Toggle.class) .select(this, NO_DEFAULT_SSL_PROPERTY) .display("No default SSL") .description("Disable default truststore") .add(); - b.withBoolean() + b.withEnum(Toggle.class) .select(this, NO_SYSTEM_SSL_PROPERTY) .display("No system SSL") .description("Disable system truststore") @@ -202,13 +168,14 @@ Sheet toSheet() { static final Persistence PERSISTENCE = Persistence .builderOf(SdmxWebConfiguration.class) .name("INSTANCE") - .version("VERSION") + .version("20230717") .with(PropertyHandler.onFile(SOURCES_PROPERTY, DEFAULT_SOURCES), SdmxWebConfiguration::getSources, SdmxWebConfiguration::setSources) .with(PropertyHandler.onString(LANGUAGES_PROPERTY, DEFAULT_LANGUAGES), SdmxWebConfiguration::getLanguages, SdmxWebConfiguration::setLanguages) - .with(PropertyHandler.onBoolean(CURL_BACKEND_PROPERTY, DEFAULT_CURL_BACKEND), SdmxWebConfiguration::isCurlBackend, SdmxWebConfiguration::setCurlBackend) - .with(PropertyHandler.onBoolean(NO_CACHE_PROPERTY, DEFAULT_NO_CACHE), SdmxWebConfiguration::isNoCache, SdmxWebConfiguration::setNoCache) - .with(PropertyHandler.onBoolean(AUTO_PROXY_PROPERTY, DEFAULT_AUTO_PROXY), SdmxWebConfiguration::isAutoProxy, SdmxWebConfiguration::setAutoProxy) - .with(PropertyHandler.onBoolean(NO_DEFAULT_SSL_PROPERTY, DEFAULT_NO_DEFAULT_SSL), SdmxWebConfiguration::isNoDefaultSSL, SdmxWebConfiguration::setNoDefaultSSL) - .with(PropertyHandler.onBoolean(NO_SYSTEM_SSL_PROPERTY, DEFAULT_NO_SYSTEM_SSL), SdmxWebConfiguration::isNoSystemSSL, SdmxWebConfiguration::setNoSystemSSL) + .with(PropertyHandler.onEnum(CURL_BACKEND_PROPERTY, DEFAULT_CURL_BACKEND), SdmxWebConfiguration::getCurlBackend, SdmxWebConfiguration::setCurlBackend) + .with(PropertyHandler.onEnum(NO_CACHE_PROPERTY, DEFAULT_NO_CACHE), SdmxWebConfiguration::getNoCache, SdmxWebConfiguration::setNoCache) + .with(PropertyHandler.onEnum(AUTO_PROXY_PROPERTY, DEFAULT_AUTO_PROXY), SdmxWebConfiguration::getAutoProxy, SdmxWebConfiguration::setAutoProxy) + .with(PropertyHandler.onEnum(NO_DEFAULT_SSL_PROPERTY, DEFAULT_NO_DEFAULT_SSL), SdmxWebConfiguration::getNoDefaultSSL, SdmxWebConfiguration::setNoDefaultSSL) + .with(PropertyHandler.onEnum(NO_SYSTEM_SSL_PROPERTY, DEFAULT_NO_SYSTEM_SSL), SdmxWebConfiguration::getNoSystemSSL, SdmxWebConfiguration::setNoSystemSSL) + .with(PropertyHandler.onBoolean(DISPLAY_CODES_PROPERTY, DEFAULT_DISPLAY_CODES), SdmxWebConfiguration::isDisplayCodes, SdmxWebConfiguration::setDisplayCodes) .build(); } diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebProviderBuddy.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebProviderBuddy.java index b15ebfc..869d30e 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebProviderBuddy.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/SdmxWebProviderBuddy.java @@ -17,7 +17,7 @@ package jdplus.sdmx.desktop.plugin.web; import ec.util.various.swing.FontAwesome; -import internal.sdmx.desktop.plugin.SdmxAutoCompletion; +import internal.sdmx.desktop.plugin.SdmxIcons; import jdplus.sdmx.base.api.web.SdmxWebBean; import jdplus.sdmx.base.api.web.SdmxWebProvider; import jdplus.toolkit.base.api.timeseries.TsMoniker; @@ -36,7 +36,7 @@ import org.openide.util.ImageUtilities; import sdmxdl.Connection; import sdmxdl.Feature; -import sdmxdl.web.SdmxWebSource; +import sdmxdl.web.WebSource; import java.awt.*; import java.io.IOException; @@ -63,26 +63,30 @@ public SdmxWebProviderBuddy() { } private void updateProvider() { - lookupProvider().ifPresent(provider -> provider.setSdmxManager(configuration.toSdmxWebManager())); + lookupProvider().ifPresent(provider -> { + provider.setSdmxManager(configuration.toSdmxWebManager()); + provider.setLanguages(configuration.toLanguages()); + provider.setDisplayCodes(configuration.isDisplayCodes()); + }); } @Override - public String getProviderName() { + public @lombok.NonNull String getProviderName() { return SOURCE; } @Override public Image getIconOrNull(int type, boolean opened) { - return SdmxAutoCompletion.getDefaultIcon().getImage(); + return SdmxIcons.getDefaultIcon().getImage(); } @Override - public Image getIconOrNull(DataSource dataSource, int type, boolean opened) { + public Image getIconOrNull(@lombok.NonNull DataSource dataSource, int type, boolean opened) { Optional lookupProvider = lookupProvider(); if (lookupProvider.isPresent()) { SdmxWebProvider provider = lookupProvider.orElseThrow(); SdmxWebBean bean = provider.decodeBean(dataSource); - SdmxWebSource source = provider.getSdmxManager().getSources().get(bean.getSource()); + WebSource source = provider.getSdmxManager().getSources().get(bean.getSource()); if (source != null) { Image result = getSourceIcon(provider, source); return supportsDataQueryDetail(provider, source) @@ -94,14 +98,14 @@ public Image getIconOrNull(DataSource dataSource, int type, boolean opened) { } @Override - public Image getIconOrNull(TsMoniker moniker, int type, boolean opened) { + public Image getIconOrNull(@lombok.NonNull TsMoniker moniker, int type, boolean opened) { Optional lookupProvider = lookupProvider(); if (lookupProvider.isPresent()) { SdmxWebProvider provider = lookupProvider.orElseThrow(); Optional dataSet = provider.toDataSet(moniker); if (dataSet.isPresent()) { SdmxWebBean bean = provider.decodeBean(dataSet.orElseThrow().getDataSource()); - SdmxWebSource source = provider.getSdmxManager().getSources().get(bean.getSource()); + WebSource source = provider.getSdmxManager().getSources().get(bean.getSource()); if (source != null) { return getSourceIcon(provider, source); } @@ -120,7 +124,7 @@ public void configure() { SdmxWebConfiguration editable = SdmxWebConfiguration.copyOf(configuration); PropertySheetDialogBuilder editor = new PropertySheetDialogBuilder() .title("Configure " + lookupProvider().map(SdmxWebProvider::getDisplayName).orElse("")) - .icon(SdmxAutoCompletion.getDefaultIcon()); + .icon(SdmxIcons.getDefaultIcon()); if (editor.editSheet(editable.toSheet())) { configuration = editable; updateProvider(); @@ -128,12 +132,12 @@ public void configure() { } @Override - public Config getConfig() { + public @lombok.NonNull Config getConfig() { return SdmxWebConfiguration.PERSISTENCE.loadConfig(configuration); } @Override - public void setConfig(Config config) throws IllegalArgumentException { + public void setConfig(@lombok.NonNull Config config) throws IllegalArgumentException { SdmxWebConfiguration.PERSISTENCE.storeConfig(configuration, config); updateProvider(); } @@ -142,12 +146,12 @@ private List getSheetOrNull(SdmxWebBean bean) { return lookupProvider().map(provider -> SdmxWebBeanSupport.newSheet(bean, provider)).orElse(null); } - private static Image getSourceIcon(SdmxWebProvider provider, SdmxWebSource source) { - return ImageUtilities.icon2Image(SdmxAutoCompletion.getFavicon(source.getWebsite())); + private static Image getSourceIcon(SdmxWebProvider provider, WebSource source) { + return ImageUtilities.icon2Image(SdmxIcons.getFavicon(provider.getSdmxManager().getNetworking(), source.getWebsite())); } - private static boolean supportsDataQueryDetail(SdmxWebProvider provider, SdmxWebSource source) { - try ( Connection conn = provider.getSdmxManager().getConnection(source)) { + private static boolean supportsDataQueryDetail(SdmxWebProvider provider, WebSource source) { + try (Connection conn = provider.getSdmxManager().getConnection(source, provider.getLanguages())) { return conn.getSupportedFeatures().contains(Feature.DATA_QUERY_DETAIL); } catch (IOException ex) { return false; diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/JSdmxWebSourcePanel.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/JSdmxWebSourcePanel.java similarity index 82% rename from jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/JSdmxWebSourcePanel.java rename to jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/JSdmxWebSourcePanel.java index 36fb13e..7a78227 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/JSdmxWebSourcePanel.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/JSdmxWebSourcePanel.java @@ -1,19 +1,5 @@ -package jdplus.sdmx.desktop.plugin.web; +package jdplus.sdmx.desktop.plugin.web.actions; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import jdplus.toolkit.desktop.plugin.ColorSchemeManager; -import jdplus.toolkit.desktop.plugin.TsManager; -import jdplus.main.desktop.design.SwingAction; -import jdplus.main.desktop.design.SwingComponent; -import jdplus.main.desktop.design.SwingProperty; -import jdplus.toolkit.desktop.plugin.tsproviders.DataSourceManager; -import jdplus.toolkit.desktop.plugin.util.ActionMaps; -import jdplus.toolkit.desktop.plugin.util.FontAwesomeUtils; -import jdplus.toolkit.desktop.plugin.util.InputMaps; -import jdplus.toolkit.desktop.plugin.util.KeyStrokes; -import jdplus.toolkit.desktop.plugin.util.ListTableModel; -import jdplus.sdmx.base.api.web.SdmxWebBean; -import jdplus.sdmx.base.api.web.SdmxWebProvider; import ec.util.chart.ColorScheme; import ec.util.chart.swing.SwingColorSchemeSupport; import ec.util.desktop.Desktop; @@ -21,42 +7,44 @@ import ec.util.table.swing.JTables; import ec.util.various.swing.FontAwesome; import ec.util.various.swing.JCommand; -import ec.util.various.swing.OnAnyThread; -import ec.util.various.swing.OnEDT; import ec.util.various.swing.StandardSwingColor; -import internal.sdmx.desktop.plugin.SdmxAutoCompletion; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Font; +import internal.sdmx.desktop.plugin.SdmxIcons; +import jdplus.main.desktop.design.SwingAction; +import jdplus.main.desktop.design.SwingComponent; +import jdplus.main.desktop.design.SwingProperty; +import jdplus.sdmx.base.api.web.SdmxWebBean; +import jdplus.sdmx.base.api.web.SdmxWebProvider; +import jdplus.toolkit.desktop.plugin.ColorSchemeManager; +import jdplus.toolkit.desktop.plugin.TsManager; +import jdplus.toolkit.desktop.plugin.concurrent.DefaultThreadFactory; +import jdplus.toolkit.desktop.plugin.tsproviders.DataSourceManager; +import jdplus.toolkit.desktop.plugin.util.*; +import nbbrd.design.swing.OnAnyThread; +import nbbrd.design.swing.OnEDT; +import org.netbeans.swing.etable.ETable; +import org.openide.awt.StatusDisplayer; +import org.openide.util.Exceptions; +import sdmxdl.Languages; +import sdmxdl.web.MonitorReport; +import sdmxdl.web.MonitorStatus; +import sdmxdl.web.SdmxWebManager; +import sdmxdl.web.WebSource; +import standalone_sdmxdl.nbbrd.io.text.Formatter; + +import javax.swing.*; +import javax.swing.table.DefaultTableCellRenderer; +import java.awt.*; import java.beans.BeanInfo; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.text.NumberFormat; +import java.util.List; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Supplier; import java.util.stream.Collectors; -import javax.swing.ActionMap; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.SwingUtilities; -import javax.swing.table.DefaultTableCellRenderer; -import nbbrd.io.text.Formatter; -import org.netbeans.swing.etable.ETable; -import org.openide.awt.StatusDisplayer; -import org.openide.util.Exceptions; -import sdmxdl.LanguagePriorityList; -import sdmxdl.web.MonitorReport; -import sdmxdl.web.MonitorStatus; -import sdmxdl.web.SdmxWebManager; -import sdmxdl.web.SdmxWebSource; @SwingComponent public final class JSdmxWebSourcePanel extends JComponent { @@ -83,6 +71,19 @@ public void setSdmxManager(SdmxWebManager sdmxManager) { firePropertyChange(SDMX_MANAGER_PROPERTY, this.sdmxManager, this.sdmxManager = (sdmxManager != null ? sdmxManager : DEFAULT_SDMX_MANAGER.get())); } + @SwingProperty + public static final String LANGUAGES_PROPERTY = "sdmxManager"; + private static final Supplier DEFAULT_LANGUAGES = () -> Languages.ANY; + private Languages languages = DEFAULT_LANGUAGES.get(); + + public Languages getLanguages() { + return languages; + } + + public void setLanguages(Languages languages) { + firePropertyChange(LANGUAGES_PROPERTY, this.languages, this.languages = (languages != null ? languages : DEFAULT_LANGUAGES.get())); + } + private final ETable table; private StatusSupport support; @@ -138,7 +139,7 @@ private void initSupport() { support = StatusSupport .builder() .sdmxManager(sdmxManager) - .executor(Executors.newCachedThreadPool(new ThreadFactoryBuilder().setDaemon(true).setPriority(Thread.MIN_PRIORITY).build())) + .executor(Executors.newCachedThreadPool(DefaultThreadFactory.builder().daemon(true).priority(Thread.MIN_PRIORITY).build())) .cache(new HashMap<>()) .fallback(MonitorReport.builder().source("").status(MonitorStatus.UNKNOWN).build()) .build(); @@ -165,7 +166,7 @@ private void onSdmxManagerChange() { support = support.toBuilder().sdmxManager(sdmxManager).build(); ((WebSourceModel) table.getModel()).setValues( sdmxManager.getSources().values().stream().filter(source -> !source.isAlias()).collect(Collectors.toList()), - sdmxManager.getLanguages() + languages ); } @@ -198,9 +199,9 @@ private DefaultTableCellRenderer newNameRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JLabel result = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - if (value instanceof SdmxWebSource source) { + if (value instanceof WebSource source) { result.setText(source.getId()); - result.setIcon(SdmxAutoCompletion.getFavicon(source.getWebsite(), table::repaint)); + result.setIcon(SdmxIcons.getFavicon(sdmxManager.getNetworking(), source.getWebsite(), table::repaint)); } return result; } @@ -214,18 +215,18 @@ private DefaultTableCellRenderer newStatusRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JLabel result = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - if (value instanceof SdmxWebSource source) { + if (value instanceof WebSource source) { MonitorReport report = support.get(source, table::repaint); result.setText(""); result.setToolTipText(uptimeRatioFormatter.formatAsString(report.getUptimeRatio()) + " uptime"); SwingColorSchemeSupport colors = ColorSchemeManager.get().getSupport(ColorSchemeManager.get().getMainColorScheme()); switch (report.getStatus()) { case DOWN -> - result.setIcon(FontAwesome.FA_TIMES_CIRCLE.getIcon(colors.getAreaColor(ColorScheme.KnownColor.RED), FontAwesomeUtils.toSize(BeanInfo.ICON_COLOR_16x16))); + result.setIcon(FontAwesome.FA_TIMES_CIRCLE.getIcon(colors.getAreaColor(ColorScheme.KnownColor.RED), FontAwesomeUtils.toSize(BeanInfo.ICON_COLOR_16x16))); case UNKNOWN -> - result.setIcon(FontAwesome.FA_QUESTION_CIRCLE.getIcon(colors.getAreaColor(ColorScheme.KnownColor.ORANGE), FontAwesomeUtils.toSize(BeanInfo.ICON_COLOR_16x16))); + result.setIcon(FontAwesome.FA_QUESTION_CIRCLE.getIcon(colors.getAreaColor(ColorScheme.KnownColor.ORANGE), FontAwesomeUtils.toSize(BeanInfo.ICON_COLOR_16x16))); case UP -> - result.setIcon(FontAwesome.FA_CHECK_CIRCLE.getIcon(colors.getAreaColor(ColorScheme.KnownColor.GREEN), FontAwesomeUtils.toSize(BeanInfo.ICON_COLOR_16x16))); + result.setIcon(FontAwesome.FA_CHECK_CIRCLE.getIcon(colors.getAreaColor(ColorScheme.KnownColor.GREEN), FontAwesomeUtils.toSize(BeanInfo.ICON_COLOR_16x16))); } } return result; @@ -248,7 +249,7 @@ private static class StatusSupport { private final Map cache; @OnEDT - public MonitorReport get(SdmxWebSource url, Runnable onUpdate) { + public MonitorReport get(WebSource url, Runnable onUpdate) { return url != null ? cache.computeIfAbsent(url.getId(), host -> request(url, onUpdate)) : fallback; } @@ -258,13 +259,13 @@ public MonitorReport getOrNull(URL url) { } @OnEDT - private MonitorReport request(SdmxWebSource url, Runnable onUpdate) { + private MonitorReport request(WebSource url, Runnable onUpdate) { executor.execute(() -> loadIntoCache(url, onUpdate)); return fallback; } @OnAnyThread - private void loadIntoCache(SdmxWebSource url, Runnable onUpdate) { + private void loadIntoCache(WebSource url, Runnable onUpdate) { MonitorReport favicon = load(url); if (favicon != null) { SwingUtilities.invokeLater(() -> { @@ -275,7 +276,7 @@ private void loadIntoCache(SdmxWebSource url, Runnable onUpdate) { } @OnAnyThread - private MonitorReport load(SdmxWebSource url) { + private MonitorReport load(WebSource url) { report("Loading favicon for " + url.getId()); try { return sdmxManager.getMonitorReport(url); @@ -291,12 +292,12 @@ private void report(String message) { } } - private static final class WebSourceModel extends ListTableModel { + private static final class WebSourceModel extends ListTableModel { - private List values = Collections.emptyList(); - private LanguagePriorityList languages = LanguagePriorityList.ANY; + private List values = Collections.emptyList(); + private Languages languages = Languages.ANY; - public void setValues(List values, LanguagePriorityList languages) { + public void setValues(List values, Languages languages) { this.values = values; this.languages = languages; fireTableDataChanged(); @@ -308,12 +309,12 @@ protected List getColumnNames() { } @Override - protected List getValues() { + protected List getValues() { return values; } @Override - protected Object getValueAt(SdmxWebSource row, int columnIndex) { + protected Object getValueAt(WebSource row, int columnIndex) { switch (columnIndex) { case 0: return row; @@ -336,7 +337,7 @@ private static final class OpenCommand extends JCommand { @Override public void execute(JSdmxWebSourcePanel c) throws Exception { int idx = c.table.convertRowIndexToModel(c.table.getSelectedRow()); - SdmxWebSource source = ((WebSourceModel) c.table.getModel()).getValues().get(idx); + WebSource source = ((WebSourceModel) c.table.getModel()).getValues().get(idx); TsManager.get().getProvider(SdmxWebProvider.class).ifPresent(provider -> { SdmxWebBean bean = provider.newBean(); bean.setSource(source.getId()); @@ -382,7 +383,7 @@ public JCommand.ActionAdapter toAction(JSdmxWebSourcePanel c) { return super.toAction(c).withWeakListSelectionListener(c.table.getSelectionModel()); } - private SdmxWebSource getSelection(JSdmxWebSourcePanel c) { + private WebSource getSelection(JSdmxWebSourcePanel c) { int idx = c.table.convertRowIndexToModel(c.table.getSelectedRow()); return ((WebSourceModel) c.table.getModel()).getValues().get(idx); } @@ -413,7 +414,7 @@ public JCommand.ActionAdapter toAction(JSdmxWebSourcePanel c) { return super.toAction(c).withWeakListSelectionListener(c.table.getSelectionModel()); } - private SdmxWebSource getSelection(JSdmxWebSourcePanel c) { + private WebSource getSelection(JSdmxWebSourcePanel c) { int idx = c.table.convertRowIndexToModel(c.table.getSelectedRow()); return ((WebSourceModel) c.table.getModel()).getValues().get(idx); } diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/ListSourcesAction.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/ListSourcesAction.java similarity index 89% rename from jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/ListSourcesAction.java rename to jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/ListSourcesAction.java index 977f520..cdd5377 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/ListSourcesAction.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/ListSourcesAction.java @@ -1,29 +1,30 @@ -package jdplus.sdmx.desktop.plugin.web; +package jdplus.sdmx.desktop.plugin.web.actions; -import jdplus.toolkit.desktop.plugin.actions.AbilityNodeAction; -import jdplus.toolkit.desktop.plugin.actions.Actions; -import static jdplus.toolkit.desktop.plugin.tsproviders.TsProviderNodes.PROVIDER_ACTION_PATH; import jdplus.sdmx.base.api.web.SdmxWebProvider; import jdplus.toolkit.base.tsp.DataSourceProvider; -import java.awt.BorderLayout; +import jdplus.toolkit.desktop.plugin.actions.AbilityNodeAction; +import jdplus.toolkit.desktop.plugin.actions.Actions; import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; import org.openide.awt.ActionRegistration; import org.openide.util.NbBundle.Messages; - -import java.util.stream.Stream; -import javax.swing.JMenuItem; -import org.openide.awt.ActionReference; import org.openide.util.actions.Presenter; import org.openide.windows.TopComponent; import sdmxdl.web.SdmxWebManager; +import javax.swing.*; +import java.awt.*; +import java.util.stream.Stream; + +import static jdplus.toolkit.desktop.plugin.tsproviders.TsProviderNodes.PROVIDER_ACTION_PATH; + @ActionID(category = "Edit", id = ListSourcesAction.ID) @ActionRegistration(displayName = "#CTL_ListSourcesAction", lazy = false) @Messages("CTL_ListSourcesAction=List sources") @ActionReference(path = PROVIDER_ACTION_PATH, position = 530, separatorBefore = 500, id = @ActionID(category = "Edit", id = ListSourcesAction.ID)) public final class ListSourcesAction extends AbilityNodeAction implements Presenter.Popup { - public static final String ID = "demetra.desktop.extra.sdmx.web.ListSourcesAction"; + static final String ID = "jdplus.sdmx.desktop.plugin.web.actions.ListSourcesAction"; public ListSourcesAction() { super(DataSourceProvider.class, true); @@ -37,7 +38,7 @@ public JMenuItem getPopupPresenter() { @Override protected void performAction(Stream items) { items.map(SdmxWebProvider.class::cast).forEach(item -> { - createComponent("SdmxWebSource", item.getSdmxManager()); + createComponent("WebSource", item.getSdmxManager()); }); } diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/OpenMonitorAction.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/OpenMonitorAction.java similarity index 88% rename from jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/OpenMonitorAction.java rename to jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/OpenMonitorAction.java index 03af783..8805707 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/OpenMonitorAction.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/OpenMonitorAction.java @@ -1,26 +1,27 @@ -package jdplus.sdmx.desktop.plugin.web; +package jdplus.sdmx.desktop.plugin.web.actions; +import ec.util.desktop.Desktop; +import ec.util.desktop.DesktopManager; +import jdplus.sdmx.base.api.web.SdmxWebProvider; +import jdplus.toolkit.base.tsp.DataSource; import jdplus.toolkit.desktop.plugin.TsManager; import jdplus.toolkit.desktop.plugin.actions.AbilityNodeAction; import jdplus.toolkit.desktop.plugin.actions.Actions; -import static jdplus.toolkit.desktop.plugin.tsproviders.TsProviderNodes.SOURCE_ACTION_PATH; -import jdplus.sdmx.base.api.web.SdmxWebProvider; -import jdplus.toolkit.base.tsp.DataSource; -import ec.util.desktop.Desktop; -import ec.util.desktop.DesktopManager; import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; import org.openide.awt.ActionRegistration; import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.Presenter; +import sdmxdl.web.WebSource; +import javax.swing.*; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.util.stream.Stream; -import javax.swing.JMenuItem; -import org.openide.awt.ActionReference; -import org.openide.util.actions.Presenter; -import sdmxdl.web.SdmxWebSource; + +import static jdplus.toolkit.desktop.plugin.tsproviders.TsProviderNodes.SOURCE_ACTION_PATH; @ActionID(category = "Edit", id = OpenMonitorAction.ID) @ActionRegistration(displayName = "#CTL_OpenMonitorAction", lazy = false) @@ -28,7 +29,7 @@ @ActionReference(path = SOURCE_ACTION_PATH, position = 730, separatorBefore = 700, id = @ActionID(category = "Edit", id = OpenMonitorAction.ID)) public final class OpenMonitorAction extends AbilityNodeAction implements Presenter.Popup { - public static final String ID = "demetra.desktop.extra.sdmx.web.OpenMonitorAction"; + static final String ID = "jdplus.sdmx.desktop.plugin.web.actions.OpenMonitorAction"; public OpenMonitorAction() { super(DataSource.class, true); @@ -64,7 +65,7 @@ private URL getMonitorWebsite(DataSource dataSource) { } private URL getMonitorWebsite(SdmxWebProvider provider, DataSource dataSource) { - SdmxWebSource source = provider.getSdmxManager().getSources().get(provider.decodeBean(dataSource).getSource()); + WebSource source = provider.getSdmxManager().getSources().get(provider.decodeBean(dataSource).getSource()); return source != null ? source.getMonitorWebsite() : null; } diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/OpenWebsiteAction.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/OpenWebsiteAction.java similarity index 88% rename from jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/OpenWebsiteAction.java rename to jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/OpenWebsiteAction.java index 19b8076..e3c0b20 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/OpenWebsiteAction.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/main/java/jdplus/sdmx/desktop/plugin/web/actions/OpenWebsiteAction.java @@ -1,26 +1,27 @@ -package jdplus.sdmx.desktop.plugin.web; +package jdplus.sdmx.desktop.plugin.web.actions; +import ec.util.desktop.Desktop; +import ec.util.desktop.DesktopManager; +import jdplus.sdmx.base.api.web.SdmxWebProvider; +import jdplus.toolkit.base.tsp.DataSource; import jdplus.toolkit.desktop.plugin.TsManager; import jdplus.toolkit.desktop.plugin.actions.AbilityNodeAction; import jdplus.toolkit.desktop.plugin.actions.Actions; -import static jdplus.toolkit.desktop.plugin.tsproviders.TsProviderNodes.SOURCE_ACTION_PATH; -import jdplus.sdmx.base.api.web.SdmxWebProvider; -import jdplus.toolkit.base.tsp.DataSource; -import ec.util.desktop.Desktop; -import ec.util.desktop.DesktopManager; import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; import org.openide.awt.ActionRegistration; import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.Presenter; +import sdmxdl.web.WebSource; +import javax.swing.*; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.util.stream.Stream; -import javax.swing.JMenuItem; -import org.openide.awt.ActionReference; -import org.openide.util.actions.Presenter; -import sdmxdl.web.SdmxWebSource; + +import static jdplus.toolkit.desktop.plugin.tsproviders.TsProviderNodes.SOURCE_ACTION_PATH; @ActionID(category = "Edit", id = OpenWebsiteAction.ID) @ActionRegistration(displayName = "#CTL_OpenWebsiteAction", lazy = false) @@ -28,7 +29,7 @@ @ActionReference(path = SOURCE_ACTION_PATH, position = 720, separatorBefore = 700, id = @ActionID(category = "Edit", id = OpenWebsiteAction.ID)) public final class OpenWebsiteAction extends AbilityNodeAction implements Presenter.Popup { - public static final String ID = "demetra.desktop.extra.sdmx.web.OpenWebsiteAction"; + static final String ID = "jdplus.sdmx.desktop.plugin.web.actions.OpenWebsiteAction"; public OpenWebsiteAction() { super(DataSource.class, true); @@ -64,7 +65,7 @@ private URL getWebsite(DataSource dataSource) { } private URL getWebsite(SdmxWebProvider provider, DataSource dataSource) { - SdmxWebSource source = provider.getSdmxManager().getSources().get(provider.decodeBean(dataSource).getSource()); + WebSource source = provider.getSdmxManager().getSources().get(provider.decodeBean(dataSource).getSource()); return source != null ? source.getWebsite() : null; } diff --git a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/test/java/jdplus/sdmx/desktop/plugin/SdmxRuntimeDependenciesTest.java b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/test/java/jdplus/sdmx/desktop/plugin/SdmxRuntimeDependenciesTest.java index abb54c9..1638fdc 100644 --- a/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/test/java/jdplus/sdmx/desktop/plugin/SdmxRuntimeDependenciesTest.java +++ b/jdplus-sdmx-desktop/jdplus-sdmx-desktop-plugin/src/test/java/jdplus/sdmx/desktop/plugin/SdmxRuntimeDependenciesTest.java @@ -2,10 +2,10 @@ import jdplus.main.desktop.design.GAV; import nbbrd.design.MightBePromoted; -import nbbrd.io.FileParser; import org.assertj.core.api.Condition; import org.assertj.core.api.ListAssert; import org.junit.jupiter.api.Test; +import standalone_sdmxdl.nbbrd.io.FileParser; import java.io.IOException; import java.util.List; @@ -23,9 +23,8 @@ public void test() throws IOException { .describedAs("Check runtime dependencies") .satisfies(SdmxRuntimeDependenciesTest::checkSdmx) .satisfies(SdmxRuntimeDependenciesTest::checkSdmxdl) - .satisfies(SdmxRuntimeDependenciesTest::checkNetworkLibs) .satisfies(SdmxRuntimeDependenciesTest::checkJavaDesktopUtil) - .hasSize(16); + .hasSize(4); } private static void checkSdmx(List coordinates) { @@ -40,35 +39,7 @@ private static void checkSdmxdl(List coordinates) { assertThatGroupId(coordinates, "com.github.nbbrd.sdmx-dl") .has(sameVersion()) .extracting(GAV::getArtifactId) - .are(matchingPattern(compile("^sdmx-dl-(api|provider-ri|provider-base|format-csv|format-xml|format-kryo|format-base)$"))) - .hasSize(7); - - assertThatGroupId(coordinates, "com.google.code.gson") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("gson"); - - assertThatGroupId(coordinates, "com.github.tuupertunut") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("powershell-lib-java"); - - assertThatGroupId(coordinates, "com.esotericsoftware.kryo") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("kryo5"); - } - - private static void checkNetworkLibs(List coordinates) { - assertThatGroupId(coordinates, "com.github.nbbrd.java-net-proxy") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("java-net-proxy"); - - assertThatGroupId(coordinates, "io.github.hakky54") - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("sslcontext-kickstart"); - - assertThatGroupId(coordinates, "org.slf4j") - .has(sameVersion()) - .extracting(GAV::getArtifactId) - .containsExactlyInAnyOrder("slf4j-api", "slf4j-jdk14"); + .containsExactlyInAnyOrder("sdmx-dl-api", "sdmx-dl-standalone"); } private static void checkJavaDesktopUtil(List coordinates) { diff --git a/jdplus-sdmx-desktop/pom.xml b/jdplus-sdmx-desktop/pom.xml index 2727874..6db6343 100644 --- a/jdplus-sdmx-desktop/pom.xml +++ b/jdplus-sdmx-desktop/pom.xml @@ -6,7 +6,7 @@ com.github.nbbrd.jdplus-sdmx jdplus-sdmx - 3.0.0 + 3.1.0 jdplus-sdmx-desktop @@ -16,7 +16,7 @@ - RELEASE180 + RELEASE190 diff --git a/pom.xml b/pom.xml index 326c323..ff5877c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.nbbrd.jdplus-sdmx jdplus-sdmx - 3.0.0 + 3.1.0 pom ${project.artifactId} @@ -48,18 +48,18 @@ ${project.artifactId} - 1.18.28 - 1.6.1 - 1.4.0 - 3.33.0 + 1.18.30 + 1.7.0 + 1.5.0 + 3.39.0 - 5.9.2 + 5.10.0 3.24.2 - 3.0.2 - 3.0.0-beta.11 + 3.1.1 + 3.0.0-beta.12 @@ -124,7 +124,7 @@ org.apache.maven.plugins maven-clean-plugin - 3.2.0 + 3.3.1 org.apache.maven.plugins @@ -162,25 +162,30 @@ 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 modernizer-maven-plugin - 2.6.0 + 2.7.0 de.thetaphi forbiddenapis - 3.5.1 + 3.6 com.github.nbbrd.heylogs heylogs-maven-plugin - 0.5.0 + 0.7.0 com.amashchenko.maven.plugin @@ -195,7 +200,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.5.0 + 3.6.0 org.simplify4u.plugins @@ -272,7 +277,7 @@ org.codehaus.mojo extra-enforcer-rules - 1.6.2 + 1.7.0 org.kordamp.maven @@ -295,6 +300,7 @@ 3.6.0 + central true @@ -512,7 +518,16 @@ + + + + central + https://repo.maven.apache.org/maven2 + + false + + jdemetra-snapshots https://oss.sonatype.org/content/repositories/snapshots/ @@ -523,5 +538,15 @@ true + + sdmx-dl-snapshots + https://s01.oss.sonatype.org/content/repositories/snapshots/ + + false + + + true + +