From ea15ae0baf5d2f4a87e05605d426208e0f0da90e Mon Sep 17 00:00:00 2001 From: Serge Rider Date: Mon, 29 Jan 2024 18:49:59 +0300 Subject: [PATCH] INF-10 Move utils to dbeaver-common. Refactor WMI (#22607) --- bundles/org.jkiss.utils/META-INF/MANIFEST.MF | 17 - bundles/org.jkiss.utils/build.properties | 3 - bundles/org.jkiss.utils/pom.xml | 14 - .../src/org/jkiss/code/NotNull.java | 25 - .../src/org/jkiss/code/Nullable.java | 25 - .../jkiss/utils/AlphanumericComparator.java | 83 -- .../org/jkiss/utils/ArgumentTokenizer.java | 227 ---- .../src/org/jkiss/utils/ArrayUtils.java | 311 ----- .../src/org/jkiss/utils/Base64.java | 330 ----- .../src/org/jkiss/utils/BeanUtils.java | 488 -------- .../src/org/jkiss/utils/ByteNumberFormat.java | 180 --- .../src/org/jkiss/utils/CommonUtils.java | 1066 ----------------- .../src/org/jkiss/utils/IOUtils.java | 444 ------- .../src/org/jkiss/utils/IntKeyMap.java | 807 ------------- .../src/org/jkiss/utils/LongKeyMap.java | 806 ------------- .../src/org/jkiss/utils/MimeType.java | 90 -- .../src/org/jkiss/utils/Pair.java | 87 -- .../src/org/jkiss/utils/ReaderWriterLock.java | 112 -- .../src/org/jkiss/utils/SecurityUtils.java | 211 ---- .../org/jkiss/utils/StandardConstants.java | 45 - .../src/org/jkiss/utils/csv/CSVParser.java | 562 --------- .../org/jkiss/utils/csv/CSVParserBuilder.java | 209 ---- .../src/org/jkiss/utils/csv/CSVReader.java | 377 ------ .../org/jkiss/utils/csv/CSVReaderBuilder.java | 183 --- .../csv/CSVReaderNullFieldIndicator.java | 40 - .../src/org/jkiss/utils/csv/CSVWriter.java | 314 ----- .../src/org/jkiss/utils/csv/LineReader.java | 71 -- .../org/jkiss/utils/io/BOMInputStream.java | 147 --- .../src/org/jkiss/utils/io/ByteOrderMark.java | 93 -- .../org/jkiss/utils/rest/RequestMapping.java | 36 - .../jkiss/utils/rest/RequestParameter.java | 31 - .../src/org/jkiss/utils/rest/RestClient.java | 258 ---- .../org/jkiss/utils/rest/RestConstants.java | 34 - .../org/jkiss/utils/rest/RestException.java | 35 - .../src/org/jkiss/utils/rest/RestProxy.java | 24 - .../src/org/jkiss/utils/rest/RestServer.java | 340 ------ .../jkiss/utils/time/ExtendedDateFormat.java | 229 ---- .../src/org/jkiss/utils/xml/SAXListener.java | 65 - .../src/org/jkiss/utils/xml/SAXReader.java | 385 ------ .../src/org/jkiss/utils/xml/XMLBuilder.java | 634 ---------- .../src/org/jkiss/utils/xml/XMLConstants.java | 40 - .../src/org/jkiss/utils/xml/XMLException.java | 35 - .../src/org/jkiss/utils/xml/XMLUtils.java | 285 ----- bundles/org.jkiss.wmi/META-INF/MANIFEST.MF | 11 - bundles/org.jkiss.wmi/build.properties | 5 - bundles/org.jkiss.wmi/copy_contrib.cmd | 2 - .../org.jkiss.wmi/native/x86/jkiss_wmi.dll | Bin 159744 -> 0 bytes bundles/org.jkiss.wmi/pom.xml | 19 - bundles/pom.xml | 20 - .../org.jkiss.dbeaver.db.feature/feature.xml | 1 - .../META-INF/MANIFEST.MF | 3 +- .../build.properties | 9 +- .../native/x64/jkiss_wmi.dll | Bin .../src-native}/JNIMetaData.cpp | 0 .../src-native}/JNIMetaData.h | 0 .../src-native}/WMIObject.cpp | 0 .../src-native}/WMIObject.h | 0 .../src-native}/WMIObjectJNI.cpp | 0 .../src-native}/WMIObjectJNI.h | 0 .../src-native}/WMIObjectSink.cpp | 0 .../src-native}/WMIObjectSink.h | 0 .../src-native}/WMIService.cpp | 0 .../src-native}/WMIService.h | 0 .../src-native}/WMIService.sln | 0 .../src-native}/WMIService.vcproj | 0 .../src-native}/WMIServiceJNI.cpp | 0 .../src-native}/WMIServiceJNI.h | 0 .../src-native}/WMIServiceModule.cpp | 0 .../src-native}/WMIUtils.cpp | 0 .../src-native}/WMIUtils.h | 0 .../src-native}/gen_headers.cmd | 0 .../src-native}/show_sigs.cmd | 0 .../src-native}/stdafx.cpp | 0 .../src-native}/stdafx.h | 0 .../org/jkiss/wmi/service/WMIConstants.java | 0 .../org/jkiss/wmi/service/WMIDataType.java | 0 .../org/jkiss/wmi/service/WMIException.java | 0 .../src}/org/jkiss/wmi/service/WMIObject.java | 0 .../jkiss/wmi/service/WMIObjectAttribute.java | 0 .../jkiss/wmi/service/WMIObjectElement.java | 0 .../jkiss/wmi/service/WMIObjectMethod.java | 0 .../org/jkiss/wmi/service/WMIObjectSink.java | 0 .../wmi/service/WMIObjectSinkStatus.java | 0 .../jkiss/wmi/service/WMIQualifiedObject.java | 0 .../org/jkiss/wmi/service/WMIQualifier.java | 0 .../org/jkiss/wmi/service/WMIService.java | 0 .../org/jkiss/wmi/service/WMISinkStatus.java | 0 .../src}/org/jkiss/wmi/test/TestService.java | 0 pom.xml | 23 +- project.deps | 1 + 90 files changed, 15 insertions(+), 9877 deletions(-) delete mode 100644 bundles/org.jkiss.utils/META-INF/MANIFEST.MF delete mode 100644 bundles/org.jkiss.utils/build.properties delete mode 100644 bundles/org.jkiss.utils/pom.xml delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/code/NotNull.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/code/Nullable.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/AlphanumericComparator.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/ArgumentTokenizer.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/ArrayUtils.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/Base64.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/BeanUtils.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/ByteNumberFormat.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/CommonUtils.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/IOUtils.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/IntKeyMap.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/LongKeyMap.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/MimeType.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/Pair.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/ReaderWriterLock.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/SecurityUtils.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/StandardConstants.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVParser.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVParserBuilder.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReader.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReaderBuilder.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReaderNullFieldIndicator.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVWriter.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/csv/LineReader.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/io/BOMInputStream.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/io/ByteOrderMark.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RequestMapping.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RequestParameter.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestClient.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestConstants.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestException.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestProxy.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestServer.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/time/ExtendedDateFormat.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/xml/SAXListener.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/xml/SAXReader.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLBuilder.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLConstants.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLException.java delete mode 100644 bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLUtils.java delete mode 100644 bundles/org.jkiss.wmi/META-INF/MANIFEST.MF delete mode 100644 bundles/org.jkiss.wmi/build.properties delete mode 100644 bundles/org.jkiss.wmi/copy_contrib.cmd delete mode 100644 bundles/org.jkiss.wmi/native/x86/jkiss_wmi.dll delete mode 100644 bundles/org.jkiss.wmi/pom.xml delete mode 100644 bundles/pom.xml rename {bundles/org.jkiss.wmi => plugins/org.jkiss.dbeaver.ext.wmi}/native/x64/jkiss_wmi.dll (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/JNIMetaData.cpp (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/JNIMetaData.h (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIObject.cpp (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIObject.h (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIObjectJNI.cpp (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIObjectJNI.h (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIObjectSink.cpp (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIObjectSink.h (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIService.cpp (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIService.h (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIService.sln (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIService.vcproj (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIServiceJNI.cpp (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIServiceJNI.h (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIServiceModule.cpp (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIUtils.cpp (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/WMIUtils.h (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/gen_headers.cmd (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/show_sigs.cmd (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/stdafx.cpp (100%) rename {bundles/org.jkiss.wmi/src/native => plugins/org.jkiss.dbeaver.ext.wmi/src-native}/stdafx.h (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIConstants.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIDataType.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIException.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIObject.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIObjectAttribute.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIObjectElement.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIObjectMethod.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIObjectSink.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIObjectSinkStatus.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIQualifiedObject.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIQualifier.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMIService.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/service/WMISinkStatus.java (100%) rename {bundles/org.jkiss.wmi/src/java => plugins/org.jkiss.dbeaver.ext.wmi/src}/org/jkiss/wmi/test/TestService.java (100%) create mode 100644 project.deps diff --git a/bundles/org.jkiss.utils/META-INF/MANIFEST.MF b/bundles/org.jkiss.utils/META-INF/MANIFEST.MF deleted file mode 100644 index 50c633dd37fd..000000000000 --- a/bundles/org.jkiss.utils/META-INF/MANIFEST.MF +++ /dev/null @@ -1,17 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: DBeaver Utils -Bundle-Vendor: DBeaver Corp -Bundle-SymbolicName: org.jkiss.utils -Bundle-Version: 2.1.207.qualifier -Bundle-Release-Date: 20240205 -Bundle-RequiredExecutionEnvironment: JavaSE-17 -Require-Bundle: com.google.gson -Export-Package: org.jkiss.code, - org.jkiss.utils, - org.jkiss.utils.csv, - org.jkiss.utils.io, - org.jkiss.utils.rest, - org.jkiss.utils.time, - org.jkiss.utils.xml -Automatic-Module-Name: org.jkiss.utils diff --git a/bundles/org.jkiss.utils/build.properties b/bundles/org.jkiss.utils/build.properties deleted file mode 100644 index 3335c5d91cbc..000000000000 --- a/bundles/org.jkiss.utils/build.properties +++ /dev/null @@ -1,3 +0,0 @@ -source.. = src/ -output.. = target/classes/ -bin.includes = META-INF/,. diff --git a/bundles/org.jkiss.utils/pom.xml b/bundles/org.jkiss.utils/pom.xml deleted file mode 100644 index 94e81311b724..000000000000 --- a/bundles/org.jkiss.utils/pom.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - 4.0.0 - - org.jkiss.dbeaver - bundles - 1.0.0-SNAPSHOT - ../ - - org.jkiss.utils - 2.1.207-SNAPSHOT - eclipse-plugin - diff --git a/bundles/org.jkiss.utils/src/org/jkiss/code/NotNull.java b/bundles/org.jkiss.utils/src/org/jkiss/code/NotNull.java deleted file mode 100644 index bff9bf18a575..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/code/NotNull.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.code; - -/** - * NotNull annotation - */ -public @interface NotNull { - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/code/Nullable.java b/bundles/org.jkiss.utils/src/org/jkiss/code/Nullable.java deleted file mode 100644 index 88a5ebf0de30..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/code/Nullable.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.code; - -/** - * Nullable annotation - */ -public @interface Nullable { - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/AlphanumericComparator.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/AlphanumericComparator.java deleted file mode 100644 index e1c37a536846..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/AlphanumericComparator.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils; - -import org.jkiss.code.NotNull; - -import java.util.Comparator; - -/** - * A comparator for comparing two strings lexicographically, treating them as sequences of alphanumeric characters. - *

- * This comparator compares strings based on their alphanumeric content. It considers - * the characters in the strings as a sequence of alphanumeric characters (letters and digits) - * and compares them lexicographically. The comparison is case-insensitive. - */ -public class AlphanumericComparator implements Comparator { - private static final AlphanumericComparator INSTANCE = new AlphanumericComparator(); - - private AlphanumericComparator() { - // prevents instantiation - } - - @NotNull - public static AlphanumericComparator getInstance() { - return INSTANCE; - } - - @Override - public int compare(CharSequence o1, CharSequence o2) { - final int len1 = o1.length(); - final int len2 = o2.length(); - - int i = 0; - int j = 0; - - while (i < len1 && j < len2) { - final char ch1 = Character.toUpperCase(o1.charAt(i)); - final char ch2 = Character.toUpperCase(o2.charAt(i)); - - if (Character.isDigit(ch1) && Character.isDigit(ch2)) { - int num1 = 0; - int num2 = 0; - - while (i < len1 && Character.isDigit(o1.charAt(i))) { - num1 = num1 * 10 + Character.digit(o1.charAt(i), 10); - i += 1; - } - - while (j < len2 && Character.isDigit(o2.charAt(j))) { - num2 = num2 * 10 + Character.digit(o2.charAt(j), 10); - j += 1; - } - - if (num1 != num2) { - return num1 - num2; - } - } else { - if (ch1 != ch2) { - return ch1 - ch2; - } - - i += 1; - j += 1; - } - } - - return len1 - len2; - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/ArgumentTokenizer.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/ArgumentTokenizer.java deleted file mode 100644 index 46e12bd0d03d..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/ArgumentTokenizer.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * This software is Open Source Initiative approved Open Source Software. - * Open Source Initative Approved is a trademark of the Open Source Initiative. - * - * This file is part of DrJava. Download the current version of this project - * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/ - */ - -package org.jkiss.utils; - -import java.util.LinkedList; -import java.util.List; - -/** - * Utility class which can tokenize a String into a list of String arguments, - * with behavior similar to parsing command line arguments to a program. - * Quoted Strings are treated as single arguments, and escaped characters - * are translated so that the tokenized arguments have the same meaning. - * Since all methods are static, the class is declared abstract to prevent - * instantiation. - * - * @version $Id$ - */ -public abstract class ArgumentTokenizer { - private static final int NO_TOKEN_STATE = 0; - private static final int NORMAL_TOKEN_STATE = 1; - private static final int SINGLE_QUOTE_STATE = 2; - private static final int DOUBLE_QUOTE_STATE = 3; - - /** - * Tokenizes the given String into String tokens - * - * @param arguments A String containing one or more command-line style arguments to be tokenized. - * @return A list of parsed and properly escaped arguments. - */ - public static List tokenize(String arguments) { - return tokenize(arguments, false); - } - - /** - * Tokenizes the given String into String tokens. - * - * @param arguments A String containing one or more command-line style arguments to be tokenized. - * @param stringify whether or not to include escape special characters - * @return A list of parsed and properly escaped arguments. - */ - public static List tokenize(String arguments, boolean stringify) { - - LinkedList argList = new LinkedList(); - StringBuilder currArg = new StringBuilder(); - boolean escaped = false; - int state = NO_TOKEN_STATE; // start in the NO_TOKEN_STATE - int len = arguments.length(); - - // Loop over each character in the string - for (int i = 0; i < len; i++) { - char c = arguments.charAt(i); - if (escaped) { - // Escaped state: just append the next character to the current arg. - escaped = false; - if (c != 'n' && c != 't' && c != '\\') { - // This was just a regular slash - currArg.append('\\'); - } - currArg.append(c); - } else { - switch (state) { - case SINGLE_QUOTE_STATE: - if (c == '\'') { - // Seen the close quote; continue this arg until whitespace is seen - state = NORMAL_TOKEN_STATE; - } else { - currArg.append(c); - } - break; - case DOUBLE_QUOTE_STATE: - if (c == '"') { - // Seen the close quote; continue this arg until whitespace is seen - state = NORMAL_TOKEN_STATE; - } else if (c == '\\') { - // Look ahead, and only escape quotes or backslashes - i++; - char next = arguments.charAt(i); - if (next == '"' || next == '\\') { - currArg.append(next); - } else { - currArg.append(c); - currArg.append(next); - } - } else { - currArg.append(c); - } - break; -// case NORMAL_TOKEN_STATE: -// if (Character.isWhitespace(c)) { -// // Whitespace ends the token; start a new one -// argList.add(currArg.toString()); -// currArg = new StringBuffer(); -// state = NO_TOKEN_STATE; -// } -// else if (c == '\\') { -// // Backslash in a normal token: escape the next character -// escaped = true; -// } -// else if (c == '\'') { -// state = SINGLE_QUOTE_STATE; -// } -// else if (c == '"') { -// state = DOUBLE_QUOTE_STATE; -// } -// else { -// currArg.append(c); -// } -// break; - case NO_TOKEN_STATE: - case NORMAL_TOKEN_STATE: - switch (c) { - case '\\': - escaped = true; - state = NORMAL_TOKEN_STATE; - break; - case '\'': - state = SINGLE_QUOTE_STATE; - break; - case '"': - state = DOUBLE_QUOTE_STATE; - break; - default: - if (!Character.isWhitespace(c)) { - currArg.append(c); - state = NORMAL_TOKEN_STATE; - } else if (state == NORMAL_TOKEN_STATE) { - // Whitespace ends the token; start a new one - argList.add(currArg.toString()); - currArg = new StringBuilder(); - state = NO_TOKEN_STATE; - } - } - break; - default: - throw new IllegalStateException("ArgumentTokenizer state " + state + " is invalid!"); - } - } - } - - // If we're still escaped, put in the backslash - if (escaped) { - currArg.append('\\'); - argList.add(currArg.toString()); - } - // Close the last argument if we haven't yet - else if (state != NO_TOKEN_STATE) { - argList.add(currArg.toString()); - } - // Format each argument if we've been told to stringify them - if (stringify) { - for (int i = 0; i < argList.size(); i++) { - argList.set(i, "\"" + _escapeQuotesAndBackslashes(argList.get(i)) + "\""); - } - } - return argList; - } - - /** - * Inserts backslashes before any occurrences of a backslash or - * quote in the given string. Also converts any special characters - * appropriately. - */ - protected static String _escapeQuotesAndBackslashes(String s) { - final StringBuilder buf = new StringBuilder(s); - - // Walk backwards, looking for quotes or backslashes. - // If we see any, insert an extra backslash into the buffer at - // the same index. (By walking backwards, the index into the buffer - // will remain correct as we change the buffer.) - for (int i = s.length() - 1; i >= 0; i--) { - char c = s.charAt(i); - if ((c == '\\') || (c == '"')) { - buf.insert(i, '\\'); - } - // Replace any special characters with escaped versions - else if (c == '\n') { - buf.deleteCharAt(i); - buf.insert(i, "\\n"); - } else if (c == '\t') { - buf.deleteCharAt(i); - buf.insert(i, "\\t"); - } else if (c == '\r') { - buf.deleteCharAt(i); - buf.insert(i, "\\r"); - } else if (c == '\b') { - buf.deleteCharAt(i); - buf.insert(i, "\\b"); - } else if (c == '\f') { - buf.deleteCharAt(i); - buf.insert(i, "\\f"); - } - } - return buf.toString(); - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/ArrayUtils.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/ArrayUtils.java deleted file mode 100644 index deb37abc82b0..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/ArrayUtils.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.utils; - -import org.jkiss.code.NotNull; -import org.jkiss.code.Nullable; - -import java.lang.reflect.Array; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.function.Predicate; - -/** - * Common utils - */ -public class ArrayUtils { - - - public static boolean isEmpty(@Nullable Object[] arr) - { - return arr == null || arr.length == 0; - } - - public static boolean isEmpty(@Nullable short[] array) - { - return array == null || array.length == 0; - } - - public static boolean isArray(@Nullable Object value) { - return value != null && value.getClass().isArray(); - } - - public static boolean contains(@Nullable short[] array, short value) - { - if (array == null) - return false; - for (short item : array) { - if (item == value) - return true; - } - return false; - } - - public static boolean contains(@Nullable char[] array, char value) - { - if (array == null || array.length == 0) - return false; - for (char c : array) { - if (c == value) - return true; - } - return false; - } - - public static boolean isEmpty(@Nullable int[] array) - { - return array == null || array.length == 0; - } - - public static boolean contains(@Nullable int[] array, int value) - { - if (array == null) - return false; - for (int v : array) { - if (v == value) - return true; - } - return false; - } - - public static boolean isEmpty(@Nullable long[] array) - { - return array == null || array.length == 0; - } - - public static boolean contains(@Nullable long[] array, long value) - { - if (array == null) - return false; - for (long v : array) { - if (v == value) - return true; - } - return false; - } - - public static boolean contains(OBJECT_TYPE[] array, OBJECT_TYPE value) - { - if (isEmpty(array)) - return false; - for (OBJECT_TYPE object_type : array) { - if (CommonUtils.equalObjects(value, object_type)) - return true; - } - return false; - } - - public static boolean containsIgnoreCase(String[] array, String value) - { - if (isEmpty(array) || value == null) - return false; - for (String s : array) { - if (value.equalsIgnoreCase(s)) - return true; - } - return false; - } - - public static boolean containsRef(@NotNull OBJECT_TYPE[] array, @Nullable OBJECT_TYPE value) - { - final int length = array.length; - for (OBJECT_TYPE object_type : array) { - if (value == object_type) - return true; - } - return false; - } - - @SafeVarargs - public static boolean containsAny(OBJECT_TYPE[] array, OBJECT_TYPE... values) { - for (OBJECT_TYPE item : array) { - for (OBJECT_TYPE value : values) { - if (CommonUtils.equalObjects(item, value)) - return true; - } - } - return false; - } - - @SafeVarargs - public static boolean containsAll(OBJECT_TYPE[] array, OBJECT_TYPE... values) { - if (isEmpty(array)) { - return false; - } - for (OBJECT_TYPE value : values) { - if (!ArrayUtils.contains(array, value)) - return false; - } - return true; - } - - @NotNull - public static T[] concatArrays(@NotNull T[] first, @NotNull T[] second) - { - T[] result = Arrays.copyOf(first, first.length + second.length); - System.arraycopy(second, 0, result, first.length, second.length); - return result; - } - - @NotNull - public static List safeArray(@Nullable T[] array) - { - if (array == null) { - return Collections.emptyList(); - } else { - return Arrays.asList(array); - } - } - - /** - * Returns index of the first found element satisfying a given predicate in the provided array - */ - public static int indexOf(@NotNull T[] array, @NotNull Predicate condition) { - for (int i = 0; i < array.length; i++) { - if (condition.test(array[i])) { - return i; - } - } - return -1; - } - - public static int indexOf(T[] array, T element) { - for (int i = 0; i < array.length; i++) { - if (CommonUtils.equalObjects(array[i], element)) { - return i; - } - } - return -1; - } - - public static int indexOf(int[] array, int offset, int element) { - for (int i = offset; i < array.length; i++) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int indexOf(byte[] array, int offset, byte element) { - for (int i = offset; i < array.length; i++) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - @SuppressWarnings("unchecked") - public static T[] deleteArea(Class type, T[] elements, int from, int to) { - int delCount = to - from + 1; - T[] newArray = (T[]) Array.newInstance(type, elements.length - delCount); - System.arraycopy(elements, 0, newArray, 0, from); - if (to < elements.length - 1) { - System.arraycopy(elements, to + 1, newArray, from, elements.length - from - delCount); - } - - return newArray; - } - - @SuppressWarnings("unchecked") - public static T[] insertArea(Class type, Object[] elements, int pos, Object[] add) { - T[] newArray = (T[]) Array.newInstance(type, elements.length + add.length); - System.arraycopy(elements, 0, newArray, 0, pos); - System.arraycopy(add, 0, newArray, pos, add.length); - System.arraycopy(elements, pos, newArray, pos + add.length, elements.length - pos); - return newArray; - } - - @SuppressWarnings("unchecked") - public static T[] add(Class type, T[] elements, T add) { - T[] newArray = (T[]) Array.newInstance(type, elements.length + 1); - System.arraycopy(elements, 0, newArray, 0, elements.length); - newArray[elements.length] = add; - return newArray; - } - - @SuppressWarnings("unchecked") - public static T[] remove(Class type, T[] elements, int index) { - T[] newArray = (T[]) Array.newInstance(type, elements.length - 1); - System.arraycopy(elements, 0, newArray, 0, index); - if (index < elements.length - 1) { - System.arraycopy(elements, index + 1, newArray, index, elements.length - index - 1); - } - return newArray; - } - - public static T[] remove(Class type, T[] elements, T element) { - for (int i = 0; i < elements.length; i++) { - if (elements[i] == element) { - return remove(type, elements, i); - } - } - return elements; - } - - public static int[] add(int[] elements, int add) { - int[] newArray = new int[elements.length + 1]; - System.arraycopy(elements, 0, newArray, 0, elements.length); - newArray[elements.length] = add; - return newArray; - } - - public static void main(String[] args) { - String[] arr = new String[0]; - - for (int i = 0; i < 100; i++) { - arr = add(String.class, arr, String.valueOf(i)); - } - System.out.println(Arrays.toString(arr)); - for (int i = 0; i < 100; i++) { - arr = remove(String.class, arr, 0); - } - System.out.println(Arrays.toString(arr)); - } - - @SuppressWarnings("unchecked") - public static T[] toArray(Class type, Collection list) { - return list.toArray((T[]) Array.newInstance(type, list.size())); - } - - @Nullable - public static boolean[] unbox(@Nullable Boolean[] source) { - if (source == null) { - return null; - } - final boolean[] result = new boolean[source.length]; - for (int i = 0; i < source.length; i++) { - result[i] = source[i]; - } - return result; - } - - public static void reverse(@Nullable Object[] array) { - if (array == null || array.length <= 1) { - return; - } - for (int i = 0, j = array.length - 1; j > i; ++i, j--) { - final Object tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - } - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/Base64.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/Base64.java deleted file mode 100644 index d936daa7ede2..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/Base64.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.utils; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Writer; - -public final class Base64 { - - private static final char[] S_BASE64CHAR = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', - 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', - 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', - 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '+', '/' - }; - - private static final char S_BASE64PAD = '='; - - private static final byte[] S_DECODETABLE = new byte[128]; - - static { - for (int i = 0; i < S_DECODETABLE.length; i ++) - S_DECODETABLE[i] = Byte.MAX_VALUE; // 127 - for (int i = 0; i < S_BASE64CHAR.length; i ++) // 0 to 63 - S_DECODETABLE[S_BASE64CHAR[i]] = (byte)i; - } - - private static int decode0(char[] ibuf, byte[] obuf, int wp) { - int outlen = 3; - if (ibuf[3] == S_BASE64PAD) outlen = 2; - if (ibuf[2] == S_BASE64PAD) outlen = 1; - int b0 = S_DECODETABLE[ibuf[0]]; - int b1 = S_DECODETABLE[ibuf[1]]; - int b2 = S_DECODETABLE[ibuf[2]]; - int b3 = S_DECODETABLE[ibuf[3]]; - switch (outlen) { - case 1: - obuf[wp] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3); - return 1; - case 2: - obuf[wp++] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3); - obuf[wp] = (byte)(b1 << 4 & 0xf0 | b2 >> 2 & 0xf); - return 2; - case 3: - default: - obuf[wp++] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3); - obuf[wp++] = (byte)(b1 << 4 & 0xf0 | b2 >> 2 & 0xf); - obuf[wp] = (byte)(b2 << 6 & 0xc0 | b3 & 0x3f); - return 3; - } - } - - /** - * - */ - public static byte[] decode(char[] data, int off, int len) { - char[] ibuf = new char[4]; - int ibufcount = 0; - byte[] obuf = new byte[len/4*3+3]; - int obufcount = 0; - for (int i = off; i < off+len; i ++) { - char ch = data[i]; - if (ch == S_BASE64PAD - || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) { - ibuf[ibufcount++] = ch; - if (ibufcount == ibuf.length) { - ibufcount = 0; - obufcount += decode0(ibuf, obuf, obufcount); - } - } - } - if (obufcount == obuf.length) - return obuf; - byte[] ret = new byte[obufcount]; - System.arraycopy(obuf, 0, ret, 0, obufcount); - return ret; - } - - /** - * - */ - public static byte[] decode(String data) { - char[] ibuf = new char[4]; - int ibufcount = 0; - byte[] obuf = new byte[data.length()/4*3+3]; - int obufcount = 0; - for (int i = 0; i < data.length(); i ++) { - char ch = data.charAt(i); - if (ch == S_BASE64PAD - || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) { - ibuf[ibufcount++] = ch; - if (ibufcount == ibuf.length) { - ibufcount = 0; - obufcount += decode0(ibuf, obuf, obufcount); - } - } - } - if (obufcount == obuf.length) - return obuf; - byte[] ret = new byte[obufcount]; - System.arraycopy(obuf, 0, ret, 0, obufcount); - return ret; - } - - /** - * - */ - public static void decode(char[] data, int off, int len, OutputStream ostream) throws IOException { - char[] ibuf = new char[4]; - int ibufcount = 0; - byte[] obuf = new byte[3]; - for (int i = off; i < off+len; i ++) { - char ch = data[i]; - if (ch == S_BASE64PAD - || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) { - ibuf[ibufcount++] = ch; - if (ibufcount == ibuf.length) { - ibufcount = 0; - int obufcount = decode0(ibuf, obuf, 0); - ostream.write(obuf, 0, obufcount); - } - } - } - } - - /** - * - */ - public static void decode(String data, OutputStream ostream) throws IOException { - char[] ibuf = new char[4]; - int ibufcount = 0; - byte[] obuf = new byte[3]; - for (int i = 0; i < data.length(); i ++) { - char ch = data.charAt(i); - if (ch == S_BASE64PAD - || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) { - ibuf[ibufcount++] = ch; - if (ibufcount == ibuf.length) { - ibufcount = 0; - int obufcount = decode0(ibuf, obuf, 0); - ostream.write(obuf, 0, obufcount); - } - } - } - } - - /** - * Returns base64 representation of specified byte array. - */ - public static String encode(byte[] data) { - return encode(data, 0, data.length); - } - - public static String splitLines(String bigString, int lineLength) { - return bigString.replaceAll("(.{" + lineLength + "})", "$1\n"); - } - - /** - * Returns base64 representation of specified byte array. - */ - public static String encode(byte[] data, int off, int len) - { - if (len <= 0) return ""; - char[] out = new char[len/3*4+4]; - int rindex = off; - int windex = 0; - int rest = len-off; - while (rest >= 3) { - int i = ((data[rindex]&0xff)<<16) - +((data[rindex+1]&0xff)<<8) - +(data[rindex+2]&0xff); - out[windex++] = S_BASE64CHAR[i>>18]; - out[windex++] = S_BASE64CHAR[(i>>12)&0x3f]; - out[windex++] = S_BASE64CHAR[(i>>6)&0x3f]; - out[windex++] = S_BASE64CHAR[i&0x3f]; - rindex += 3; - rest -= 3; - } - if (rest == 1) { - int i = data[rindex]&0xff; - out[windex++] = S_BASE64CHAR[i>>2]; - out[windex++] = S_BASE64CHAR[(i<<4)&0x3f]; - out[windex++] = S_BASE64PAD; - out[windex++] = S_BASE64PAD; - } else if (rest == 2) { - int i = ((data[rindex]&0xff)<<8)+(data[rindex+1]&0xff); - out[windex++] = S_BASE64CHAR[i>>10]; - out[windex++] = S_BASE64CHAR[(i>>4)&0x3f]; - out[windex++] = S_BASE64CHAR[(i<<2)&0x3f]; - out[windex++] = S_BASE64PAD; - } - return new String(out, 0, windex); - } - - /** - * Outputs base64 representation of the specified byte array to a byte stream. - */ - public static void encode(byte[] data, int off, int len, OutputStream ostream) throws IOException { - if (len <= 0) return; - byte[] out = new byte[4]; - int rindex = off; - int rest = len-off; - while (rest >= 3) { - int i = ((data[rindex]&0xff)<<16) - +((data[rindex+1]&0xff)<<8) - +(data[rindex+2]&0xff); - out[0] = (byte)S_BASE64CHAR[i>>18]; - out[1] = (byte)S_BASE64CHAR[(i>>12)&0x3f]; - out[2] = (byte)S_BASE64CHAR[(i>>6)&0x3f]; - out[3] = (byte)S_BASE64CHAR[i&0x3f]; - ostream.write(out, 0, 4); - rindex += 3; - rest -= 3; - } - if (rest == 1) { - int i = data[rindex]&0xff; - out[0] = (byte)S_BASE64CHAR[i>>2]; - out[1] = (byte)S_BASE64CHAR[(i<<4)&0x3f]; - out[2] = (byte)S_BASE64PAD; - out[3] = (byte)S_BASE64PAD; - ostream.write(out, 0, 4); - } else if (rest == 2) { - int i = ((data[rindex]&0xff)<<8)+(data[rindex+1]&0xff); - out[0] = (byte)S_BASE64CHAR[i>>10]; - out[1] = (byte)S_BASE64CHAR[(i>>4)&0x3f]; - out[2] = (byte)S_BASE64CHAR[(i<<2)&0x3f]; - out[3] = (byte)S_BASE64PAD; - ostream.write(out, 0, 4); - } - } - - /** - * Outputs base64 representation of the specified byte array to a character stream. - */ - public static void encode(byte[] data, int off, int len, Writer writer) throws IOException { - if (len <= 0) return; - char[] out = new char[4]; - int rindex = off; - int rest = len-off; - while (rest >= 3) { - int i = ((data[rindex]&0xff)<<16) - +((data[rindex+1]&0xff)<<8) - +(data[rindex+2]&0xff); - out[0] = S_BASE64CHAR[i>>18]; - out[1] = S_BASE64CHAR[(i>>12)&0x3f]; - out[2] = S_BASE64CHAR[(i>>6)&0x3f]; - out[3] = S_BASE64CHAR[i&0x3f]; - writer.write(out, 0, 4); - rindex += 3; - rest -= 3; -/* - if (output % 76 == 0) - writer.write("\n"); -*/ - } - if (rest == 1) { - int i = data[rindex]&0xff; - out[0] = S_BASE64CHAR[i>>2]; - out[1] = S_BASE64CHAR[(i<<4)&0x3f]; - out[2] = S_BASE64PAD; - out[3] = S_BASE64PAD; - writer.write(out, 0, 4); - } else if (rest == 2) { - int i = ((data[rindex]&0xff)<<8)+(data[rindex+1]&0xff); - out[0] = S_BASE64CHAR[i>>10]; - out[1] = S_BASE64CHAR[(i>>4)&0x3f]; - out[2] = S_BASE64CHAR[(i<<2)&0x3f]; - out[3] = S_BASE64PAD; - writer.write(out, 0, 4); - } - } - - /** - * Outputs base64 representation of the specified input stream to a character stream. - */ - public static void encode(InputStream stream, long len, Writer writer) - throws IOException - { - if (len <= 0) return; - char[] out = new char[4]; - long rest = len; - while (rest >= 3) { - int i = ((stream.read()&0xff)<<16) - +((stream.read()&0xff)<<8) - +(stream.read()&0xff); - out[0] = S_BASE64CHAR[i>>18]; - out[1] = S_BASE64CHAR[(i>>12)&0x3f]; - out[2] = S_BASE64CHAR[(i>>6)&0x3f]; - out[3] = S_BASE64CHAR[i&0x3f]; - writer.write(out, 0, 4); - rest -= 3; - } - if (rest == 1) { - int i = stream.read()&0xff; - out[0] = S_BASE64CHAR[i>>2]; - out[1] = S_BASE64CHAR[(i<<4)&0x3f]; - out[2] = S_BASE64PAD; - out[3] = S_BASE64PAD; - writer.write(out, 0, 4); - } else if (rest == 2) { - int i = ((stream.read()&0xff)<<8)+(stream.read()&0xff); - out[0] = S_BASE64CHAR[i>>10]; - out[1] = S_BASE64CHAR[(i>>4)&0x3f]; - out[2] = S_BASE64CHAR[(i<<2)&0x3f]; - out[3] = S_BASE64PAD; - writer.write(out, 0, 4); - } - } - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/BeanUtils.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/BeanUtils.java deleted file mode 100644 index 5a686adbd543..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/BeanUtils.java +++ /dev/null @@ -1,488 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.utils; - -import org.jkiss.code.NotNull; -import org.jkiss.code.Nullable; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.*; -import java.util.*; -import java.util.function.Supplier; - -/** - * BeanUtils - */ -public class BeanUtils { - - public static boolean isGetterName(String name) { - return name.startsWith("get") || name.startsWith("is") || name.startsWith("has"); - } - - public static String getPropertyNameFromGetter(String getterName) { - if (getterName.startsWith("get")) { - return - Character.toLowerCase(getterName.charAt(3)) + - getterName.substring(4); - } else if (getterName.startsWith("is")) { - return - Character.toLowerCase(getterName.charAt(2)) + - getterName.substring(3); - } else if (getterName.startsWith("has")) { - return - Character.toLowerCase(getterName.charAt(3)) + - getterName.substring(4); - } else { - // Unrecognized getter name - return null; - } - } - - public static String getSetterName(String getterName) { - if (getterName.startsWith("get")) { - return "set" + getterName.substring(3); - } else if (getterName.startsWith("is")) { - return "set" + getterName.substring(2); - } else if (getterName.startsWith("has")) { - return "set" + getterName.substring(3); - } else { - // Unrecognized getter name - return null; - } - } - - /** - * Returns a set method matching the property name. - */ - public static Method getSetMethod(Class cl, String propertyName) { - Method method = getSetMethod(cl, propertyName, false); - - if (method != null) { - return method; - } - - return getSetMethod(cl, propertyName, true); - } - - /** - * Returns a set method matching the property name. - */ - public static Method getSetMethod( - Class cl, - String propertyName, - boolean ignoreCase) { - String setName = "set" + propertyNameToMethodName(propertyName); - - return getSetMethod( - cl.getMethods(), - setName, - ignoreCase); - } - - /** - * Returns a get method matching the property name. - */ - public static Method getGetMethod(Class cl, String propertyName) { - Method method = getGetMethod(cl, propertyName, false); - - return method != null ? - method : - getGetMethod(cl, propertyName, true); - } - - /** - * Returns a get method matching the property name. - */ - public static Method getGetMethod( - Class cl, - String propertyName, - boolean ignoreCase) { - String methodName = propertyNameToMethodName(propertyName); - return getGetMethod( - cl.getMethods(), - "get" + methodName, - "is" + methodName, - ignoreCase); - } - - /** - * Converts a user's property name to a bean method name. - * - * @param propertyName the user property name - * @return the equivalent bean method name - */ - public static String propertyNameToMethodName(String propertyName) { - char ch = propertyName.charAt(0); - if (Character.isLowerCase(ch)) - propertyName = Character.toUpperCase(ch) + propertyName.substring(1); - - return propertyName; - } - - /** - * Converts a user's property name to a bean method name. - * - * @param methodName the method name - * @return the equivalent property name - */ - public static String methodNameToPropertyName(String methodName) { - if (methodName.startsWith("get")) - methodName = methodName.substring(3); - else if (methodName.startsWith("set")) - methodName = methodName.substring(3); - else if (methodName.startsWith("is")) - methodName = methodName.substring(2); - - if (methodName.length() == 0) - return null; - - char ch = methodName.charAt(0); - if (Character.isUpperCase(ch) && (methodName.length() == 1 || !Character.isUpperCase(methodName.charAt(1)))) { - methodName = Character.toLowerCase(ch) + methodName.substring(1); - } - - return methodName; - } - - public static boolean isArrayType(Type type) { - return (type instanceof Class && ((Class) type).isArray()); - } - - public static boolean isCollectionType(Type type) { - if (type instanceof Class && Collection.class.isAssignableFrom((Class) type)) { -/* - if (type instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType)type; - if (pt.getActualTypeArguments().length == 1) { - return true; - } - } -*/ - return true; - } - return isArrayType(type); - } - - public static Class getCollectionType(Type type) { - if (type instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) type; - if (pt.getActualTypeArguments().length == 1) { - final Type argType = pt.getActualTypeArguments()[0]; - if (argType instanceof Class) { - return (Class) argType; - } else if (argType instanceof WildcardType) { - final Type[] upperBounds = ((WildcardType) argType).getUpperBounds(); - if (upperBounds.length > 0 && upperBounds[0] instanceof Class) { - return (Class) upperBounds[0]; - } - final Type[] lowerBounds = ((WildcardType) argType).getLowerBounds(); - if (lowerBounds.length > 0 && lowerBounds[0] instanceof Class) { - return (Class) lowerBounds[0]; - } - } - } - } - return null; - } - - public static Object readObjectProperty(Object object, String propName) - throws IllegalAccessException, InvocationTargetException { - if (propName.indexOf('.') == -1) { - Method getter = getGetMethod(object.getClass(), propName); - return getter == null ? null : getter.invoke(object); - } - // Parse property path - StringTokenizer st = new StringTokenizer(propName, "."); - Object value = object; - while (value != null && st.hasMoreTokens()) { - String pathItem = st.nextToken(); - Method getter = getGetMethod(value.getClass(), pathItem); - if (getter == null) { - return null; - } - value = getter.invoke(value); - } - return value; - } - - /** - * Finds the matching set method - */ - private static Method getGetMethod( - Method[] methods, - String getName, - String isName, - boolean ignoreCase) { - for (int i = 0; i < methods.length; i++) { - Method method = methods[i]; - - // The method must be public - if ( - (!Modifier.isPublic(method.getModifiers())) || - (!Modifier.isPublic(method.getDeclaringClass().getModifiers())) || - (method.getParameterTypes().length != 0) || - (method.getReturnType().equals(void.class))) { - continue; - } else if (!ignoreCase && method.getName().equals(getName)) { - // If it matches the get name, it's the right method - return method; - } else if (ignoreCase && method.getName().equalsIgnoreCase(getName)) { - // If it matches the get name, it's the right method - return method; - } else if (!method.getReturnType().equals(boolean.class)) { - // The is methods must return boolean - continue; - } else if (!ignoreCase && method.getName().equals(isName)) { - // If it matches the is name, it must return boolean - return method; - } else if (ignoreCase && method.getName().equalsIgnoreCase(isName)) { - // If it matches the is name, it must return boolean - return method; - } - } - - return null; - } - - /** - * Finds the matching set method - * - * @param setName the method name - */ - private static Method getSetMethod( - Method[] methods, - String setName, - boolean ignoreCase) { - for (int i = 0; i < methods.length; i++) { - Method method = methods[i]; - - // The method name must match - if ( - !(ignoreCase ? method.getName().equalsIgnoreCase(setName) : method.getName().equals(setName)) || - !Modifier.isPublic(method.getModifiers()) || - !Modifier.isPublic(method.getDeclaringClass().getModifiers()) || - method.getParameterTypes().length != 1 - ) - continue; - - return method; - } - - return null; - } - - public static final Short DEFAULT_SHORT = (short) 0; - public static final Integer DEFAULT_INTEGER = 0; - public static final Long DEFAULT_LONG = 0L; - public static final Float DEFAULT_FLOAT = (float) 0.0; - public static final Double DEFAULT_DOUBLE = 0.0; - public static final Byte DEFAULT_BYTE = (byte) 0; - public static final Character DEFAULT_CHAR = (char) 0; - - public static boolean isBooleanType(Type paramClass) { - return paramClass == Boolean.class || paramClass == Boolean.TYPE; - } - - public static Object getDefaultPrimitiveValue(Class paramClass) { - if (paramClass == Boolean.TYPE) { - return Boolean.FALSE; - } else if (paramClass == Short.TYPE) { - return DEFAULT_SHORT; - } else if (paramClass == Integer.TYPE) { - return DEFAULT_INTEGER; - } else if (paramClass == Long.TYPE) { - return DEFAULT_LONG; - } else if (paramClass == Float.TYPE) { - return DEFAULT_FLOAT; - } else if (paramClass == Double.TYPE) { - return DEFAULT_DOUBLE; - } else if (paramClass == Byte.TYPE) { - return DEFAULT_BYTE; - } else if (paramClass == Character.TYPE) { - return DEFAULT_CHAR; - } else { - throw new IllegalArgumentException("Class " + paramClass.getName() + " is not primitive type"); - } - } - - public static boolean isNumericType(Class paramClass) { - return - Number.class.isAssignableFrom(paramClass) || - paramClass == Short.TYPE || - paramClass == Integer.TYPE || - paramClass == Long.TYPE || - paramClass == Double.TYPE || - paramClass == Float.TYPE || - paramClass == Byte.TYPE; - } - - public static Object invokeObjectMethod(Object object, String name, Class paramTypes[], Object args[]) - throws Throwable { - Method method = object.getClass().getMethod(name, paramTypes); - method.setAccessible(true); - try { - return method.invoke(object, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - } - - public static Object invokeObjectMethod(Object object, String name) - throws Throwable { - Method method = object.getClass().getMethod(name); - method.setAccessible(true); - try { - return method.invoke(object); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - } - - @Nullable - public static Object invokeObjectDeclaredMethod( - @NotNull Object object, - @NotNull String methodName, - @NotNull Class[] paramTypes, - @NotNull Object[] args) throws Throwable - { - for (Class cls = object.getClass(); cls != null; cls = cls.getSuperclass()) { - for (Method method : cls.getDeclaredMethods()) { - if (method.getName().equals(methodName) && Arrays.equals(method.getParameterTypes(), paramTypes)) { - method.setAccessible(true); - try { - return method.invoke(object, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - } - } - } - throw new NoSuchMethodException("Cannot find declared method " + methodName + "(" + Arrays.toString(paramTypes) + ")"); - } - - public static Object invokeStaticMethod(Class objectType, String name, Class paramTypes[], Object args[]) - throws Throwable { - Method method = objectType.getMethod(name, paramTypes); - method.setAccessible(true); - try { - return method.invoke(null, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - } - - public static Class findAssignableType(Class[] types, Class type) { - for (Class childType : types) { - if (type.isAssignableFrom(childType)) { - return (Class) childType; - } - } - return null; - } - - /** - * Determines the distance of the given object to the given class in the - * inheritance tree. - *

- * @param object the root object - * @param clazz the class to determine the distance to - * @return the distance of the object to the class. If the object is not an - * instance of the class {@code -1} will return. - */ - public static int getInheritanceDistance(Object object, Class clazz) { - if (clazz.isInstance(object)) { - int distance = 0; - Class compared = object.getClass(); - while (compared != clazz) { - compared = compared.getSuperclass(); - distance++; - if (compared == Object.class) { - break; - } - } - return distance; - } else { - return -1; - } - } - - @SuppressWarnings("unchecked") - public static T getFieldValue(@NotNull Object object, @NotNull String name) throws Throwable { - final Field field = object.getClass().getDeclaredField(name); - if (!field.canAccess(object)) { - field.setAccessible(true); - } - return (T) field.get(object); - } - - @Nullable - public static Object handleObjectMethod(@NotNull Object proxy, @NotNull Method method, Object[] args) { - switch (method.getName()) { - case "toString": - return "Proxy"; - case "hashCode": - return System.identityHashCode(proxy); - case "equals": - return proxy == args[0]; - default: - return null; - } - } - - @NotNull - public static List deepCopy(@NotNull List src) { - final List dst = tryInstantiateOrDefault(src.getClass(), ArrayList::new); - for (T element : src) { - dst.add(deepCopy(element)); - } - return dst; - } - - @NotNull - public static Map deepCopy(@NotNull Map src) { - final Map dst = tryInstantiateOrDefault(src.getClass(), LinkedHashMap::new); - for (Map.Entry entry : src.entrySet()) { - dst.put(entry.getKey(), deepCopy(entry.getValue())); - } - return dst; - } - - @SuppressWarnings("unchecked") - private static T deepCopy(@Nullable T object) { - if (object == null) { - return null; - } else if (object instanceof Map) { - return (T) deepCopy((Map) object); - } else if (object instanceof List) { - return (T) deepCopy((List) object); - } else { - return object; - } - } - - @SuppressWarnings("unchecked") - @NotNull - private static T tryInstantiateOrDefault(@NotNull Class cls, @NotNull Supplier supplier) { - try { - return (T) MethodHandles.lookup().findConstructor(cls, MethodType.methodType(void.class)).invoke(); - } catch (Throwable ignored) { - return supplier.get(); - } - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/ByteNumberFormat.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/ByteNumberFormat.java deleted file mode 100644 index f858287ac75a..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/ByteNumberFormat.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils; - -import org.jkiss.code.NotNull; - -import java.text.DecimalFormat; -import java.text.FieldPosition; -import java.text.NumberFormat; -import java.text.ParsePosition; - -/** - * Bytes formatter - */ -public class ByteNumberFormat extends NumberFormat { - private static final long serialVersionUID = 1; - - public static final Unit[] UNITS = Unit.values(); - - private static final DecimalFormat fpFormat = new DecimalFormat("#.#"); - - private final BinaryPrefix binaryPrefix; - - /** - * Creates a new formatter. - */ - public ByteNumberFormat() { - binaryPrefix = BinaryPrefix.JEDEC; - } - - public ByteNumberFormat(@NotNull BinaryPrefix binaryPrefix) { - this.binaryPrefix = binaryPrefix; - } - - public static int computeIndex(double bytes) { - int index = 0; - - for (int i = 0; i < UNITS.length; i++) { - int result = (int)(bytes / 1024); - if (result == 0) { - break; - } else { - bytes /= 1024; - if (bytes < 1) { - break; - } - index++; - } - } - - return index; - } - - /** - * Returns a string representing the bytes. - * - * @param bytes the number of bytes. - * - * @return A string. - */ - public String getBytes(double bytes) { - - int index = computeIndex(bytes); - if (index >= UNITS.length) { - index = UNITS.length - 1; - } - - double intBytes = bytes; - if (intBytes == 0) { - return String.valueOf(0); - } - - for (int i = 0; i < index; i++) { - intBytes /= 1024; - } - - - String str; - if ((long)intBytes >= 10) { - str = String.valueOf((long)intBytes); - } else { - str = fpFormat.format(intBytes); - } - final Unit unit = UNITS[index]; - if (unit == Unit.BYTE) { - return str; - } - return str + (binaryPrefix == BinaryPrefix.ISO ? unit.isoPrefix : unit.jedecPrefix); - } - - /** - * Formats a number into the specified string buffer. - * - * @param number the number to format. - * @param toAppendTo the string buffer. - * @param pos the field position (ignored here). - * - * @return The string buffer. - */ - @Override - public StringBuffer format(double number, StringBuffer toAppendTo, - FieldPosition pos) { - return toAppendTo.append(getBytes(number)); - } - - /** - * Formats a number into the specified string buffer. - * - * @param number the number to format. - * @param toAppendTo the string buffer. - * @param pos the field position (ignored here). - * - * @return The string buffer. - */ - @Override - public StringBuffer format(long number, StringBuffer toAppendTo, - FieldPosition pos) { - return toAppendTo.append(getBytes(number)); - } - - /** - * This method returns null for all inputs. This class cannot - * be used for parsing. - * - * @param source the source string. - * @param parsePosition the parse position. - * - * @return null. - */ - @Override - public Number parse(String source, ParsePosition parsePosition) { - return null; - } - - private enum Unit { - BYTE("B", "B"), - KILOBYTE("K", "KiB"), - MEGABYTE("M", "MiB"), - GIGABYTE("G", "GiB"), - TERABYTE("T", "TiB"), - PETABYTE("P", "PiB"); - - private final String jedecPrefix; - private final String isoPrefix; - - Unit(String jedecPrefix, String isoPrefix) { - this.jedecPrefix = jedecPrefix; - this.isoPrefix = isoPrefix; - } - } - - /** - * A unit prefix for multiples of byte. - */ - public enum BinaryPrefix { - /** - * JEDEC-compliant prefixes (K, M, G, T, etc.). It's easy to confuse such prefixes with SI prefixes, leading to ambiguity. - */ - JEDEC, - - /** - * ISO 80000-13 format. This format explicitly states the binary nature of prefixes right in their names (kibi, mibi, gibi, etc.) - */ - ISO, - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/CommonUtils.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/CommonUtils.java deleted file mode 100644 index baad78ae2377..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/CommonUtils.java +++ /dev/null @@ -1,1066 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.utils; - -import org.jkiss.code.NotNull; -import org.jkiss.code.Nullable; - -import java.lang.reflect.InvocationTargetException; -import java.util.*; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Common utils - */ -public class CommonUtils { - - public static final char PARAGRAPH_CHAR = (char) 182; - - public static boolean isJavaIdentifier(@NotNull CharSequence str) { - if (str.length() == 0 || !Character.isJavaIdentifierStart(str.charAt(0))) { - return false; - } - for (int i = 1; i < str.length(); i++) { - if (!Character.isJavaIdentifierPart(str.charAt(i))) { - return false; - } - } - return true; - } - - @NotNull - public static String escapeJavaString(@NotNull String str) { - StringBuilder res = new StringBuilder(str.length() + 5); - for (int i = 0; i < str.length(); i++) { - char c = str.charAt(i); - switch (c) { - case '"' -> res.append("\\\""); - case '\n' -> res.append("\\n"); - case '\r' -> res.append("\\r"); - case '\t' -> res.append("\\t"); - default -> res.append(c); - } - } - return res.toString(); - } - - @Nullable - public static String escapeIdentifier(@Nullable String str) { - if (str == null) { - return null; - } - StringBuilder res = new StringBuilder(str.length()); - for (int i = 0; i < str.length(); i++) { - char c = str.charAt(i); - if (Character.isJavaIdentifierPart(c)) { - res.append(c); - } else { - if (res.length() == 0 || res.charAt(res.length() - 1) != '_') { - res.append('_'); - } - } - } - return res.toString(); - } - - @NotNull - public static String escapeFileName(@Nullable String str) { - if (str == null) { - return ""; - } - StringBuilder res = new StringBuilder(str.length()); - for (int i = 0; i < str.length(); i++) { - char c = str.charAt(i); - if (Character.isISOControl(c) || c == '\\' || c == '/' || c == '<' || c == '>' || c == '|' || c == '"' || c == ':' - || c == '*' || c == '?') { - res.append('_'); - } else { - res.append(c); - } - } - return res.toString(); - } - - public static String makeDirectoryName(@NotNull String str) { - if (!str.endsWith("/")) { - str += "/"; - } - return str; - } - - @NotNull - public static String removeTrailingSlash(@NotNull String str) { - while (str.endsWith("/") || str.endsWith("\\")) { - str = str.substring(0, str.length() - 1); - } - return str; - } - - @NotNull - public static String removeLeadingSlash(@NotNull String str) { - while (str.startsWith("/") || str.startsWith("\\")) { - str = str.substring(1); - } - return str; - } - - public static String capitalizeWord(String str) { - if (isEmpty(str) || Character.isUpperCase(str.charAt(0))) { - return str; - } - return Character.toUpperCase(str.charAt(0)) + str.substring(1); - } - - - public static String toCamelCase(String str) { - if (isEmpty(str)) { - return str; - } - - final StringBuilder ret = new StringBuilder(str.length()); - - boolean isWordStart = true; - for (int i = 0; i < str.length(); i++) { - char ch = str.charAt(i); - if (Character.isLetterOrDigit(ch)) { - if (isWordStart) { - ret.append(Character.toUpperCase(ch)); - isWordStart = false; - } else { - ret.append(Character.toLowerCase(ch)); - } - } else { - ret.append(ch); - isWordStart = true; - } - } - - return ret.toString(); - } - - @NotNull - public static T notNull(@Nullable T value, @NotNull T defaultValue) { - return value != null ? value : defaultValue; - } - - public static boolean isEmpty(@Nullable CharSequence value) { - return value == null || value.length() == 0; - } - - public static boolean isEmpty(@Nullable String value) { - return value == null || value.length() == 0; - } - - public static boolean isNotEmpty(@Nullable String value) { - return !isEmpty(value); - } - - public static boolean isEmpty(@Nullable Collection value) { - return value == null || value.isEmpty(); - } - - public static boolean isEmpty(@Nullable Map value) { - return value == null || value.isEmpty(); - } - - @Nullable - public static T getFirstOrNull(@NotNull Iterable iterable) { - Iterator iterator = iterable.iterator(); - if (iterator.hasNext()) { - return iterator.next(); - } - return null; - } - - @NotNull - public static Collection safeCollection(@Nullable Collection theList) { - if (theList == null) { - theList = Collections.emptyList(); - } - return theList; - } - - @NotNull - public static List singletonOrEmpty(@Nullable T object) { - if (object == null) { - return Collections.emptyList(); - } - return Collections.singletonList(object); - } - - @NotNull - public static List safeList(@Nullable List theList) { - if (theList == null) { - theList = Collections.emptyList(); - } - return theList; - } - - @NotNull - public static List copyList(@Nullable Collection theList) { - if (theList == null) { - return new ArrayList<>(); - } else { - return new ArrayList<>(theList); - } - } - - /** - * Swaps the element with its neighbor to the left in the specified list. - * If the element is not present in the list or it is the leftmost element in the list, - * the list remains unchanged. - * - * @param list list - * @param element element - * @param type of the list - */ - public static void shiftLeft(@NotNull List list, @NotNull T element) { - int idx = list.indexOf(element); - if (idx > 0) { - Collections.swap(list, idx - 1, idx); - } - } - - /** - * Swaps the element with its neighbor to the right in the specified list. - * If the element is not present in the list or it is the rightmost element in the list, - * the list remains unchanged. - * - * @param list list - * @param element element - * @param type of the list - */ - public static void shiftRight(@NotNull List list, @NotNull T element) { - int idx = list.indexOf(element); - if (idx != -1 && idx != list.size() - 1) { - Collections.swap(list, idx, idx + 1); - } - } - - @NotNull - public static String notEmpty(@Nullable String value) { - return value == null ? "" : value; - } - - @Nullable - public static String nullIfEmpty(@Nullable String value) { - return value == null || value.isEmpty() ? null : value; - } - - public static boolean isTrue(Boolean value) { - return value != null && value; - } - - public static boolean getBoolean(String value) { - return Boolean.parseBoolean(value); - } - - public static boolean getBoolean(@Nullable String value, boolean defaultValue) { - return isEmpty(value) ? defaultValue : Boolean.parseBoolean(value); - } - - public static boolean getBoolean(@Nullable Object value, boolean defaultValue) { - if (value == null) { - return defaultValue; - } else if (value instanceof Boolean b) { - return b; - } else { - return getBoolean(value.toString(), defaultValue); - } - } - - @NotNull - public static String getLineSeparator() { - String lineSeparator = System.getProperty(StandardConstants.ENV_LINE_SEPARATOR); - return lineSeparator == null ? "\n" : lineSeparator; - } - - @NotNull - public static Throwable getRootCause(@NotNull Throwable ex) { - Throwable rootCause = ex; - for (; ; ) { - if (rootCause.getCause() != null) { - rootCause = rootCause.getCause(); - } else if (rootCause instanceof InvocationTargetException ite && ite.getTargetException() != null) { - rootCause = ite.getTargetException(); - } else { - break; - } - } - return rootCause; - } - - public static boolean equalObjects(@Nullable Object o1, @Nullable Object o2) { - if (o1 == o2) { - return true; - } - if (o1 == null || o2 == null) { - return false; - } -// if (o1.getClass() != o2.getClass()) { -// return false; -// } - return o1.equals(o2); - } - - public static boolean equalOrEmptyStrings(@Nullable String s1, @Nullable String s2) { - return equalObjects(s1, s2) || (isEmpty(s1) && isEmpty(s2)); - } - - public static boolean equalsContents(@Nullable Collection c1, @Nullable Collection c2) { - if (CommonUtils.isEmpty(c1) && CommonUtils.isEmpty(c2)) { - return true; - } - if (c1 == null || c2 == null || c1.size() != c2.size()) { - return false; - } - for (Object o : c1) { - if (!c2.contains(o)) { - return false; - } - } - return true; - } - - @NotNull - public static String toString(@Nullable Object object) { - if (object == null) { - return ""; - } else if (object instanceof String s) { - return s; - } else { - String strValue = object.toString(); - return strValue == null ? "" : strValue; - } - } - - public static String toString(@Nullable Object object, String def) { - if (object == null) { - return def; - } else if (object instanceof String s) { - return s; - } else { - return object.toString(); - } - } - - public static boolean toBoolean(@Nullable Object object) { - return object != null && getBoolean(object.toString()); - } - - public static int toInt(@Nullable Object object, int def) { - if (object == null) { - return def; - } else if (object instanceof Number n) { - return n.intValue(); - } else { - try { - return Integer.parseInt(toString(object)); - } catch (NumberFormatException e) { - try { - return (int)Double.parseDouble(toString(object)); - } catch (NumberFormatException e1) { - e1.printStackTrace(); - return def; - } - } - } - } - - public static int toInt(@Nullable Object object) { - return toInt(object, 0); - } - - public static boolean isInt(@Nullable Object object) { - if (object == null) { - return false; - } else if (object instanceof Number) { - return true; - } else { - try { - Integer.parseInt(toString(object)); - return true; - } catch (NumberFormatException e) { - return false; - } - } - } - public static long toLong(@Nullable Object object) { - return toLong(object, 0); - } - - public static long toLong(@Nullable Object object, long defValue) { - if (object == null) { - return defValue; - } else if (object instanceof Number n) { - return n.longValue(); - } else { - try { - return Long.parseLong(toString(object)); - } catch (NumberFormatException e) { - try { - return (int)Double.parseDouble(toString(object)); - } catch (NumberFormatException e1) { - return defValue; - } - } - } - } - - public static boolean isLong(@Nullable Object object) { - if (object == null) { - return false; - } else if (object instanceof Number) { - return true; - } else { - try { - Long.parseLong(toString(object)); - return true; - } catch (NumberFormatException e) { - return false; - } - } - } - - public static boolean isNumber(@Nullable Object object) { - if (object == null) { - return false; - } else if (object instanceof Number) { - return true; - } else { - try { - Double.parseDouble(toString(object)); - return true; - } catch (NumberFormatException e) { - return false; - } - } - } - - public static double toDouble(@Nullable Object object) { - if (object == null) { - return 0.0; - } else if (object instanceof Number) { - return ((Number) object).doubleValue(); - } else { - try { - return Double.parseDouble(toString(object)); - } catch (NumberFormatException e) { - return Double.NaN; - } - } - } - - public static double toDouble(@Nullable Object object, double def) { - if (object == null) { - return def; - } else if (object instanceof Number) { - return ((Number) object).doubleValue(); - } else { - try { - return Double.parseDouble(toString(object)); - } catch (NumberFormatException e) { - return def; - } - } - } - - public static float toFloat(@Nullable Object object) { - if (object == null) { - return 0.0f; - } else if (object instanceof Number) { - return ((Number) object).floatValue(); - } else { - try { - return Float.parseFloat(toString(object)); - } catch (NumberFormatException e) { - return Float.NaN; - } - } - } - - public static float toFloat(@Nullable Object object, float def) { - if (object == null) { - return def; - } else if (object instanceof Number) { - return ((Number) object).floatValue(); - } else { - try { - return Float.parseFloat(toString(object)); - } catch (NumberFormatException e) { - return def; - } - } - } - - public static boolean isNaN(@Nullable Object value) { - return (value instanceof Float && ((Float) value).isNaN()) - || (value instanceof Double && ((Double) value).isNaN()); - } - - public static boolean isInfinite(@Nullable Object value) { - return (value instanceof Float && ((Float) value).isInfinite()) - || (value instanceof Double && ((Double) value).isInfinite()); - } - - @NotNull - public static String toHexString(@Nullable byte[] bytes) { - return bytes == null ? "" : toHexString(bytes, 0, bytes.length); - } - - final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); - - @NotNull - public static String toHexString(@Nullable byte[] bytes, int offset, int length) { - if (bytes == null || bytes.length == 0) { - return ""; - } - char[] hexChars = new char[length * 2]; - for (int i = 0; i < length; i++) { - int v = bytes[offset + i] & 0xFF; - hexChars[i * 2] = hexArray[v >>> 4]; - hexChars[i * 2 + 1] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } - - public static byte[] parseHexString(String hex) { - int strLength = hex.length(); - byte[] data = new byte[strLength / 2]; - for (int i = 0; i < strLength; i += 2) { - data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i+1), 16)); - } - return data; - } - - public static String toBinaryString(long longValue, int bitCount) { - String strValue = Long.toString(longValue, 2); - if (strValue.length() < bitCount) { - char[] headZeroes = new char[bitCount - strValue.length()]; - Arrays.fill(headZeroes, '0'); - strValue = String.valueOf(headZeroes) + strValue; - } - return strValue; - } - - public static String[] splitWithDelimiter(String s, String delimiter) { - if (s == null) { - return null; - } - String delimiterReplacement = "DRDRDR"; //$NON-NLS-1$ - s = s.replace(delimiter, delimiterReplacement + delimiter); - return s.split(delimiterReplacement); - } - - @NotNull - public static List splitString(@Nullable String str, char delimiter) { - if (CommonUtils.isEmpty(str)) { - return Collections.emptyList(); - } else { - List result = new ArrayList<>(); - StringTokenizer st = new StringTokenizer(str, String.valueOf(delimiter)); - while (st.hasMoreTokens()) { - result.add(st.nextToken()); - } - return result; - } - } - - @NotNull - public static String[] split(@Nullable String str, String delimiter) { - if (CommonUtils.isEmpty(str)) { - return new String[0]; - } else { - return str.split(delimiter); - } - } - - @NotNull - public static String makeString(@Nullable List tokens, char delimiter) { - if (tokens == null) { - return ""; - } else if (tokens.size() == 1) { - return tokens.get(0); - } else { - StringBuilder buf = new StringBuilder(); - for (String token : tokens) { - if (buf.length() > 0) { - buf.append(delimiter); - } - buf.append(token); - } - return buf.toString(); - } - } - - @Nullable - public static String truncateString(@Nullable String str, int maxLength) { - if (str != null && str.length() > maxLength) { - return str.substring(0, maxLength); - } - return str; - } - - public static String joinStrings(String divider, String ... array) { - if (array == null) return ""; - StringBuilder str = new StringBuilder(); - for (int i = 0; i < array.length; i++) { - if (i > 0) str.append(divider); - str.append(array[i]); - } - return str.toString(); - } - - public static String joinStrings(String divider, Collection col) { - if (col == null) return ""; - StringBuilder str = new StringBuilder(); - for (String item : col) { - if (str.length() > 0) str.append(divider); - str.append(item); - } - return str.toString(); - } - - public static boolean isEmptyTrimmed(@Nullable String str) { - return str == null || str.length() == 0 || str.trim().length() == 0; - } - - public static boolean isBitSet(int value, int mask) { - return (value & mask) == mask; - } - - public static boolean isBitSet(long value, long mask) { - return (value & mask) == mask; - } - - @Nullable - public static > T valueOf(@NotNull Class type, @Nullable String name) { - return valueOf(type, name, null, false); - } - - @Nullable - public static > T valueOf(@NotNull Class type, @Nullable String name, T defValue, boolean underscoreSpaces) { - if (name == null) { - return defValue; - } - name = name.trim(); - if (name.length() == 0) { - return defValue; - } - if (underscoreSpaces) { - name = name.replace(' ', '_'); - } - try { - return Enum.valueOf(type, name); - } catch (Exception e) { - e.printStackTrace(); - return defValue; - } - } - - public static > T valueOf(Class enumType, String str, T defValue) { - if (isEmpty(str)) { - return defValue; - } - try { - return Enum.valueOf(enumType, str); - } catch (Exception e) { - e.printStackTrace(); - return defValue; - } - } - - @NotNull - public static T getItem(@NotNull Collection collection, int index) { - if (collection instanceof List) { - return ((List) collection).get(index); - } else { - Iterator iter = collection.iterator(); - for (int i = 0; i < index; i++) { - iter.next(); - } - return iter.next(); - } - } - - @NotNull - public static > T fromOrdinal(Class enumClass, int ordinal) { - T[] enumConstants = enumClass.getEnumConstants(); - for (T value : enumConstants) { - if (value.ordinal() == ordinal) { - return value; - } - } - IllegalArgumentException error = new IllegalArgumentException("Invalid ordinal " + ordinal + " for type " + enumClass.getName()); - if (enumConstants.length == 0) { - throw error; - } else { - error.printStackTrace(System.err); - return enumConstants[0]; - } - } - - @NotNull - public static List filterCollection(@NotNull Collection collection, @NotNull Class type) { - List result = new ArrayList<>(); - for (Object item : collection) { - if (type.isInstance(item)) { - result.add(type.cast(item)); - } - } - return result; - } - - @NotNull - public static String escapeDisplayString(@NotNull final String delim) { - StringBuilder str = new StringBuilder(); - for (int i = 0; i < delim.length(); i++) { - char c = delim.charAt(i); - if (c == '\n') { - str.append("\\n"); - } else if (c == '\r') { - str.append("\\r"); - } else if (c == '\t') { - str.append("\\t"); - } else { - str.append(c); - } - } - return str.toString(); - } - - @NotNull - public static String unescapeDisplayString(@NotNull final String delim) { - return delim.replace("\\t", "\t").replace("\\n", "\n").replace("\\r", "\r"); - } - - public static int hashCode(@Nullable Object obj) { - return obj == null ? 0 : obj.hashCode(); - } - - public static T getOption(Map options, String name, T defValue) { - Object optionValue = options.get(name); - if (optionValue == null) { - return defValue; - } - return (T)optionValue; - } - - public static boolean getOption(Map options, String name) { - return getOption(options, name, false); - } - - public static boolean getOption(Map options, String name, boolean defValue) { - if (options == null) { - return false; - } - Object optionValue = options.get(name); - return getBoolean(optionValue, defValue); - } - - public static Map makeStringMap(Map objMap) { - Map strMap = new LinkedHashMap<>(objMap.size()); - for (Map.Entry e : objMap.entrySet()) { - strMap.put(toString(e.getKey(), null), e.getValue()); - } - return strMap; - } - - public static String fixedLengthString(String string, int length) { - return String.format("%1$"+length+ "s", string); - } - - public static boolean startsWithIgnoreCase(@Nullable String str, @Nullable String startPart) { - if (isEmpty(str) || isEmpty(startPart)) { - return false; - } - return str.regionMatches(true, 0, startPart, 0, startPart.length()); - } - - public static String niceFormatFloat(float val) { - if (val == (int) val) - return String.valueOf((int)val); - else - return String.valueOf(val); - } - - public static String niceFormatDouble(double val) { - if (val == (long) val) - return String.valueOf((long)val); - else - return String.valueOf(val); - } - - public static String trim(String str) { - return str == null ? null : str.trim(); - } - - public static String compactWhiteSpaces(String str) { - return str.replaceAll("\\s+", " "); - } - - public static String getSingleLineString(String displayString) { - return displayString - .replace('\n', PARAGRAPH_CHAR) - .replace("\r", "") - .replace("\t", " ") - .replace((char)0, ' '); - } - - public static int compare(Object o1, Object o2) { - if (o1 == o2) { - return 0; - } - if (o1 == null) { - return -1; - } else if (o2 == null) { - return 1; - } - if (o1.getClass() == o2.getClass() && o1 instanceof Comparable) { - return ((Comparable) o1).compareTo(o2); - } - return toString(o1).compareTo(toString(o2)); - } - - public static int compareNumbers(Number value1, Number value2) { - double numDiff = value1.doubleValue() - value2.doubleValue(); - return numDiff < 0 ? -1 : (numDiff > 0 ? 1 : 0); - } - - public static String cutExtraLines(String message, int maxLines) { - if (message == null || message.indexOf('\n') == -1) { - return message; - } - int lfCount = 0; - StringBuilder buf = new StringBuilder(); - for (int i = 0; i < message.length(); i++) { - char c = message.charAt(i); - if (c == '\n') { - lfCount++; - } - buf.append(c); - if (lfCount == maxLines) { - buf.append("..."); - break; - } - } - return buf.toString(); - } - - public static boolean isSameDay(@NotNull Date date1, @NotNull Date date2) { - Calendar cal1 = Calendar.getInstance(); - cal1.setTime(date1); - Calendar cal2 = Calendar.getInstance(); - cal2.setTime(date2); - return isSameDay(cal1, cal2); - } - - public static boolean isSameDay(@NotNull Calendar cal1, @NotNull Calendar cal2) { - return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && - cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && - cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)); - } - - public static String escapeBourneShellString(@NotNull String s) { - return "'" + s.replace("'", "'\\''") + "'"; - } - - public static String unescapeBourneShellString(@NotNull String s) { - if (!s.startsWith("'") || !s.endsWith("'") || s.length() < 2) { //not an escaped bourne shell string - return s; - } - return s.substring(1, s.length() - 1).replace("'\\''", "'"); - } - - /** - * Checks whether the supplied ch is within - * the range of the specified radix value. - * - * @param ch character codepoint to be checked - * @param radix desired radix - * @return true if the character fits - * into the radix, false otherwise - */ - public static boolean isDigit(int ch, int radix) { - if (radix <= 0 || radix > 36) - return false; - if (ch >= '0' && ch <= '9') - return radix > ch - '0'; - if (ch >= 'a' && ch <= 'z') - return radix > ch - 'a' + 10; - if (ch >= 'A' && ch <= 'Z') - return radix > ch - 'A' + 10; - return false; - } - - /** - * Checks if the {@code index} is within the bounds of the range from - * {@code 0} (inclusive) to {@code length} (exclusive). - * - *

The {@code index} is defined to be out of bounds if any of the - * following inequalities is true: - *

- * - * @param index the index - * @param length the upper-bound (exclusive) of the range - * @return {@code true} if it is within bounds of the range - */ - public static boolean isValidIndex(int index, int length) { - return 0 <= index && index < length; - } - - @NotNull - public static String escapeHtml(@Nullable String text) { - if (text == null) { - return " "; - } - return text - .replace("&", "&") - .replace("<", "<") - .replace(">", ">") - .replace("\r\n", "
") - .replace("\r", "
") - .replace("\n", "
"); - } - - /** - * Finds the object with the best matching name. Here we consider a case sensitive match better then a case insensitive one. - * - * @param objects container with objects - * @param name to match - * @param nameExtractor function which extracts the name from object - * @param type of objects to search from - * @return the best match or {@code null} if nothing found - */ - @Nullable - public static T findBestCaseAwareMatch(@NotNull Iterable objects, @NotNull String name, - @NotNull Function nameExtractor) { - T firstCaseInsensitiveMatch = null; - for (T obj: objects) { - String objectName = nameExtractor.apply(obj); - if (name.equals(objectName)) { //case sensitive match - return obj; - } - if (firstCaseInsensitiveMatch == null && name.equalsIgnoreCase(objectName)) { - firstCaseInsensitiveMatch = obj; - } - } - return firstCaseInsensitiveMatch; - } - - /** - * Groups values into a map of their shared key and a list of matching values using that key. - *

- *

Group strings by their first character

- *
{@code
-     * final List values = Arrays.asList("aaa", "abb", "bbb", "bab", "ccc");
-     * final Map> groups = group(values, x -> x.charAt(0));
-     *
-     * Assert.assertEquals(Arrays.asList("aaa", "abb"), groups.get('a'));
-     * Assert.assertEquals(Arrays.asList("bbb", "bab"), groups.get('b'));
-     * Assert.assertEquals(Arrays.asList("ccc"), groups.get('c'));
-     * }
- * @param values values to group - * @param keyExtractor a function that extracts key from value that is used to group values - * @return map of a shared key and a list of matching values - */ - @NotNull - public static Map> group(@NotNull Collection values, @NotNull Function keyExtractor) { - final Map> grouped = new HashMap<>(); - for (V value : values) { - final K key = keyExtractor.apply(value); - final List group = grouped.computeIfAbsent(key, k -> new ArrayList<>()); - group.add(value); - } - return grouped; - } - - /** - * Clamps given value to range between lower and upper bounds. - * - * @param value the value to clamp - * @param min the lower boundary to clamp {@code value} to - * @param max the upper boundary to clamp {@code value} to - * @return {@code min} if {@code value} is less than {@code min}, {@code max} if {@code value} is greater than {@code max}, otherwise {@code value} - */ - public static int clamp(int value, int min, int max) { - return Math.max(min, Math.min(value, max)); - } - - /** - * Replaces every subsequence of the input sequence that matches the - * pattern with the result of applying the given replacer function to the - * match result of this matcher corresponding to that subsequence. - */ - @NotNull - public static String replaceAll(@NotNull String input, @NotNull String regex, @NotNull Function replacer) { - Matcher matcher = Pattern.compile(regex).matcher(input); - StringBuilder sb = new StringBuilder(); - while (matcher.find()) { - matcher.appendReplacement(sb, replacer.apply(matcher)); - } - matcher.appendTail(sb); - return sb.toString(); - } - - @SafeVarargs - public static T[] array(T... elems) { - return elems; - } - - /** - * Removes (single or multiple) starting '/' from {@code resourcePath} and replaces all '\' with '/' - */ - @NotNull - public static String normalizeResourcePath(@NotNull String resourcePath) { - while (resourcePath.startsWith("/")) { - resourcePath = resourcePath.substring(1); - } - resourcePath = resourcePath.replace('\\', '/'); - return resourcePath; - } - - /** - * Replaces the last {@code toReplace} entry in {@code string} with {@code replacement} - */ - @NotNull - public static String replaceLast(@NotNull String string, @NotNull String toReplace, @NotNull String replacement) { - int pos = string.lastIndexOf(toReplace); - if (pos > -1) { - return string.substring(0, pos) - + replacement - + string.substring(pos + toReplace.length()); - } else { - return string; - } - } - - /** - * Sets prefix for sql queries params (f.e. schema names for tables) - */ - @NotNull - public static String normalizeTableNames(@NotNull String sql, @Nullable String prefix) { - return sql.replaceAll("\\{table_prefix}", isEmpty(prefix) ? "" : prefix + "."); - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/IOUtils.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/IOUtils.java deleted file mode 100644 index 27eeb4943acc..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/IOUtils.java +++ /dev/null @@ -1,444 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.utils; - -import org.jkiss.code.NotNull; -import org.jkiss.code.Nullable; - -import java.io.*; -import java.net.ServerSocket; -import java.net.URI; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; -import java.nio.file.Files; -import java.nio.file.InvalidPathException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Comparator; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; - -/** - * Some IO helper functions - */ -public final class IOUtils { - - public static final int DEFAULT_BUFFER_SIZE = 16384; - - private static final boolean USE_NIO_STREAMS = false; - - public static void close(Closeable closeable) { - try { - closeable.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static void close(AutoCloseable closeable) { - try { - closeable.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public static void fastCopy(final InputStream src, final OutputStream dest) throws IOException { - fastCopy(src, dest, DEFAULT_BUFFER_SIZE); - } - - public static void fastCopy(final InputStream src, final OutputStream dest, int bufferSize) throws IOException { - if (USE_NIO_STREAMS) { - final ReadableByteChannel inputChannel = Channels.newChannel(src); - final WritableByteChannel outputChannel = Channels.newChannel(dest); - fastCopy(inputChannel, outputChannel, bufferSize); - } else { - copyStream(src, dest, bufferSize); - } - } - - public static void fastCopy(final ReadableByteChannel src, final WritableByteChannel dest, int bufferSize) throws IOException { - final ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize); - - while (src.read(buffer) != -1) { - flipBuffer(buffer); - dest.write(buffer); - buffer.compact(); - } - - flipBuffer(buffer); - - while (buffer.hasRemaining()) { - dest.write(buffer); - } - } - - public static void flipBuffer(Buffer buffer) { - buffer.flip(); - } - - public static void copyStream( - java.io.InputStream inputStream, - java.io.OutputStream outputStream) - throws IOException { - copyStream(inputStream, outputStream, DEFAULT_BUFFER_SIZE); - } - - /** - * Read entire input stream and writes all data to output stream - * then closes input and flushed output - */ - public static void copyStream( - java.io.InputStream inputStream, - java.io.OutputStream outputStream, - int bufferSize) - throws IOException { - try { - byte[] writeBuffer = new byte[bufferSize]; - for (int br = inputStream.read(writeBuffer); br != -1; br = inputStream.read(writeBuffer)) { - outputStream.write(writeBuffer, 0, br); - } - outputStream.flush(); - } finally { - // Close input stream - inputStream.close(); - } - } - - /** - * Read entire input stream portion and writes it data to output stream - */ - public static void copyStreamPortion( - java.io.InputStream inputStream, - java.io.OutputStream outputStream, - int portionSize, - int bufferSize) - throws IOException { - if (bufferSize > portionSize) { - bufferSize = portionSize; - } - byte[] writeBuffer = new byte[bufferSize]; - int totalRead = 0; - while (totalRead < portionSize) { - int bytesToRead = bufferSize; - if (bytesToRead > portionSize - totalRead) { - bytesToRead = portionSize - totalRead; - } - int bytesRead = inputStream.read(writeBuffer, 0, bytesToRead); - outputStream.write(writeBuffer, 0, bytesRead); - totalRead += bytesRead; - } - - // Close input stream - outputStream.flush(); - } - - public static String toString(File file, String encoding) throws IOException { - try (InputStream is = new FileInputStream(file)) { - try (Reader reader = new InputStreamReader(is, encoding)) { - StringWriter writer = new StringWriter(); - copyText(reader, writer, DEFAULT_BUFFER_SIZE); - return writer.toString(); - } - } - } - - /** - * Read entire reader content and writes it to writer - * then closes reader and flushed output. - */ - public static void copyText( - java.io.Reader reader, - java.io.Writer writer, - int bufferSize) - throws IOException { - char[] writeBuffer = new char[bufferSize]; - for (int br = reader.read(writeBuffer); br != -1; br = reader.read(writeBuffer)) { - writer.write(writeBuffer, 0, br); - } - writer.flush(); - } - - public static void copyText( - java.io.Reader reader, - java.io.Writer writer) - throws IOException { - copyText(reader, writer, DEFAULT_BUFFER_SIZE); - } - - public static byte[] readFileToBuffer(File file) throws IOException { - byte[] buffer = new byte[(int) file.length()]; - try (InputStream is = new FileInputStream(file)) { - readStreamToBuffer(is, buffer); - } - return buffer; - } - - public static void writeFileFromBuffer(File file, byte[] buffer) throws IOException { - try (OutputStream os = new FileOutputStream(file)) { - os.write(buffer); - } - } - - public static void writeFileFromString(File file, String str) throws IOException { - try (Writer os = new FileWriter(file)) { - os.write(str); - } - } - - public static int readStreamToBuffer( - java.io.InputStream inputStream, - byte[] buffer) - throws IOException { - int totalRead = 0; - while (totalRead != buffer.length) { - int br = inputStream.read(buffer, totalRead, buffer.length - totalRead); - if (br == -1) { - break; - } - totalRead += br; - } - return totalRead; - } - - public static String readLine(java.io.InputStream input) - throws IOException { - StringBuilder linebuf = new StringBuilder(); - for (int b = input.read(); b != '\n'; b = input.read()) { - if (b == -1) { - if (linebuf.length() == 0) { - return null; - } else { - break; - } - } - if (b != '\r') { - linebuf.append((char) b); - } - } - return linebuf.toString(); - } - - public static String readFullLine(java.io.InputStream input) - throws IOException { - StringBuilder linebuf = new StringBuilder(); - for (int b = input.read(); ; b = input.read()) { - if (b == -1) { - if (linebuf.length() == 0) { - return null; - } else { - break; - } - } - linebuf.append((char) b); - if (b == '\n') { - break; - } - } - return linebuf.toString(); - } - - public static int findFreePort(int minPort, int maxPort) { - int portRange = Math.abs(maxPort - minPort); - while (true) { - int portNum = minPort + SecurityUtils.getRandom().nextInt(portRange); - try { - ServerSocket socket = new ServerSocket(portNum); - try { - socket.close(); - } catch (IOException e) { - // just skip - } - return portNum; - } catch (IOException e) { - // Port is busy - } - } - } - - public static String readToString(Reader is) throws IOException { - StringBuilder result = new StringBuilder(4000); - char[] buffer = new char[4000]; - for (; ; ) { - int count = is.read(buffer); - if (count <= 0) { - break; - } - result.append(buffer, 0, count); - } - return result.toString(); - } - - static void copyZipStream(InputStream inputStream, OutputStream outputStream) - throws IOException - { - byte[] writeBuffer = new byte[IOUtils.DEFAULT_BUFFER_SIZE]; - for (int br = inputStream.read(writeBuffer); br != -1; br = inputStream.read(writeBuffer)) { - outputStream.write(writeBuffer, 0, br); - } - outputStream.flush(); - } - - public static void extractZipArchive(InputStream stream, Path targetFolder) throws IOException { - try (ZipInputStream zipStream = new ZipInputStream(stream)) { - for (; ; ) { - ZipEntry zipEntry = zipStream.getNextEntry(); - if (zipEntry == null) { - break; - } - try { - if (!zipEntry.isDirectory()) { - String zipEntryName = zipEntry.getName(); - checkAndExtractEntry(zipStream, zipEntry, targetFolder); - } - } finally { - zipStream.closeEntry(); - } - } - } - } - - private static void checkAndExtractEntry(InputStream zipStream, ZipEntry zipEntry, Path targetFolder) throws IOException { - if (!Files.exists(targetFolder)) { - try { - Files.createDirectories(targetFolder); - } catch (IOException e) { - throw new IOException("Can't create local cache folder '" + targetFolder.toAbsolutePath() + "'", e); - } - } - Path localFile = targetFolder.resolve(zipEntry.getName()); - if (!localFile.normalize().startsWith(targetFolder.normalize())) { - throw new IOException("Zip entry is outside of the target directory"); - } - if (Files.exists(localFile)) { - // Already extracted? - return; - } - Path localDir = localFile.getParent(); - if (!Files.exists(localDir)) { // in case of localFile located in subdirectory inside zip archive - try { - Files.createDirectories(localDir); - } catch (IOException e) { - throw new IOException("Can't create local file directory in the cache '" + localDir.toAbsolutePath() + "'", e); - } - } - try (OutputStream os = Files.newOutputStream(localFile)) { - copyZipStream(zipStream, os); - } - } - - - public static void zipFolder(final File folder, final OutputStream outputStream) throws IOException { - try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) { - processFolder(folder, zipOutputStream, folder.getPath().length() + 1); - } - } - - private static void processFolder(final File folder, final ZipOutputStream zipOutputStream, final int prefixLength) throws IOException { - File[] folderFiles = folder.listFiles(); - if (folderFiles == null) { - return; - } - for (File file : folderFiles) { - BasicFileAttributes fAttrs = Files.readAttributes(file.toPath(), BasicFileAttributes.class); - if (fAttrs.isRegularFile()) { - final ZipEntry zipEntry = new ZipEntry(file.getPath().substring(prefixLength)); - zipOutputStream.putNextEntry(zipEntry); - try (FileInputStream inputStream = new FileInputStream(file)) { - IOUtils.copyStream(inputStream, zipOutputStream); - } - zipOutputStream.closeEntry(); - } else if (fAttrs.isDirectory()) { - processFolder(file, zipOutputStream, prefixLength); - } - } - } - public static void deleteDirectory(@NotNull Path path) throws IOException { - Files.walk(path) - .sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); - } - - @Nullable - public static String getDirectoryPath(@NotNull String sPath) throws InvalidPathException { - final Path path = Paths.get(sPath); - if (Files.isDirectory(path)) { - return path.toString(); - } else { - final Path parent = path.getParent(); - if (parent != null) { - return parent.toString(); - } - } - return null; - } - - @NotNull - public static String getFileNameWithoutExtension(Path file) { - String fileName = file.getFileName().toString(); - int divPos = fileName.lastIndexOf('.'); - if (divPos != -1) { - return fileName.substring(0, divPos); - } - return fileName; - } - - @Nullable - public static String getFileExtension(Path file) { - String fileName = file.getFileName().toString(); - return getFileExtension(fileName); - } - - @Nullable - public static String getFileExtension(String fileName) { - int divPos = fileName.lastIndexOf('.'); - if (divPos != -1) { - return fileName.substring(divPos + 1); - } - return null; - } - - @NotNull - public static Path getPathFromString(@NotNull String pathOrUri) { - if (pathOrUri.contains("://")) { - return Path.of(URI.create(pathOrUri)); - } else { - return Path.of(pathOrUri); - } - } - - - public static boolean isLocalFile(String filePath) { - return !filePath.contains("://") || filePath.startsWith("file:"); - } - - public static boolean isLocalURI(URI uri) { - return uri.getScheme().equals("file"); - } - - public static boolean isLocalPath(Path filePath) { - return isLocalURI(filePath.toUri()); - } - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/IntKeyMap.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/IntKeyMap.java deleted file mode 100644 index b97960eee9c7..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/IntKeyMap.java +++ /dev/null @@ -1,807 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils; - -import java.util.*; - -/** - Map with int key. -*/ -@SuppressWarnings("unchecked") -public class IntKeyMap implements Map { - /** - * The default initial capacity - MUST be a power of two. - */ - static final int DEFAULT_INITIAL_CAPACITY = 16; - - /** - * The maximum capacity, used if a higher value is implicitly specified - * by either of the constructors with arguments. - * MUST be a power of two <= 1<<30. - */ - static final int MAXIMUM_CAPACITY = 1 << 30; - - /** - * The load fast used when none specified in constructor. - **/ - static final float DEFAULT_LOAD_FACTOR = 0.75f; - - /** - * The table, resized as necessary. Length MUST Always be a power of two. - */ - transient IntEntry[] table; - - /** - * The number of key-value mappings contained in this identity hash map. - */ - transient int size; - - /** - * The next size value at which to resize (capacity * load factor). - * @serial - */ - int threshold; - - /** - * The load factor for the hash table. - * - * @serial - */ - final float loadFactor; - - /** - * The number of times this IntKeyMap has been structurally modified - */ - transient volatile int modCount; - - /** - * Constructs an empty IntKeyMap with the specified initial - * capacity and load factor. - * - * @param initialCapacity The initial capacity. - * @param loadFactor The load factor. - * @throws IllegalArgumentException if the initial capacity is negative - * or the load factor is nonpositive. - */ - public IntKeyMap(int initialCapacity, float loadFactor) { - if (initialCapacity < 0) - throw new IllegalArgumentException("Illegal initial capacity: " + - initialCapacity); - if (initialCapacity > MAXIMUM_CAPACITY) - initialCapacity = MAXIMUM_CAPACITY; - if (loadFactor <= 0 || Float.isNaN(loadFactor)) - throw new IllegalArgumentException("Illegal load factor: " + - loadFactor); - - // Find a power of 2 >= initialCapacity - int capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; - - this.loadFactor = loadFactor; - threshold = (int)(capacity * loadFactor); - table = new IntEntry[capacity]; - } - - /** - * Constructs an empty IntKeyMap with the specified initial - * capacity and the default load factor (0.75). - * - * @param initialCapacity the initial capacity. - * @throws IllegalArgumentException if the initial capacity is negative. - */ - public IntKeyMap(int initialCapacity) { - this(initialCapacity, DEFAULT_LOAD_FACTOR); - } - - /** - * Constructs an empty IntKeyMap with the default initial capacity - * (16) and the default load factor (0.75). - */ - public IntKeyMap() { - this.loadFactor = DEFAULT_LOAD_FACTOR; - threshold = DEFAULT_INITIAL_CAPACITY; - table = new IntEntry[DEFAULT_INITIAL_CAPACITY]; - } - - static int hash(long x) { - int h = (int)(x ^ (x >>> 32)); - h += ~(h << 9); - h ^= (h >>> 14); - h += (h << 4); - h ^= (h >>> 10); - return h; - } - - /** - * Returns index for hash code h. - */ - static int indexFor(int h, int length) { - return h & (length-1); - } - - /** - * Returns the number of key-value mappings in this map. - * - * @return the number of key-value mappings in this map. - */ - @Override - public int size() { - return size; - } - - /** - * Returns true if this map contains no key-value mappings. - * - * @return true if this map contains no key-value mappings. - */ - @Override - public boolean isEmpty() - { - return size == 0; - } - - @Override - public boolean containsKey(Object key) - { - return containsKey(((Number)key).intValue()); - } - - /** - * Returns the value to which the specified key is mapped in this identity - * hash map, or null if the map contains no mapping for this key. - * A return value of null does not necessarily indicate - * that the map contains no mapping for the key; it is also possible that - * the map explicitly maps the key to null. The - * containsKey method may be used to distinguish these two cases. - * - * @param key the key whose associated value is to be returned. - * @return the value to which this map maps the specified key, or - * null if the map contains no mapping for this key. - * @see #put(int, Object) - */ - public VALUE get(int key) { - int hash = hash(key); - int i = indexFor(hash, table.length); - IntEntry e = table[i]; - while (true) { - if (e == null) - return null; - if (e.hash == hash && key == e.key) - return e.value; - e = e.next; - } - } - - /** - * Returns true if this map contains a mapping for the - * specified key. - */ - public boolean containsKey(int key) - { - int hash = hash(key); - int i = indexFor(hash, table.length); - IntEntry e = table[i]; - while (e != null) { - if (e.hash == hash && key == e.key) - return true; - e = e.next; - } - return false; - } - - /** - * Returns the entry associated with the specified key in the - * IntKeyMap. Returns null if the IntKeyMap contains no mapping - * for this key. - */ - IntEntry getEntry(int key) { - int hash = hash(key); - int i = indexFor(hash, table.length); - IntEntry e = table[i]; - while (e != null && !(e.hash == hash && key == e.key)) - e = e.next; - return e; - } - - /** - * Associates the specified value with the specified key in this map. - * If the map previously contained a mapping for this key, the old - * value is replaced. - * - * @param key key with which the specified value is to be associated. - * @param value value to be associated with the specified key. - * @return previous value associated with specified key, or null - * if there was no mapping for key. A null return can - * also indicate that the IntKeyMap previously associated - * null with the specified key. - */ - public VALUE put(int key, VALUE value) { - int hash = hash(key); - int i = indexFor(hash, table.length); - - for (IntEntry e = table[i]; e != null; e = e.next) { - if (e.hash == hash && key == e.key) { - VALUE oldValue = e.value; - e.value = value; - return oldValue; - } - } - - modCount++; - addEntry(hash, key, value, i); - return null; - } - - /** - * This method is used instead of put by constructors and - * pseudoconstructors (clone, readObject). It does not resize the table, - * check for comodification, etc. It calls createEntry rather than - * addEntry. - */ - private void putForCreate(int key, VALUE value) { - int hash = hash(key); - int i = indexFor(hash, table.length); - - /** - * Look for preexisting entry for key. This will never happen for - * clone or deserialize. It will only happen for construction if the - * input Map is a sorted map whose ordering is inconsistent w/ equals. - */ - for (IntEntry e = table[i]; e != null; e = e.next) { - if (e.hash == hash && key == e.key) { - e.value = value; - return; - } - } - - createEntry(hash, key, value, i); - } - - void putAllForCreate(IntKeyMap m) { - for (Iterator i = m.entrySet().iterator(); i.hasNext(); ) { - IntEntry e = (IntEntry) i.next(); - putForCreate(e.key, e.value); - } - } - - /** - * Rehashes the contents of this map into a new IntKeyMap instance - * with a larger capacity. This method is called automatically when the - * number of keys in this map exceeds its capacity and load factor. - * - * @param newCapacity the new capacity, MUST be a power of two. - */ - void resize(int newCapacity) { - // assert (newCapacity & -newCapacity) == newCapacity; // power of 2 - IntEntry[] oldTable = table; - int oldCapacity = oldTable.length; - - // check if needed - if (size < threshold || oldCapacity > newCapacity) - return; - - IntEntry[] newTable = new IntEntry[newCapacity]; - transfer(newTable); - table = newTable; - threshold = (int)(newCapacity * loadFactor); - } - - /** - * Transfer all entries from current table to newTable. - */ - void transfer(IntEntry[] newTable) { - IntEntry[] src = table; - int newCapacity = newTable.length; - for (int j = 0; j < src.length; j++) { - IntEntry e = src[j]; - if (e != null) { - src[j] = null; - do { - IntEntry next = e.next; - int i = indexFor(e.hash, newCapacity); - e.next = newTable[i]; - newTable[i] = e; - e = next; - } while (e != null); - } - } - } - - /** - * Copies all of the mappings from the specified map to this map - * These mappings will replace any mappings that - * this map had for any of the keys currently in the specified map. - * - * @param t mappings to be stored in this map. - * @throws NullPointerException if the specified map is null. - */ - public void putAll(IntKeyMap t) { - // Expand enough to hold t's elements without resizing. - int n = t.size(); - if (n == 0) - return; - if (n >= threshold) { - n = (int)(n / loadFactor + 1); - if (n > MAXIMUM_CAPACITY) - n = MAXIMUM_CAPACITY; - int capacity = table.length; - while (capacity < n) - capacity <<= 1; - resize(capacity); - } - - for (Iterator i = t.entrySet().iterator(); i.hasNext(); ) { - IntEntry e = (IntEntry) i.next(); - put(e.key, e.value); - } - } - - /** - * Removes the mapping for this key from this map if present. - * - * @param key key whose mapping is to be removed from the map. - * @return previous value associated with specified key, or null - * if there was no mapping for key. A null return can - * also indicate that the map previously associated null - * with the specified key. - */ - public VALUE remove(int key) { - IntEntry e = removeEntryForKey(key); - return (e == null ? null : e.value); - } - - /** - * Removes and returns the entry associated with the specified key - * in the IntKeyMap. Returns null if the IntKeyMap contains no mapping - * for this key. - */ - IntEntry removeEntryForKey(int key) { - int hash = hash(key); - int i = indexFor(hash, table.length); - IntEntry prev = table[i]; - IntEntry e = prev; - - while (e != null) { - IntEntry next = e.next; - if (e.hash == hash && key == e.key) { - modCount++; - size--; - if (prev == e) - table[i] = next; - else - prev.next = next; - return e; - } - prev = e; - e = next; - } - - return e; - } - - /** - * Special version of remove for EntrySet. - */ - IntEntry removeMapping(Object o) { - if (!(o instanceof IntEntry)) - return null; - - IntEntry entry = (IntEntry)o; - int hash = hash(entry.key); - int i = indexFor(hash, table.length); - IntEntry prev = table[i]; - IntEntry e = prev; - - while (e != null) { - IntEntry next = e.next; - if (e.hash == hash && e.equals(entry)) { - modCount++; - size--; - if (prev == e) - table[i] = next; - else - prev.next = next; - return e; - } - prev = e; - e = next; - } - - return e; - } - - /** - * Removes all mappings from this map. - */ - @Override - public void clear() { - modCount++; - IntEntry tab[] = table; - for (int i = 0; i < tab.length; i++) - tab[i] = null; - size = 0; - } - - /** - * Returns true if this map maps one or more keys to the - * specified value. - * - * @param value value whose presence in this map is to be tested. - * @return true if this map maps one or more keys to the - * specified value. - */ - @Override - public boolean containsValue(Object value) - { - if (value == null) - return containsNullValue(); - - IntEntry tab[] = table; - for (int i = 0; i < tab.length ; i++) - for (IntEntry e = tab[i] ; e != null ; e = e.next) - if (value.equals(e.value)) - return true; - return false; - } - - @Override - public VALUE get(Object key) - { - return get(((Number)key).intValue()); - } - - @Override - public VALUE put(Integer key, VALUE value) - { - return put(key.intValue(), value); - } - - @Override - public VALUE remove(Object key) - { - return remove(((Number)key).intValue()); - } - - @Override - public void putAll(Map t) - { - throw new UnsupportedOperationException(); - } - - /** - * Special-case code for containsValue with null argument - **/ - private boolean containsNullValue() - { - IntEntry tab[] = table; - for (int i = 0; i < tab.length ; i++) - for (IntEntry e = tab[i] ; e != null ; e = e.next) - if (e.value == null) - return true; - return false; - } - - public static class IntEntry implements Entry { - final int key; - VALUE value; - final int hash; - IntEntry next; - - /** - * Create new entry. - */ - IntEntry(int h, int k, VALUE v, IntEntry n) { - value = v; - next = n; - key = k; - hash = h; - } - - public int getInt() { - return key; - } - - @Override - public Integer getKey() - { - return key; - } - - @Override - public VALUE getValue() { - return value; - } - - @Override - public VALUE setValue(VALUE newValue) { - VALUE oldValue = value; - value = newValue; - return oldValue; - } - - public boolean equals(Object o) { - if (!(o instanceof IntEntry)) - return false; - IntEntry e = (IntEntry)o; - if (key == e.key) { - VALUE v1 = getValue(); - VALUE v2 = e.getValue(); - if (v1 == v2 || (v1 != null && v1.equals(v2))) - return true; - } - return false; - } - - public int hashCode() { - return hash(key) ^ (value==null ? 0 : value.hashCode()); - } - - public String toString() { - return String.valueOf(key) + "=" + getValue(); - } - - } - - /** - * Add a new entry with the specified key, value and hash code to - * the specified bucket. It is the responsibility of this - * method to resize the table if appropriate. - * - * Subclass overrides this to alter the behavior of put method. - */ - void addEntry(int hash, int key, VALUE value, int bucketIndex) { - table[bucketIndex] = new IntEntry<>(hash, key, value, table[bucketIndex]); - if (size++ >= threshold) - resize(2 * table.length); - } - - /** - * Like addEntry except that this version is used when creating entries - * as part of Map construction or "pseudo-construction" (cloning, - * deserialization). This version needn't worry about resizing the table. - * - * Subclass overrides this to alter the behavior of IntKeyMap(Map), - * clone, and readObject. - */ - void createEntry(int hash, int key, VALUE value, int bucketIndex) { - table[bucketIndex] = new IntEntry<>(hash, key, value, table[bucketIndex]); - size++; - } - - private abstract class HashIterator implements Iterator { - IntEntry next; // next entry to return - int expectedModCount; // For fast-fail - int index; // current slot - IntEntry current; // current entry - - HashIterator() { - expectedModCount = modCount; - IntEntry[] t = table; - int i = t.length; - IntEntry n = null; - if (size != 0) { // advance to first entry - while (i > 0 && (n = t[--i]) == null) - ; - } - next = n; - index = i; - } - - @Override - public boolean hasNext() { - return next != null; - } - - IntEntry nextEntry() { - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); - IntEntry e = next; - if (e == null) - throw new NoSuchElementException(); - - IntEntry n = e.next; - IntEntry[] t = table; - int i = index; - while (n == null && i > 0) - n = t[--i]; - index = i; - next = n; - return current = e; - } - - @Override - public void remove() { - if (current == null) - throw new IllegalStateException(); - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); - int k = current.key; - current = null; - IntKeyMap.this.removeEntryForKey(k); - expectedModCount = modCount; - } - - } - - private class ValueIterator extends HashIterator { - @Override - public VALUE next() { - return nextEntry().value; - } - } - - private class KeyIterator extends HashIterator { - @Override - public Integer next() { - return nextEntry().key; - } - public int nextInt() { - return nextEntry().key; - } - } - - private class EntryIterator extends HashIterator> { - @Override - public IntEntry next() { - return nextEntry(); - } - } - - // Subclass overrides these to alter behavior of views' iterator() method - Iterator newKeyIterator() - { - return new KeyIterator(); - } - Iterator newValueIterator() - { - return new ValueIterator(); - } - Iterator> newEntryIterator() - { - return new EntryIterator(); - } - - - // Views - - private transient Set> entrySet = null; - transient volatile Set keySet = null; - transient volatile Collection values = null; - - /** - * Returns a set view of the keys contained in this map. The set is - * backed by the map, so changes to the map are reflected in the set, and - * vice-versa. The set supports element removal, which removes the - * corresponding mapping from this map, via the Iterator.remove, - * Set.remove, removeAll, retainAll, and - * clear operations. It does not support the add or - * addAll operations. - * - * @return a set view of the keys contained in this map. - */ - @Override - public Set keySet() { - Set ks = keySet; - return (ks != null ? ks : (keySet = new KeySet())); - } - - private class KeySet extends AbstractSet { - @Override - public Iterator iterator() { - return newKeyIterator(); - } - @Override - public int size() { - return size; - } - @Override - public boolean contains(Object o) { - if (o instanceof Number) { - return containsKey(((Number)o).intValue()); - } else { - return false; - } - } - @Override - public boolean remove(Object o) { - if (o instanceof Number) { - return IntKeyMap.this.removeEntryForKey(((Number)o).intValue()) != null; - } else { - return false; - } - } - @Override - public void clear() { - IntKeyMap.this.clear(); - } - } - - /** - * Returns a collection view of the values contained in this map. The - * collection is backed by the map, so changes to the map are reflected in - * the collection, and vice-versa. The collection supports element - * removal, which removes the corresponding mapping from this map, via the - * Iterator.remove, Collection.remove, - * removeAll, retainAll, and clear operations. - * It does not support the add or addAll operations. - * - * @return a collection view of the values contained in this map. - */ - @Override - public Collection values() { - Collection vs = values; - return (vs != null ? vs : (values = new Values())); - } - - private class Values extends AbstractCollection { - @Override - public Iterator iterator() { - return newValueIterator(); - } - @Override - public int size() { - return size; - } - @Override - public boolean contains(Object o) { - return containsValue(o); - } - @Override - public void clear() { - IntKeyMap.this.clear(); - } - } - - @Override - public Set entrySet() - { - Set> es = entrySet; - return (es != null ? es : (entrySet = new EntrySet())); - } - - private class EntrySet extends AbstractSet> { - @Override - public Iterator> iterator() { - return newEntryIterator(); - } - @Override - public boolean contains(Object o) { - if (!(o instanceof IntEntry)) - return false; - IntEntry e = (IntEntry)o; - IntEntry candidate = getEntry(e.key); - return candidate != null && candidate.equals(e); - } - @Override - public boolean remove(Object o) { - return removeMapping(o) != null; - } - @Override - public int size() { - return size; - } - @Override - public void clear() { - IntKeyMap.this.clear(); - } - } - - // These methods are used when serializing HashSets - int capacity() { return table.length; } - float loadFactor() { return loadFactor; } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/LongKeyMap.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/LongKeyMap.java deleted file mode 100644 index 40807b68422d..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/LongKeyMap.java +++ /dev/null @@ -1,806 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils; - -import java.util.*; - -/** - Map with long key. -*/ -public class LongKeyMap implements Map { - /** - * The default initial capacity - MUST be a power of two. - */ - static final int DEFAULT_INITIAL_CAPACITY = 16; - - /** - * The maximum capacity, used if a higher value is implicitly specified - * by either of the constructors with arguments. - * MUST be a power of two <= 1<<30. - */ - static final int MAXIMUM_CAPACITY = 1 << 30; - - /** - * The load fast used when none specified in constructor. - **/ - static final float DEFAULT_LOAD_FACTOR = 0.75f; - - /** - * The table, resized as necessary. Length MUST Always be a power of two. - */ - transient LongEntry[] table; - - /** - * The number of key-value mappings contained in this identity hash map. - */ - transient int size; - - /** - * The next size value at which to resize (capacity * load factor). - * @serial - */ - int threshold; - - /** - * The load factor for the hash table. - * - * @serial - */ - final float loadFactor; - - /** - * The number of times this LongKeyMap has been structurally modified - */ - transient volatile int modCount; - - /** - * Constructs an empty LongKeyMap with the specified initial - * capacity and load factor. - * - * @param initialCapacity The initial capacity. - * @param loadFactor The load factor. - * @throws IllegalArgumentException if the initial capacity is negative - * or the load factor is nonpositive. - */ - public LongKeyMap(int initialCapacity, float loadFactor) { - if (initialCapacity < 0) - throw new IllegalArgumentException("Illegal initial capacity: " + - initialCapacity); - if (initialCapacity > MAXIMUM_CAPACITY) - initialCapacity = MAXIMUM_CAPACITY; - if (loadFactor <= 0 || Float.isNaN(loadFactor)) - throw new IllegalArgumentException("Illegal load factor: " + - loadFactor); - - // Find a power of 2 >= initialCapacity - int capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; - - this.loadFactor = loadFactor; - threshold = (int)(capacity * loadFactor); - table = new LongEntry[capacity]; - } - - /** - * Constructs an empty LongKeyMap with the specified initial - * capacity and the default load factor (0.75). - * - * @param initialCapacity the initial capacity. - * @throws IllegalArgumentException if the initial capacity is negative. - */ - public LongKeyMap(int initialCapacity) { - this(initialCapacity, DEFAULT_LOAD_FACTOR); - } - - /** - * Constructs an empty LongKeyMap with the default initial capacity - * (16) and the default load factor (0.75). - */ - public LongKeyMap() { - this.loadFactor = DEFAULT_LOAD_FACTOR; - threshold = DEFAULT_INITIAL_CAPACITY; - table = new LongEntry[DEFAULT_INITIAL_CAPACITY]; - } - - static int hash(long x) { - int h = (int)(x ^ (x >>> 32)); - h += ~(h << 9); - h ^= (h >>> 14); - h += (h << 4); - h ^= (h >>> 10); - return h; - } - - /** - * Returns index for hash code h. - */ - static int indexFor(int h, int length) { - return h & (length-1); - } - - /** - * Returns the number of key-value mappings in this map. - * - * @return the number of key-value mappings in this map. - */ - @Override - public int size() { - return size; - } - - /** - * Returns true if this map contains no key-value mappings. - * - * @return true if this map contains no key-value mappings. - */ - @Override - public boolean isEmpty() - { - return size == 0; - } - - @Override - public boolean containsKey(Object key) - { - return containsKey(((Number)key).longValue()); - } - - /** - * Returns the value to which the specified key is mapped in this identity - * hash map, or null if the map contains no mapping for this key. - * A return value of null does not necessarily indicate - * that the map contains no mapping for the key; it is also possible that - * the map explicitly maps the key to null. The - * containsKey method may be used to distinguish these two cases. - * - * @param key the key whose associated value is to be returned. - * @return the value to which this map maps the specified key, or - * null if the map contains no mapping for this key. - * @see #put(long, Object) - */ - public VALUE get(long key) { - int hash = hash(key); - int i = indexFor(hash, table.length); - LongEntry e = table[i]; - while (true) { - if (e == null) - return null; - if (e.hash == hash && key == e.key) - return e.value; - e = e.next; - } - } - - /** - * Returns true if this map contains a mapping for the - * specified key. - */ - public boolean containsKey(long key) - { - int hash = hash(key); - int i = indexFor(hash, table.length); - LongEntry e = table[i]; - while (e != null) { - if (e.hash == hash && key == e.key) - return true; - e = e.next; - } - return false; - } - - /** - * Returns the entry associated with the specified key in the - * LongKeyMap. Returns null if the LongKeyMap contains no mapping - * for this key. - */ - LongEntry getEntry(long key) { - int hash = hash(key); - int i = indexFor(hash, table.length); - LongEntry e = table[i]; - while (e != null && !(e.hash == hash && key == e.key)) - e = e.next; - return e; - } - - /** - * Associates the specified value with the specified key in this map. - * If the map previously contained a mapping for this key, the old - * value is replaced. - * - * @param key key with which the specified value is to be associated. - * @param value value to be associated with the specified key. - * @return previous value associated with specified key, or null - * if there was no mapping for key. A null return can - * also indicate that the LongKeyMap previously associated - * null with the specified key. - */ - public VALUE put(long key, VALUE value) { - int hash = hash(key); - int i = indexFor(hash, table.length); - - for (LongEntry e = table[i]; e != null; e = e.next) { - if (e.hash == hash && key == e.key) { - VALUE oldValue = e.value; - e.value = value; - return oldValue; - } - } - - modCount++; - addEntry(hash, key, value, i); - return null; - } - - /** - * This method is used instead of put by constructors and - * pseudoconstructors (clone, readObject). It does not resize the table, - * check for comodification, etc. It calls createEntry rather than - * addEntry. - */ - private void putForCreate(long key, VALUE value) { - int hash = hash(key); - int i = indexFor(hash, table.length); - - /** - * Look for preexisting entry for key. This will never happen for - * clone or deserialize. It will only happen for construction if the - * input Map is a sorted map whose ordering is inconsistent w/ equals. - */ - for (LongEntry e = table[i]; e != null; e = e.next) { - if (e.hash == hash && key == e.key) { - e.value = value; - return; - } - } - - createEntry(hash, key, value, i); - } - - void putAllForCreate(LongKeyMap m) { - for (Iterator> i = m.entrySet().iterator(); i.hasNext(); ) { - LongEntry e = i.next(); - putForCreate(e.key, e.value); - } - } - - /** - * Rehashes the contents of this map into a new LongKeyMap instance - * with a larger capacity. This method is called automatically when the - * number of keys in this map exceeds its capacity and load factor. - * - * @param newCapacity the new capacity, MUST be a power of two. - */ - void resize(int newCapacity) { - // assert (newCapacity & -newCapacity) == newCapacity; // power of 2 - LongEntry[] oldTable = table; - int oldCapacity = oldTable.length; - - // check if needed - if (size < threshold || oldCapacity > newCapacity) - return; - - LongEntry[] newTable = new LongEntry[newCapacity]; - transfer(newTable); - table = newTable; - threshold = (int)(newCapacity * loadFactor); - } - - /** - * Transfer all entries from current table to newTable. - */ - void transfer(LongEntry[] newTable) { - LongEntry[] src = table; - int newCapacity = newTable.length; - for (int j = 0; j < src.length; j++) { - LongEntry e = src[j]; - if (e != null) { - src[j] = null; - do { - LongEntry next = e.next; - int i = indexFor(e.hash, newCapacity); - e.next = newTable[i]; - newTable[i] = e; - e = next; - } while (e != null); - } - } - } - - /** - * Copies all of the mappings from the specified map to this map - * These mappings will replace any mappings that - * this map had for any of the keys currently in the specified map. - * - * @param t mappings to be stored in this map. - * @throws NullPointerException if the specified map is null. - */ - public void putAll(LongKeyMap t) { - // Expand enough to hold t's elements without resizing. - int n = t.size(); - if (n == 0) - return; - if (n >= threshold) { - n = (int)(n / loadFactor + 1); - if (n > MAXIMUM_CAPACITY) - n = MAXIMUM_CAPACITY; - int capacity = table.length; - while (capacity < n) - capacity <<= 1; - resize(capacity); - } - - for (Iterator> i = t.entrySet().iterator(); i.hasNext(); ) { - LongEntry e = i.next(); - put(e.key, e.value); - } - } - - /** - * Removes the mapping for this key from this map if present. - * - * @param key key whose mapping is to be removed from the map. - * @return previous value associated with specified key, or null - * if there was no mapping for key. A null return can - * also indicate that the map previously associated null - * with the specified key. - */ - public VALUE remove(long key) { - LongEntry e = removeEntryForKey(key); - return (e == null ? null : e.value); - } - - /** - * Removes and returns the entry associated with the specified key - * in the LongKeyMap. Returns null if the LongKeyMap contains no mapping - * for this key. - */ - LongEntry removeEntryForKey(long key) { - int hash = hash(key); - int i = indexFor(hash, table.length); - LongEntry prev = table[i]; - LongEntry e = prev; - - while (e != null) { - LongEntry next = e.next; - if (e.hash == hash && key == e.key) { - modCount++; - size--; - if (prev == e) - table[i] = next; - else - prev.next = next; - return e; - } - prev = e; - e = next; - } - - return e; - } - - /** - * Special version of remove for EntrySet. - */ - LongEntry removeMapping(Object o) { - if (!(o instanceof LongEntry)) - return null; - - LongEntry entry = (LongEntry)o; - int hash = hash(entry.key); - int i = indexFor(hash, table.length); - LongEntry prev = table[i]; - LongEntry e = prev; - - while (e != null) { - LongEntry next = e.next; - if (e.hash == hash && e.equals(entry)) { - modCount++; - size--; - if (prev == e) - table[i] = next; - else - prev.next = next; - return e; - } - prev = e; - e = next; - } - - return e; - } - - /** - * Removes all mappings from this map. - */ - @Override - public void clear() { - modCount++; - LongEntry tab[] = table; - for (int i = 0; i < tab.length; i++) - tab[i] = null; - size = 0; - } - - /** - * Returns true if this map maps one or more keys to the - * specified value. - * - * @param value value whose presence in this map is to be tested. - * @return true if this map maps one or more keys to the - * specified value. - */ - @Override - public boolean containsValue(Object value) - { - if (value == null) - return containsNullValue(); - - LongEntry tab[] = table; - for (int i = 0; i < tab.length ; i++) - for (LongEntry e = tab[i] ; e != null ; e = e.next) - if (value.equals(e.value)) - return true; - return false; - } - - @Override - public VALUE get(Object key) - { - return get(((Number)key).longValue()); - } - - @Override - public VALUE put(Long key, VALUE value) - { - return put(key.longValue(), value); - } - - @Override - public VALUE remove(Object key) - { - return remove(((Number)key).longValue()); - } - - @Override - public void putAll(Map t) - { - throw new UnsupportedOperationException(); - } - - /** - * Special-case code for containsValue with null argument - **/ - private boolean containsNullValue() - { - LongEntry tab[] = table; - for (int i = 0; i < tab.length ; i++) - for (LongEntry e = tab[i] ; e != null ; e = e.next) - if (e.value == null) - return true; - return false; - } - - public static class LongEntry implements Entry { - final long key; - VALUE value; - final int hash; - LongEntry next; - - /** - * Create new entry. - */ - LongEntry(int h, long k, VALUE v, LongEntry n) { - value = v; - next = n; - key = k; - hash = h; - } - - public long getLong() { - return key; - } - - @Override - public Long getKey() - { - return key; - } - - @Override - public VALUE getValue() { - return value; - } - - @Override - public VALUE setValue(VALUE newValue) { - VALUE oldValue = value; - value = newValue; - return oldValue; - } - - public boolean equals(Object o) { - if (!(o instanceof LongEntry)) - return false; - LongEntry e = (LongEntry)o; - if (key == e.key) { - VALUE v1 = getValue(); - VALUE v2 = e.getValue(); - if (v1 == v2 || (v1 != null && v1.equals(v2))) - return true; - } - return false; - } - - public int hashCode() { - return hash(key) ^ (value==null ? 0 : value.hashCode()); - } - - public String toString() { - return String.valueOf(key) + "=" + getValue(); - } - - } - - /** - * Add a new entry with the specified key, value and hash code to - * the specified bucket. It is the responsibility of this - * method to resize the table if appropriate. - * - * Subclass overrides this to alter the behavior of put method. - */ - void addEntry(int hash, long key, VALUE value, int bucketIndex) { - table[bucketIndex] = new LongEntry<>(hash, key, value, table[bucketIndex]); - if (size++ >= threshold) - resize(2 * table.length); - } - - /** - * Like addEntry except that this version is used when creating entries - * as part of Map construction or "pseudo-construction" (cloning, - * deserialization). This version needn't worry about resizing the table. - * - * Subclass overrides this to alter the behavior of LongKeyMap(Map), - * clone, and readObject. - */ - void createEntry(int hash, long key, VALUE value, int bucketIndex) { - table[bucketIndex] = new LongEntry<>(hash, key, value, table[bucketIndex]); - size++; - } - - private abstract class HashIterator implements Iterator { - LongEntry next; // next entry to return - int expectedModCount; // For fast-fail - int index; // current slot - LongEntry current; // current entry - - HashIterator() { - expectedModCount = modCount; - LongEntry[] t = table; - int i = t.length; - LongEntry n = null; - if (size != 0) { // advance to first entry - while (i > 0 && (n = t[--i]) == null) - ; - } - next = n; - index = i; - } - - @Override - public boolean hasNext() { - return next != null; - } - - LongEntry nextEntry() { - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); - LongEntry e = next; - if (e == null) - throw new NoSuchElementException(); - - LongEntry n = e.next; - LongEntry[] t = table; - int i = index; - while (n == null && i > 0) - n = t[--i]; - index = i; - next = n; - return current = e; - } - - @Override - public void remove() { - if (current == null) - throw new IllegalStateException(); - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); - long k = current.key; - current = null; - LongKeyMap.this.removeEntryForKey(k); - expectedModCount = modCount; - } - - } - - private class ValueIterator extends HashIterator { - @Override - public VALUE next() { - return nextEntry().value; - } - } - - private class KeyIterator extends HashIterator { - @Override - public Long next() { - return nextEntry().key; - } - public long nextLong() { - return nextEntry().key; - } - } - - private class EntryIterator extends HashIterator> { - @Override - public LongEntry next() { - return nextEntry(); - } - } - - // Subclass overrides these to alter behavior of views' iterator() method - Iterator newKeyIterator() - { - return new KeyIterator(); - } - Iterator newValueIterator() - { - return new ValueIterator(); - } - Iterator> newEntryIterator() - { - return new EntryIterator(); - } - - - // Views - - private transient Set> entrySet = null; - transient volatile Set keySet = null; - transient volatile Collection values = null; - - /** - * Returns a set view of the keys contained in this map. The set is - * backed by the map, so changes to the map are reflected in the set, and - * vice-versa. The set supports element removal, which removes the - * corresponding mapping from this map, via the Iterator.remove, - * Set.remove, removeAll, retainAll, and - * clear operations. It does not support the add or - * addAll operations. - * - * @return a set view of the keys contained in this map. - */ - @Override - public Set keySet() { - Set ks = keySet; - return (ks != null ? ks : (keySet = new KeySet())); - } - - private class KeySet extends AbstractSet { - @Override - public Iterator iterator() { - return newKeyIterator(); - } - @Override - public int size() { - return size; - } - @Override - public boolean contains(Object o) { - if (o instanceof Number) { - return containsKey(((Number)o).longValue()); - } else { - return false; - } - } - @Override - public boolean remove(Object o) { - if (o instanceof Number) { - return LongKeyMap.this.removeEntryForKey(((Number)o).longValue()) != null; - } else { - return false; - } - } - @Override - public void clear() { - LongKeyMap.this.clear(); - } - } - - /** - * Returns a collection view of the values contained in this map. The - * collection is backed by the map, so changes to the map are reflected in - * the collection, and vice-versa. The collection supports element - * removal, which removes the corresponding mapping from this map, via the - * Iterator.remove, Collection.remove, - * removeAll, retainAll, and clear operations. - * It does not support the add or addAll operations. - * - * @return a collection view of the values contained in this map. - */ - @Override - public Collection values() { - Collection vs = values; - return (vs != null ? vs : (values = new Values())); - } - - private class Values extends AbstractCollection { - @Override - public Iterator iterator() { - return newValueIterator(); - } - @Override - public int size() { - return size; - } - @Override - public boolean contains(Object o) { - return containsValue(o); - } - @Override - public void clear() { - LongKeyMap.this.clear(); - } - } - - @Override - public Set entrySet() - { - Set> es = entrySet; - return (es != null ? es : (entrySet = new EntrySet())); - } - - private class EntrySet extends AbstractSet> { - @Override - public Iterator> iterator() { - return newEntryIterator(); - } - @Override - public boolean contains(Object o) { - if (!(o instanceof LongEntry)) - return false; - LongEntry e = (LongEntry)o; - LongEntry candidate = getEntry(e.key); - return candidate != null && candidate.equals(e); - } - @Override - public boolean remove(Object o) { - return removeMapping(o) != null; - } - @Override - public int size() { - return size; - } - @Override - public void clear() { - LongKeyMap.this.clear(); - } - } - - // These methods are used when serializing HashSets - int capacity() { return table.length; } - float loadFactor() { return loadFactor; } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/MimeType.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/MimeType.java deleted file mode 100644 index 8732a66eafd0..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/MimeType.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils; - -import java.util.Locale; - -/** - * MIME type parser - */ -public class MimeType { - - private String primaryType; - private String subType; - - public MimeType() { - primaryType = "application"; - subType = "*"; - } - - public MimeType(String rawdata) throws IllegalArgumentException { - parse(rawdata); - } - - public MimeType(String primary, String sub) { - primaryType = primary.toLowerCase(Locale.ENGLISH); - subType = sub.toLowerCase(Locale.ENGLISH); - } - - private void parse(String rawdata) throws IllegalArgumentException { - int slashIndex = rawdata.indexOf('/'); - int semIndex = rawdata.indexOf(';'); - if ((slashIndex < 0) && (semIndex < 0)) { - primaryType = rawdata; - subType = "*"; - } else if ((slashIndex < 0) && (semIndex >= 0)) { - primaryType = rawdata.substring(0, semIndex); - subType = "*"; - } else if ((slashIndex >= 0) && (semIndex < 0)) { - primaryType = rawdata.substring(0, slashIndex).trim().toLowerCase(Locale.ENGLISH); - subType = rawdata.substring(slashIndex + 1).trim().toLowerCase(Locale.ENGLISH); - } else if (slashIndex < semIndex) { - primaryType = rawdata.substring(0, slashIndex).trim().toLowerCase(Locale.ENGLISH); - subType = rawdata.substring(slashIndex + 1, semIndex).trim().toLowerCase(Locale.ENGLISH); - } else { - // we have a ';' lexically before a '/' which means we - // have a primary type and a parameter list but no sub type - throw new IllegalArgumentException("Unable to find a sub type."); - } - } - - public String getPrimaryType() { - return primaryType; - } - - public String getSubType() { - return subType; - } - - public String toString() { - return getBaseType(); - } - - public String getBaseType() { - return primaryType + "/" + subType; - } - - public boolean match(MimeType type) { - return primaryType.equals(type.getPrimaryType()) && - (subType.equals("*") || type.getSubType().equals("*") || (subType.equals(type.getSubType()))); - } - - public boolean match(String rawdata) throws IllegalArgumentException { - return match(new MimeType(rawdata)); - } - -} \ No newline at end of file diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/Pair.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/Pair.java deleted file mode 100644 index 44435f068784..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/Pair.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils; - -import java.util.Objects; - -/** - * Pair - */ -public class Pair { - private T1 first; - private T2 second; - - public Pair(T1 first, T2 second) - { - this.first = first; - this.second = second; - } - - public T1 getFirst() - { - return first; - } - - public void setFirst(T1 first) { - this.first = first; - } - - public T2 getSecond() - { - return second; - } - - public void setSecond(T2 second) { - this.second = second; - } - - @Override - public String toString() { - return first + "=" + second; - } - - /** - * Checks the two objects for equality by delegating to their respective - * {@link Object#equals(Object)} methods. - * - * @param o the {@link Pair} to which this one is to be checked for equality - * @return true if the underlying objects of the Pair are both considered - * equal - */ - @Override - public boolean equals(Object o) { - if (!(o instanceof Pair)) { - return false; - } - Pair p = (Pair) o; - return Objects.deepEquals(p.first, first) && Objects.deepEquals(p.second, second); - } - - /** - * Compute a hash code using the hash codes of the underlying objects - * @return a hashcode of the Pair - */ - @Override - public int hashCode() { - return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode()); - } - - public static Pair of(T1 t1, T2 t2) { - return new Pair<>(t1, t2); - } - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/ReaderWriterLock.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/ReaderWriterLock.java deleted file mode 100644 index 5209d637cab1..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/ReaderWriterLock.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils; - -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Supplier; - -public class ReaderWriterLock { - - private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); - private final Supplier mutatorSupplier; - - public ReaderWriterLock(Supplier mutatorSupplier) { - this.mutatorSupplier = mutatorSupplier; - } - - /** - * Represents an operation that accepts a single input argument and returns no result possibly throwing an exception. - */ - public interface ExceptableConsumer { - /** - * Performs the operation on the given argument. - */ - void accept(T t) throws EXCEPTION; - } - - /** - * Represents an operation that accepts a single input argument and produces a result possibly throwing an exception. - */ - public interface ExceptableFunction { - /** - * Performs the operation on the given argument and returns the result. - */ - RESULT apply(T t) throws EXCEPTION; - } - - /** - * Acquires the reader or writer lock, executes given operation and releases the lock returning the operation result. - */ - public RESULT compute( - boolean writing, - ExceptableFunction action - ) throws EXCEPTION { - Lock lock = writing ? rwLock.writeLock() : rwLock.readLock(); - lock.lock(); - try { - return action.apply(mutatorSupplier.get()); - } finally { - lock.unlock(); - } - } - - /** - * Acquires the reader lock, executes given operation and releases the lock returning the operation result. - */ - public RESULT computeReading( - ExceptableFunction action - ) throws EXCEPTION { - return this.compute(false, action); - } - - /** - * Acquires the writer lock, executes given operation and releases the lock returning the operation result. - */ - public RESULT computeWriting( - ExceptableFunction action - ) throws EXCEPTION { - return this.compute(true, action); - } - - /** - * Acquires the reader or writer lock, executes given operation and releases the lock. - */ - public void exec( - boolean writing, - ExceptableConsumer action - ) throws EXCEPTION { - this.compute(writing, m -> { - action.accept(m); - return null; - }); - } - - /** - * Acquires the reader lock, executes given operation and releases the lock. - */ - public void execReading(ExceptableConsumer action) throws EXCEPTION { - this.exec(false, action); - } - - /** - * Acquires the writer lock, executes given operation and releases the lock. - */ - public void execWriting(ExceptableConsumer action) throws EXCEPTION { - this.exec(true, action); - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/SecurityUtils.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/SecurityUtils.java deleted file mode 100644 index c33a5ab9b83d..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/SecurityUtils.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Random; - -/** - * Come security-related functions. - */ -public class SecurityUtils { - - public static String ECRYPTION_ALGORYTHM = "MD5"; - - private static java.util.Random random; - private static java.util.Random secureRand; - - static { - secureRand = new java.util.Random(System.currentTimeMillis()); - long secureInitializer = secureRand.nextLong(); - random = new java.util.Random(secureInitializer); - } - - /** - * Generate the random GUID - */ - public static String generateGUID(boolean secure) { - String localHostAddr; - { - java.net.InetAddress id; - try { - id = java.net.InetAddress.getLocalHost(); - localHostAddr = id.toString(); - } catch (java.net.UnknownHostException e) { - localHostAddr = "localhost"; - } - } - - long time = System.currentTimeMillis(); - long rand; - - if (secure) { - rand = secureRand.nextLong(); - } else { - rand = SecurityUtils.random.nextLong(); - } - - // This StringBuilder can be a long as you need; the MD5 - // hash will always return 128 bits. You can change - // the seed to include anything you want here. - // You could even stream a file through the MD5 making - // the odds of guessing it at least as great as that - // of guessing the contents of the file! - StringBuilder sb = new StringBuilder(32); - sb.append(localHostAddr) - .append(":") - .append(Long.toString(time)) - .append(":") - .append(Long.toString(rand)); - - - byte[] array; - try { - MessageDigest md5 = MessageDigest.getInstance(ECRYPTION_ALGORYTHM); - md5.update(sb.toString().getBytes(StandardCharsets.UTF_8)); - array = md5.digest(); - } catch (NoSuchAlgorithmException e) { - // Too bad. Lets get simple random numbers - array = new byte[16]; - random.nextBytes(array); - } - sb.setLength(0); - for (int j = 0; j < array.length; ++j) { - int b = array[j] & 0xFF; - if (b < 0x10) { - sb.append('0'); - } - sb.append(Integer.toHexString(b)); - } - - String raw = sb.toString().toUpperCase(); - sb.setLength(0); - sb.append(raw.substring(0, 8)); - sb.append("-"); - sb.append(raw.substring(8, 12)); - sb.append("-"); - sb.append(raw.substring(12, 16)); - sb.append("-"); - sb.append(raw.substring(16, 20)); - sb.append("-"); - sb.append(raw.substring(20)); - - return sb.toString(); - } - - public static String generateUniqueId() { - long curTime = System.currentTimeMillis(); - int random = secureRand.nextInt(); - if (random < 0) { - random = -random; - } - - return - Long.toString(curTime, Character.MAX_RADIX) + - Integer.toString(random, Character.MAX_RADIX); - } - - public static String makeDigest( - String userAlias, - String userPassword) { - try { - if (userPassword == null) { - userPassword = ""; - } - MessageDigest md5 = - MessageDigest.getInstance(ECRYPTION_ALGORYTHM); - md5.update(userAlias.getBytes(StandardCharsets.UTF_8)); - - return CommonUtils.toHexString(md5.digest(userPassword.getBytes(StandardCharsets.UTF_8))); - } catch (NoSuchAlgorithmException toCatch) { - return "*"; - } - } - - public static String makeDigest( - String userPassword) { - try { - MessageDigest md5 = - MessageDigest.getInstance(ECRYPTION_ALGORYTHM); - - return CommonUtils.toHexString(md5.digest(userPassword.getBytes(StandardCharsets.UTF_8))); - } catch (NoSuchAlgorithmException toCatch) { - return "*"; - } - } - - /** - * Generate a random password of the given length. - */ - public static String generatePassword(int length) { - SecureRandom random = new SecureRandom(); - StringBuilder pass = new StringBuilder(length); - for (int i = 0; i < length; i++) { - pass.append( - PASSWORD_ALPHABET[random.nextInt(PASSWORD_ALPHABET.length)] - ); - } - return (pass.toString()); - } - - public static long generateRandomLong() { - SecureRandom random = new SecureRandom(); - return random.nextLong(); - } - - public static byte[] generateRandomBytes(int length) { - SecureRandom random = new SecureRandom(); - byte[] bytes = new byte[length]; - random.nextBytes(bytes); - return bytes; - } - - /** - * Generate a random password of the default length (8). - */ - public static String generatePassword() { - return generatePassword(DEFAULT_PASSWORD_LENGTH); - } - - public static Random getRandom() { - return random; - } - - /** - * Default length for passwords - */ - public static final int DEFAULT_PASSWORD_LENGTH = 8; - - /** - * Alphabet consisting of upper and lowercase letters A-Z and - * the digits 0-9. - */ - public static final char[] PASSWORD_ALPHABET = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', - }; - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/StandardConstants.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/StandardConstants.java deleted file mode 100644 index 58a017d674db..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/StandardConstants.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils; - -/** - * Standard Java constants - */ -public abstract class StandardConstants { - - public static final String ENV_LINE_SEPARATOR = "line.separator"; - public static final String ENV_PATH_SEPARATOR = "path.separator"; - - public static final String ENV_TMP_DIR = "java.io.tmpdir"; - public static final String ENV_FILE_ENCODING = "file.encoding"; - public static final String ENV_CONSOLE_ENCODING = "console.encoding"; - - public static final String ENV_USER_HOME = "user.home"; - public static final String ENV_USER_NAME = "user.name"; - public static final String ENV_USER_TIMEZONE = "user.timezone"; - public static final String ENV_OS_NAME = "os.name"; - public static final String ENV_OS_VERSION = "os.version"; - public static final String ENV_OS_ARCH = "os.arch"; - - public static final String ENV_JAVA_VERSION = "java.version"; - public static final String ENV_JAVA_VENDOR = "java.vendor"; - public static final String ENV_JAVA_ARCH = "sun.arch.data.model"; - public static final String ENV_JAVA_CLASSPATH = "java.class.path"; - - public static final int MIN_PORT_VALUE = 0; - public static final int MAX_PORT_VALUE = 65535; -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVParser.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVParser.java deleted file mode 100644 index 55d8f2ea2f4d..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVParser.java +++ /dev/null @@ -1,562 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package contains a slightly modified version of opencsv library - * without unwanted functionality and dependencies, licensed under Apache 2.0. - * - * See https://search.maven.org/artifact/com.opencsv/opencsv/3.4/bundle - * See http://opencsv.sf.net/ - */ -package org.jkiss.utils.csv; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * A very simple CSV parser released under a commercial-friendly license. - * This just implements splitting a single line into fields. - * - * @author Glen Smith - * @author Rainer Pruy - */ - -public class CSVParser { - - /** - * The default separator to use if none is supplied to the constructor. - */ - public static final char DEFAULT_SEPARATOR = ','; - /** - * The average size of a line read by openCSV (used for setting the size of StringBuilders). - */ - public static final int INITIAL_READ_SIZE = 128; - /** - * The default quote character to use if none is supplied to the - * constructor. - */ - public static final char DEFAULT_QUOTE_CHARACTER = '"'; - /** - * The default escape character to use if none is supplied to the - * constructor. - */ - public static final char DEFAULT_ESCAPE_CHARACTER = '\\'; - /** - * The default strict quote behavior to use if none is supplied to the - * constructor. - */ - public static final boolean DEFAULT_STRICT_QUOTES = false; - /** - * The default leading whitespace behavior to use if none is supplied to the - * constructor. - */ - public static final boolean DEFAULT_IGNORE_LEADING_WHITESPACE = true; - /** - * If the quote character is set to null then there is no quote character. - */ - public static final boolean DEFAULT_IGNORE_QUOTATIONS = false; - /** - * This is the "null" character - if a value is set to this then it is ignored. - */ - public static final char NULL_CHARACTER = '\0'; - /** - * Denotes what field contents will cause the parser to return null: EMPTY_SEPARATORS, EMPTY_QUOTES, BOTH, NEITHER (default) - */ - public static final CSVReaderNullFieldIndicator DEFAULT_NULL_FIELD_INDICATOR = CSVReaderNullFieldIndicator.NEITHER; - - /** - * This is the character that the CSVParser will treat as the separator. - */ - private final char separator; - /** - * This is the character that the CSVParser will treat as the quotation character. - */ - private final char quotechar; - /** - * This is the character that the CSVParser will treat as the escape character. - */ - private final char escape; - /** - * Determines if the field is between quotes (true) or between separators (false). - */ - private final boolean strictQuotes; - /** - * Ignore any leading white space at the start of the field. - */ - private final boolean ignoreLeadingWhiteSpace; - /** - * Skip over quotation characters when parsing. - */ - private final boolean ignoreQuotations; - private final CSVReaderNullFieldIndicator nullFieldIndicator; - private String pending; - private boolean inField = false; - - /** - * Constructs CSVParser using a comma for the separator. - */ - public CSVParser() { - this(DEFAULT_SEPARATOR, DEFAULT_QUOTE_CHARACTER, DEFAULT_ESCAPE_CHARACTER); - } - - /** - * Constructs CSVParser with supplied separator. - * - * @param separator the delimiter to use for separating entries. - */ - public CSVParser(char separator) { - this(separator, DEFAULT_QUOTE_CHARACTER, DEFAULT_ESCAPE_CHARACTER); - } - - - /** - * Constructs CSVParser with supplied separator and quote char. - * - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - */ - public CSVParser(char separator, char quotechar) { - this(separator, quotechar, DEFAULT_ESCAPE_CHARACTER); - } - - /** - * Constructs CSVReader with supplied separator and quote char. - * - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escape the character to use for escaping a separator or quote - */ - public CSVParser(char separator, char quotechar, char escape) { - this(separator, quotechar, escape, DEFAULT_STRICT_QUOTES); - } - - /** - * Constructs CSVParser with supplied separator and quote char. - * Allows setting the "strict quotes" flag - * - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escape the character to use for escaping a separator or quote - * @param strictQuotes if true, characters outside the quotes are ignored - */ - public CSVParser(char separator, char quotechar, char escape, boolean strictQuotes) { - this(separator, quotechar, escape, strictQuotes, DEFAULT_IGNORE_LEADING_WHITESPACE); - } - - /** - * Constructs CSVParser with supplied separator and quote char. - * Allows setting the "strict quotes" and "ignore leading whitespace" flags - * - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escape the character to use for escaping a separator or quote - * @param strictQuotes if true, characters outside the quotes are ignored - * @param ignoreLeadingWhiteSpace if true, white space in front of a quote in a field is ignored - */ - public CSVParser(char separator, char quotechar, char escape, boolean strictQuotes, boolean ignoreLeadingWhiteSpace) { - this(separator, quotechar, escape, strictQuotes, ignoreLeadingWhiteSpace, DEFAULT_IGNORE_QUOTATIONS); - } - - /** - * Constructs CSVParser with supplied separator and quote char. - * Allows setting the "strict quotes" and "ignore leading whitespace" flags - * - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escape the character to use for escaping a separator or quote - * @param strictQuotes if true, characters outside the quotes are ignored - * @param ignoreLeadingWhiteSpace if true, white space in front of a quote in a field is ignored - * @param ignoreQuotations if true, treat quotations like any other character. - */ - public CSVParser(char separator, char quotechar, char escape, boolean strictQuotes, boolean ignoreLeadingWhiteSpace, - boolean ignoreQuotations) { - this(separator, quotechar, escape, strictQuotes, ignoreLeadingWhiteSpace, ignoreQuotations, DEFAULT_NULL_FIELD_INDICATOR); - } - - /** - * Constructs CSVParser with supplied separator and quote char. - * Allows setting the "strict quotes" and "ignore leading whitespace" flags - * - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escape the character to use for escaping a separator or quote - * @param strictQuotes if true, characters outside the quotes are ignored - * @param ignoreLeadingWhiteSpace if true, white space in front of a quote in a field is ignored - * @param ignoreQuotations if true, treat quotations like any other character. - * @param nullFieldIndicator which field content will be returned as null: EMPTY_SEPARATORS, EMPTY_QUOTES, - * BOTH, NEITHER (default) - */ - CSVParser(char separator, char quotechar, char escape, boolean strictQuotes, boolean ignoreLeadingWhiteSpace, - boolean ignoreQuotations, CSVReaderNullFieldIndicator nullFieldIndicator) { - if (anyCharactersAreTheSame(separator, quotechar, escape)) { - throw new UnsupportedOperationException("The separator, quote, and escape characters must be different!"); - } - if (separator == NULL_CHARACTER) { - throw new UnsupportedOperationException("The separator character must be defined!"); - } - this.separator = separator; - this.quotechar = quotechar; - this.escape = escape; - this.strictQuotes = strictQuotes; - this.ignoreLeadingWhiteSpace = ignoreLeadingWhiteSpace; - this.ignoreQuotations = ignoreQuotations; - this.nullFieldIndicator = nullFieldIndicator; - } - - - /** - * @return The default separator for this parser. - */ - public char getSeparator() { - return separator; - } - - /** - * @return The default quotation character for this parser. - */ - public char getQuotechar() { - return quotechar; - } - - /** - * @return The default escape character for this parser. - */ - public char getEscape() { - return escape; - } - - /** - * @return The default strictQuotes setting for this parser. - */ - public boolean isStrictQuotes() { - return strictQuotes; - } - - /** - * @return The default ignoreLeadingWhiteSpace setting for this parser. - */ - public boolean isIgnoreLeadingWhiteSpace() { - return ignoreLeadingWhiteSpace; - } - - /** - * @return the default ignoreQuotation setting for this parser. - */ - public boolean isIgnoreQuotations() { - return ignoreQuotations; - } - - /** - * checks to see if any two of the three characters are the same. This is because in openCSV the - * separator, quote, and escape characters must the different. - * - * @param separator the defined separator character - * @param quotechar the defined quotation cahracter - * @param escape the defined escape character - * @return true if any two of the three are the same. - */ - private boolean anyCharactersAreTheSame(char separator, char quotechar, char escape) { - return isSameCharacter(separator, quotechar) || isSameCharacter(separator, escape) || isSameCharacter(quotechar, escape); - } - - /** - * checks that the two characters are the same and are not the defined NULL_CHARACTER. - * - * @param c1 first character - * @param c2 second character - * @return true if both characters are the same and are not the defined NULL_CHARACTER - */ - private boolean isSameCharacter(char c1, char c2) { - return c1 != NULL_CHARACTER && c1 == c2; - } - - /** - * @return true if something was left over from last call(s) - */ - public boolean isPending() { - return pending != null; - } - - /** - * Parses an incoming String and returns an array of elements. This method is used when the - * data spans multiple lines. - * - * @param nextLine current line to be processed - * @return the comma-tokenized list of elements, or null if nextLine is null - * @throws IOException if bad things happen during the read - */ - public String[] parseLineMulti(String nextLine) throws IOException { - return parseLine(nextLine, true); - } - - /** - * Parses an incoming String and returns an array of elements. This method is used when all data is contained - * in a single line. - * - * @param nextLine Line to be parsed. - * @return the comma-tokenized list of elements, or null if nextLine is null - * @throws IOException if bad things happen during the read - */ - public String[] parseLine(String nextLine) throws IOException { - return parseLine(nextLine, false); - } - - /** - * Parses an incoming String and returns an array of elements. - * - * @param nextLine the string to parse - * @param multi Does it take multiple lines to form a single record. - * @return the comma-tokenized list of elements, or null if nextLine is null - * @throws IOException if bad things happen during the read - */ - private String[] parseLine(String nextLine, boolean multi) throws IOException { - - if (!multi && pending != null) { - pending = null; - } - - if (nextLine == null) { - if (pending != null) { - String s = pending; - pending = null; - return new String[]{s}; - } else { - return null; - } - } - - List tokensOnThisLine = new ArrayList<>(); - StringBuilder sb = new StringBuilder(INITIAL_READ_SIZE); - boolean inQuotes = false; - boolean fromQuotedField = false; - if (pending != null) { - sb.append(pending); - pending = null; - inQuotes = !this.ignoreQuotations;//true; - } - for (int i = 0; i < nextLine.length(); i++) { - - char c = nextLine.charAt(i); - if (c == this.escape) { - if (isNextCharacterEscapable(nextLine, inQuotes(inQuotes), i)) { - i = appendNextCharacterAndAdvanceLoop(nextLine, sb, i); - } - } else if (c == quotechar) { - if (isNextCharacterEscapedQuote(nextLine, inQuotes(inQuotes), i)) { - i = appendNextCharacterAndAdvanceLoop(nextLine, sb, i); - } else { - - inQuotes = !inQuotes; - if (atStartOfField(sb)) { - fromQuotedField = true; - } - - // the tricky case of an embedded quote in the middle: a,bc"d"ef,g - if (!strictQuotes) { - if (i > 2 //not on the beginning of the line - && nextLine.charAt(i - 1) != this.separator //not at the beginning of an escape sequence - && nextLine.length() > (i + 1) && - nextLine.charAt(i + 1) != this.separator //not at the end of an escape sequence - ) { - - if (ignoreLeadingWhiteSpace && sb.length() > 0 && isAllWhiteSpace(sb)) { - sb.setLength(0); - } else { - sb.append(c); - } - - } - } - } - inField = !inField; - } else if (c == separator && !(inQuotes && !ignoreQuotations)) { - tokensOnThisLine.add(convertEmptyToNullIfNeeded(sb.toString(), fromQuotedField)); - fromQuotedField = false; - sb.setLength(0); - inField = false; - } else { - if (!strictQuotes || (inQuotes && !ignoreQuotations)) { - sb.append(c); - inField = true; - fromQuotedField = true; - } - } - - } - // line is done - check status - if ((inQuotes && !ignoreQuotations)) { - if (multi) { - // continuing a quoted section, re-append newline - sb.append('\n'); - pending = sb.toString(); - sb = null; // this partial content is not to be added to field list yet - } else { - throw new IOException("Un-terminated quoted field at end of CSV line"); - } - if (inField) { - fromQuotedField = true; - } - } else { - inField = false; - } - - if (sb != null) { - tokensOnThisLine.add(convertEmptyToNullIfNeeded(sb.toString(), fromQuotedField)); - fromQuotedField = false; - } - return tokensOnThisLine.toArray(new String[tokensOnThisLine.size()]); - - } - - private boolean atStartOfField(StringBuilder sb) { - return sb.length() == 0; - } - - private String convertEmptyToNullIfNeeded(String s, boolean fromQuotedField) { - if (s.isEmpty() && shouldConvertEmptyToNull(fromQuotedField)) { - return null; - } - return s; - } - - private boolean shouldConvertEmptyToNull(boolean fromQuotedField) { - switch (nullFieldIndicator) { - case BOTH: - return true; - case EMPTY_SEPARATORS: - return !fromQuotedField; - case EMPTY_QUOTES: - return fromQuotedField; - default: - return false; - } - } - - /** - * Appends the next character in the line to the stringbuffer. - * - * @param line - line to process - * @param sb - contains the processed character - * @param i - current position in the line. - * @return new position in the line. - */ - private int appendNextCharacterAndAdvanceLoop(String line, StringBuilder sb, int i) { - sb.append(line.charAt(i + 1)); - i++; - return i; - } - - /** - * Determines if we can process as if we were in quotes. - * - * @param inQuotes - are we currently in quotes. - * @return - true if we should process as if we are inside quotes. - */ - private boolean inQuotes(boolean inQuotes) { - return (inQuotes && !ignoreQuotations) || inField; - } - - /** - * Checks to see if the character after the index is a quotation character. - *

- * precondition: the current character is a quote or an escape - * - * @param nextLine the current line - * @param inQuotes true if the current context is quoted - * @param i current index in line - * @return true if the following character is a quote - */ - private boolean isNextCharacterEscapedQuote(String nextLine, boolean inQuotes, int i) { - return inQuotes // we are in quotes, therefore there can be escaped quotes in here. - && nextLine.length() > (i + 1) // there is indeed another character to check. - && isCharacterQuoteCharacter(nextLine.charAt(i + 1)); - } - - /** - * Checks to see if the passed in character is the defined quotation character. - * - * @param c source character - * @return true if c is the defined quotation character - */ - private boolean isCharacterQuoteCharacter(char c) { - return c == quotechar; - } - - /** - * checks to see if the character is the defined escape character. - * - * @param c source character - * @return true if the character is the defined escape character - */ - private boolean isCharacterEscapeCharacter(char c) { - return c == escape; - } - - /** - * Checks to see if the character passed in could be escapable. Escapable characters for openCSV are the - * quotation character or the escape character. - * - * @param c source character - * @return true if the character could be escapable. - */ - private boolean isCharacterEscapable(char c) { - return isCharacterQuoteCharacter(c) || isCharacterEscapeCharacter(c); - } - - /** - * Checks to see if the character after the current index in a String is an escapable character. - * Meaning the next character is either a quotation character or the escape char and you are inside - * quotes. - *

- * precondition: the current character is an escape - * - * @param nextLine the current line - * @param inQuotes true if the current context is quoted - * @param i current index in line - * @return true if the following character is a quote - */ - protected boolean isNextCharacterEscapable(String nextLine, boolean inQuotes, int i) { - return inQuotes // we are in quotes, therefore there can be escaped quotes in here. - && nextLine.length() > (i + 1) // there is indeed another character to check. - && isCharacterEscapable(nextLine.charAt(i + 1)); - } - - /** - * Checks if every element is the character sequence is whitespace. - *

- * precondition: sb.length() is greater than 0 - * - * @param sb A sequence of characters to examine - * @return true if every character in the sequence is whitespace - */ - protected boolean isAllWhiteSpace(CharSequence sb) { - for (int i = 0; i < sb.length(); i++) { - if (Character.isWhitespace(sb.charAt(i))) { - return true; - } - } - return false; - } - - /** - * @return - the null field indicator. - */ - public CSVReaderNullFieldIndicator nullFieldIndicator() { - return nullFieldIndicator; - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVParserBuilder.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVParserBuilder.java deleted file mode 100644 index b60a0bfec257..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVParserBuilder.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package contains a slightly modified version of opencsv library - * without unwanted functionality and dependencies, licensed under Apache 2.0. - * - * See https://search.maven.org/artifact/com.opencsv/opencsv/3.4/bundle - * See http://opencsv.sf.net/ - */ -package org.jkiss.utils.csv; - - -/** - * Builder for creating a CSVParser. - * - * - * final CSVParser parser = - * new CSVParserBuilder() - * .withSeparator('\t') - * .withIgnoreQuotations(true) - * .build(); - * - * - * @see CSVParser - */ -public class CSVParserBuilder { - - private char separator = CSVParser.DEFAULT_SEPARATOR; - private char quoteChar = CSVParser.DEFAULT_QUOTE_CHARACTER; - private char escapeChar = CSVParser.DEFAULT_ESCAPE_CHARACTER; - private boolean strictQuotes = CSVParser.DEFAULT_STRICT_QUOTES; - private boolean ignoreLeadingWhiteSpace = CSVParser.DEFAULT_IGNORE_LEADING_WHITESPACE; - private boolean ignoreQuotations = CSVParser.DEFAULT_IGNORE_QUOTATIONS; - private CSVReaderNullFieldIndicator nullFieldIndicator = CSVReaderNullFieldIndicator.NEITHER; - - /** - * Default constructor. - */ - public CSVParserBuilder() { - } - - /** - * Sets the delimiter to use for separating entries. - * - * @param separator the delimiter to use for separating entries - * @return The CSVParserBuilder - */ - public CSVParserBuilder withSeparator( - final char separator) { - this.separator = separator; - return this; - } - - - /** - * Sets the character to use for quoted elements. - * - * @param quoteChar the character to use for quoted element. - * @return The CSVParserBuilder - */ - public CSVParserBuilder withQuoteChar( - final char quoteChar) { - this.quoteChar = quoteChar; - return this; - } - - - /** - * Sets the character to use for escaping a separator or quote. - * - * @param escapeChar the character to use for escaping a separator or quote. - * @return The CSVParserBuilder - */ - public CSVParserBuilder withEscapeChar( - final char escapeChar) { - this.escapeChar = escapeChar; - return this; - } - - - /** - * Sets the strict quotes setting - if true, characters - * outside the quotes are ignored. - * - * @param strictQuotes if true, characters outside the quotes are ignored - * @return The CSVParserBuilder - */ - public CSVParserBuilder withStrictQuotes( - final boolean strictQuotes) { - this.strictQuotes = strictQuotes; - return this; - } - - /** - * Sets the ignore leading whitespace setting - if true, white space - * in front of a quote in a field is ignored. - * - * @param ignoreLeadingWhiteSpace if true, white space in front of a quote in a field is ignored - * @return The CSVParserBuilder - */ - public CSVParserBuilder withIgnoreLeadingWhiteSpace( - final boolean ignoreLeadingWhiteSpace) { - this.ignoreLeadingWhiteSpace = ignoreLeadingWhiteSpace; - return this; - } - - /** - * Sets the ignore quotations mode - if true, quotations are ignored. - * - * @param ignoreQuotations if true, quotations are ignored - * @return The CSVParserBuilder - */ - public CSVParserBuilder withIgnoreQuotations( - final boolean ignoreQuotations) { - this.ignoreQuotations = ignoreQuotations; - return this; - } - - /** - * Constructs CSVParser. - * - * @return a new CSVParser with defined settings. - */ - public CSVParser build() { - return new CSVParser( - separator, - quoteChar, - escapeChar, - strictQuotes, - ignoreLeadingWhiteSpace, - ignoreQuotations, - nullFieldIndicator); - } - - /** - * @return the defined separator. - */ - public char getSeparator() { - return separator; - } - - /** - * @return the defined quotation character. - */ - public char getQuoteChar() { - return quoteChar; - } - - /** - * @return the defined escape character. - */ - public char getEscapeChar() { - return escapeChar; - } - - /** - * @return the defined strict quotation setting. - */ - public boolean isStrictQuotes() { - return strictQuotes; - } - - /** - * @return the defined ignoreLeadingWhiteSpace setting. - */ - public boolean isIgnoreLeadingWhiteSpace() { - return ignoreLeadingWhiteSpace; - } - - /** - * @return the defined ignoreQuotation setting. - */ - public boolean isIgnoreQuotations() { - return ignoreQuotations; - } - - /** - * Sets the NullFieldIndicator. - * - * @param fieldIndicator - CSVReaderNullFieldIndicator set to what should be considered a null field. - * @return - The CSVParserBuilder - */ - public CSVParserBuilder withFieldAsNull(final CSVReaderNullFieldIndicator fieldIndicator) { - this.nullFieldIndicator = fieldIndicator; - return this; - } - - /** - * @return - the null field indicator. - */ - public CSVReaderNullFieldIndicator nullFieldIndicator() { - return nullFieldIndicator; - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReader.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReader.java deleted file mode 100644 index f16f4583259e..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReader.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package contains a slightly modified version of opencsv library - * without unwanted functionality and dependencies, licensed under Apache 2.0. - * - * See https://search.maven.org/artifact/com.opencsv/opencsv/3.4/bundle - * See http://opencsv.sf.net/ - */ -package org.jkiss.utils.csv; - -import java.io.BufferedReader; -import java.io.Closeable; -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; - -/** - * A very simple CSV reader released under a commercial-friendly license. - * - * @author Glen Smith - */ -public class CSVReader implements Closeable { - - public static final boolean DEFAULT_KEEP_CR = false; - public static final boolean DEFAULT_VERIFY_READER = false; - /** - * The default line to start reading. - */ - public static final int DEFAULT_SKIP_LINES = 0; - private CSVParser parser; - private int skipLines; - private BufferedReader br; - private LineReader lineReader; - private boolean hasNext = true; - private boolean linesSkiped; - private boolean keepCR; - private boolean verifyReader; - - /** - * Constructs CSVReader using a comma for the separator. - * - * @param reader the reader to an underlying CSV source. - */ - public CSVReader(Reader reader) { - this(reader, CSVParser.DEFAULT_SEPARATOR, CSVParser.DEFAULT_QUOTE_CHARACTER, CSVParser.DEFAULT_ESCAPE_CHARACTER); - } - - /** - * Constructs CSVReader with supplied separator. - * - * @param reader the reader to an underlying CSV source. - * @param separator the delimiter to use for separating entries. - */ - public CSVReader(Reader reader, char separator) { - this(reader, separator, CSVParser.DEFAULT_QUOTE_CHARACTER, CSVParser.DEFAULT_ESCAPE_CHARACTER); - } - - /** - * Constructs CSVReader with supplied separator and quote char. - * - * @param reader the reader to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - */ - public CSVReader(Reader reader, char separator, char quotechar) { - this(reader, separator, quotechar, CSVParser.DEFAULT_ESCAPE_CHARACTER, DEFAULT_SKIP_LINES, CSVParser.DEFAULT_STRICT_QUOTES); - } - - /** - * Constructs CSVReader with supplied separator, quote char and quote handling - * behavior. - * - * @param reader the reader to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param strictQuotes sets if characters outside the quotes are ignored - */ - public CSVReader(Reader reader, char separator, char quotechar, boolean strictQuotes) { - this(reader, separator, quotechar, CSVParser.DEFAULT_ESCAPE_CHARACTER, DEFAULT_SKIP_LINES, strictQuotes); - } - - /** - * Constructs CSVReader. - * - * @param reader the reader to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escape the character to use for escaping a separator or quote - */ - - public CSVReader(Reader reader, char separator, - char quotechar, char escape) { - this(reader, separator, quotechar, escape, DEFAULT_SKIP_LINES, CSVParser.DEFAULT_STRICT_QUOTES); - } - - /** - * Constructs CSVReader. - * - * @param reader the reader to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param line the line number to skip for start reading - */ - public CSVReader(Reader reader, char separator, char quotechar, int line) { - this(reader, separator, quotechar, CSVParser.DEFAULT_ESCAPE_CHARACTER, line, CSVParser.DEFAULT_STRICT_QUOTES); - } - - /** - * Constructs CSVReader. - * - * @param reader the reader to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escape the character to use for escaping a separator or quote - * @param line the line number to skip for start reading - */ - public CSVReader(Reader reader, char separator, char quotechar, char escape, int line) { - this(reader, separator, quotechar, escape, line, CSVParser.DEFAULT_STRICT_QUOTES); - } - - /** - * Constructs CSVReader. - * - * @param reader the reader to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escape the character to use for escaping a separator or quote - * @param line the line number to skip for start reading - * @param strictQuotes sets if characters outside the quotes are ignored - */ - public CSVReader(Reader reader, char separator, char quotechar, char escape, int line, boolean strictQuotes) { - this(reader, separator, quotechar, escape, line, strictQuotes, CSVParser.DEFAULT_IGNORE_LEADING_WHITESPACE); - } - - /** - * Constructs CSVReader with all data entered. - * - * @param reader the reader to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escape the character to use for escaping a separator or quote - * @param line the line number to skip for start reading - * @param strictQuotes sets if characters outside the quotes are ignored - * @param ignoreLeadingWhiteSpace it true, parser should ignore white space before a quote in a field - */ - public CSVReader(Reader reader, char separator, char quotechar, char escape, int line, boolean strictQuotes, boolean ignoreLeadingWhiteSpace) { - this(reader, - line, - new CSVParser(separator, quotechar, escape, strictQuotes, ignoreLeadingWhiteSpace)); - } - - /** - * Constructs CSVReader with all data entered. - * - * @param reader the reader to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escape the character to use for escaping a separator or quote - * @param line the line number to skip for start reading - * @param strictQuotes sets if characters outside the quotes are ignored - * @param ignoreLeadingWhiteSpace if true, parser should ignore white space before a quote in a field - * @param keepCR if true the reader will keep carriage returns, otherwise it will discard them. - */ - public CSVReader(Reader reader, char separator, char quotechar, char escape, int line, boolean strictQuotes, - boolean ignoreLeadingWhiteSpace, boolean keepCR) { - this(reader, line, - new CSVParser(separator, quotechar, escape, strictQuotes, ignoreLeadingWhiteSpace), keepCR, DEFAULT_VERIFY_READER); - } - - /** - * Constructs CSVReader with supplied CSVParser. - * - * @param reader the reader to an underlying CSV source. - * @param line the line number to skip for start reading - * @param csvParser the parser to use to parse input - */ - public CSVReader(Reader reader, int line, CSVParser csvParser) { - this(reader, line, csvParser, DEFAULT_KEEP_CR, DEFAULT_VERIFY_READER); - } - - /** - * Constructs CSVReader with supplied CSVParser. - * - * @param reader the reader to an underlying CSV source. - * @param line the line number to skip for start reading - * @param csvParser the parser to use to parse input - * @param keepCR true to keep carriage returns in data read, false otherwise - * @param verifyReader true to verify reader before each read, false otherwise - */ - CSVReader(Reader reader, int line, CSVParser csvParser, boolean keepCR, boolean verifyReader) { - this.br = - (reader instanceof BufferedReader ? - (BufferedReader) reader : - new BufferedReader(reader)); - this.lineReader = new LineReader(br, keepCR); - this.skipLines = line; - this.parser = csvParser; - this.keepCR = keepCR; - this.verifyReader = verifyReader; - } - - /** - * @return the CSVParser used by the reader. - */ - public CSVParser getParser() { - return parser; - } - - /** - * Returns the number of lines in the csv file to skip before processing. This is - * useful when there is miscellaneous data at the beginning of a file. - * - * @return the number of lines in the csv file to skip before processing. - */ - public int getSkipLines() { - return skipLines; - } - - /** - * Returns if the reader will keep carriage returns found in data or remove them. - * - * @return true if reader will keep carriage returns, false otherwise. - */ - public boolean keepCarriageReturns() { - return keepCR; - } - - /** - * Reads the entire file into a List with each element being a String[] of - * tokens. - * - * @return a List of String[], with each String[] representing a line of the - * file. - * @throws IOException if bad things happen during the read - */ - public List readAll() throws IOException { - - List allElements = new ArrayList<>(); - while (hasNext) { - String[] nextLineAsTokens = readNext(); - if (nextLineAsTokens != null) { - allElements.add(nextLineAsTokens); - } - } - return allElements; - - } - - /** - * Reads the next line from the buffer and converts to a string array. - * - * @return a string array with each comma-separated element as a separate - * entry. - * @throws IOException if bad things happen during the read - */ - public String[] readNext() throws IOException { - - String[] result = null; - do { - String nextLine = getNextLine(); - if (!hasNext) { - return result; // should throw if still pending? - } - String[] r = parser.parseLineMulti(nextLine); - if (r.length > 0) { - if (result == null) { - result = r; - } else { - result = combineResultsFromMultipleReads(result, r); - } - } - } while (parser.isPending()); - return result; - } - - /** - * For multi line records this method combines the current result with the result from previous read(s). - * - * @param buffer - previous data read for this record - * @param lastRead - latest data read for this record. - * @return String array with union of the buffer and lastRead arrays. - */ - private String[] combineResultsFromMultipleReads(String[] buffer, String[] lastRead) { - String[] t = new String[buffer.length + lastRead.length]; - System.arraycopy(buffer, 0, t, 0, buffer.length); - System.arraycopy(lastRead, 0, t, buffer.length, lastRead.length); - return t; - } - - /** - * Reads the next line from the file. - * - * @return the next line from the file without trailing newline - * @throws IOException if bad things happen during the read - */ - private String getNextLine() throws IOException { - if (isClosed()) { - hasNext = false; - return null; - } - - if (!this.linesSkiped) { - for (int i = 0; i < skipLines; i++) { - lineReader.readLine(); - } - this.linesSkiped = true; - } - String nextLine = lineReader.readLine(); - if (nextLine == null) { - hasNext = false; - } - return hasNext ? nextLine : null; - } - - /** - * Checks to see if the file is closed. - * - * @return true if the reader can no longer be read from. - */ - private boolean isClosed() { - if (!verifyReader) { - return false; - } - try { - br.mark(1); - int nextByte = br.read(); - br.reset(); // resets stream position, possible because its buffered - return nextByte == -1; // read() returns -1 at end of stream - } catch (IOException e) { - return true; - } - } - - /** - * Closes the underlying reader. - * - * @throws IOException if the close fails - */ - public void close() throws IOException { - br.close(); - } - - /** - * Returns if the CSVReader will verify the reader before each read. - *

- * By default the value is true which is the functionality for version 3.0. - * If set to false the reader is always assumed ready to read - this is the functionality - * for version 2.4 and before. - *

- * The reason this method was needed was that certain types of Readers would return - * false for its ready() method until a read was done (namely readers created using Channels). - * This caused opencsv not to read from those readers. - * - * @return true if CSVReader will verify the reader before reads. False otherwise. - * @link https://sourceforge.net/p/opencsv/bugs/108/ - */ - public boolean verifyReader() { - return this.verifyReader; - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReaderBuilder.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReaderBuilder.java deleted file mode 100644 index e576f6e04705..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReaderBuilder.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package contains a slightly modified version of opencsv library - * without unwanted functionality and dependencies, licensed under Apache 2.0. - * - * See https://search.maven.org/artifact/com.opencsv/opencsv/3.4/bundle - * See http://opencsv.sf.net/ - */ -package org.jkiss.utils.csv; - - -import java.io.Reader; - -/** - * Builder for creating a CSVReader. This should be the preferred method of - * creating a Reader as there are so many possible values to be set it is - * impossible to have constructors for all of them and keep backwards - * compatibility with previous constructors. - * - * - * final CSVParser parser = - * new CSVParserBuilder() - * .withSeparator('\t') - * .withIgnoreQuotations(true) - * .build(); - * final CSVReader reader = - * new CSVReaderBuilder(new StringReader(csv)) - * .withSkipLines(1) - * .withCSVParser(parser) - * .build(); - * - * - * @see CSVReader - */ -public class CSVReaderBuilder { - - private final CSVParserBuilder parserBuilder = new CSVParserBuilder(); - private final Reader reader; - private int skipLines = CSVReader.DEFAULT_SKIP_LINES; - /*@Nullable*/private CSVParser csvParser = null; - private boolean keepCR; - private boolean verifyReader = CSVReader.DEFAULT_VERIFY_READER; - private CSVReaderNullFieldIndicator nullFieldIndicator = CSVReaderNullFieldIndicator.NEITHER; - - /** - * Sets the reader to an underlying CSV source. - * - * @param reader the reader to an underlying CSV source. - */ - public CSVReaderBuilder( - final Reader reader) { - if (reader == null) { - throw new IllegalArgumentException("Reader may not be null"); - } - this.reader = reader; - } - - /** - * Used by unit tests. - * - * @return the reader. - */ - protected Reader getReader() { - return reader; - } - - /** - * used by unit tests. - * - * @return The set number of lines to skip - */ - protected int getSkipLines() { - return skipLines; - } - - /** - * used by unit tests. - * - * @return the csvParser used by the builder. - */ - protected CSVParser getCsvParser() { - return csvParser; - } - - /** - * Sets the line number to skip for start reading. - * - * @param skipLines the line number to skip for start reading. - * @return the CSVReaderBuilder with skipLines set. - */ - public CSVReaderBuilder withSkipLines( - final int skipLines) { - this.skipLines = (skipLines <= 0 ? 0 : skipLines); - return this; - } - - - /** - * Sets the parser to use to parse the input. - * - * @param csvParser the parser to use to parse the input. - * @return the CSVReaderBuilder with the CSVParser set. - */ - public CSVReaderBuilder withCSVParser( - final /*@Nullable*/ CSVParser csvParser) { - this.csvParser = csvParser; - return this; - } - - - /** - * Creates the CSVReader. - * @return the CSVReader based on the set criteria. - */ - public CSVReader build() { - final CSVParser parser = - (csvParser != null ? csvParser : parserBuilder.withFieldAsNull(nullFieldIndicator).build()); - return new CSVReader(reader, skipLines, parser, keepCR, verifyReader); - } - - /** - * Sets if the reader will keep or discard carriage returns. - * - * @param keepCR - true to keep carriage returns, false to discard. - * @return the CSVReaderBuilder based on the set criteria. - */ - public CSVReaderBuilder withKeepCarriageReturn(boolean keepCR) { - this.keepCR = keepCR; - return this; - } - - /** - * Returns if the reader built will keep or discard carriage returns. - * - * @return true if the reader built will keep carriage returns, false otherwise. - */ - protected boolean keepCarriageReturn() { - return this.keepCR; - } - - /** - * Checks to see if the CSVReader should verify the reader state before reads or not. - * - * This should be set to false if you are using some form of asynchronous reader (like readers created - * by the java.nio.* classes). - * - * The default value is true. - * - * @param verifyReader true if CSVReader should verify reader before each read, false otherwise. - * @return The CSVReaderBuilder based on this criteria. - */ - public CSVReaderBuilder withVerifyReader(boolean verifyReader) { - this.verifyReader = verifyReader; - return this; - } - - /** - * Checks to see if it should treat an field with two separators, two quotes, or both as a null field. - * - * @param indicator - CSVReaderNullFieldIndicator set to what should be considered a null field. - * @return The CSVReaderBuilder based on this criteria. - */ - public CSVReaderBuilder withFieldAsNull(CSVReaderNullFieldIndicator indicator) { - this.nullFieldIndicator = indicator; - return this; - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReaderNullFieldIndicator.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReaderNullFieldIndicator.java deleted file mode 100644 index 426d01a96119..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVReaderNullFieldIndicator.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package contains a slightly modified version of opencsv library - * without unwanted functionality and dependencies, licensed under Apache 2.0. - * - * See https://search.maven.org/artifact/com.opencsv/opencsv/3.4/bundle - * See http://opencsv.sf.net/ - */ -package org.jkiss.utils.csv; - -/** - * Enumeration used to tell the CSVParser what to consider null. - *

- * EMPTY_SEPARATORS - two sequential separators are null. - * EMPTY_QUOTES - two sequential quotes are null - * BOTH - both are null - * NEITHER - default. Both are considered empty string. - */ -public enum CSVReaderNullFieldIndicator { - EMPTY_SEPARATORS, - EMPTY_QUOTES, - BOTH, - NEITHER; -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVWriter.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVWriter.java deleted file mode 100644 index 0afb172d239a..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/CSVWriter.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package contains a slightly modified version of opencsv library - * without unwanted functionality and dependencies, licensed under Apache 2.0. - * - * See https://search.maven.org/artifact/com.opencsv/opencsv/3.4/bundle - * See http://opencsv.sf.net/ - */ -package org.jkiss.utils.csv; - -import java.io.*; -import java.util.List; - -/** - * A very simple CSV writer released under a commercial-friendly license. - * - * @author Glen Smith - */ -public class CSVWriter implements Closeable, Flushable { - - public static final int INITIAL_STRING_SIZE = 128; - /** - * The character used for escaping quotes. - */ - public static final char DEFAULT_ESCAPE_CHARACTER = '"'; - /** - * The default separator to use if none is supplied to the constructor. - */ - public static final char DEFAULT_SEPARATOR = ','; - /** - * The default quote character to use if none is supplied to the - * constructor. - */ - public static final char DEFAULT_QUOTE_CHARACTER = '"'; - /** - * The quote constant to use when you wish to suppress all quoting. - */ - public static final char NO_QUOTE_CHARACTER = '\u0000'; - /** - * The escape constant to use when you wish to suppress all escaping. - */ - public static final char NO_ESCAPE_CHARACTER = '\u0000'; - /** - * Default line terminator uses platform encoding. - */ - public static final String DEFAULT_LINE_END = "\n"; - private Writer rawWriter; - private PrintWriter pw; - private char separator; - private char quotechar; - private char escapechar; - private String lineEnd; - - /** - * Constructs CSVWriter using a comma for the separator. - * - * @param writer the writer to an underlying CSV source. - */ - public CSVWriter(Writer writer) { - this(writer, DEFAULT_SEPARATOR); - } - - /** - * Constructs CSVWriter with supplied separator. - * - * @param writer the writer to an underlying CSV source. - * @param separator the delimiter to use for separating entries. - */ - public CSVWriter(Writer writer, char separator) { - this(writer, separator, DEFAULT_QUOTE_CHARACTER); - } - - /** - * Constructs CSVWriter with supplied separator and quote char. - * - * @param writer the writer to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - */ - public CSVWriter(Writer writer, char separator, char quotechar) { - this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER); - } - - /** - * Constructs CSVWriter with supplied separator and quote char. - * - * @param writer the writer to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escapechar the character to use for escaping quotechars or escapechars - */ - public CSVWriter(Writer writer, char separator, char quotechar, char escapechar) { - this(writer, separator, quotechar, escapechar, DEFAULT_LINE_END); - } - - - /** - * Constructs CSVWriter with supplied separator and quote char. - * - * @param writer the writer to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param lineEnd the line feed terminator to use - */ - public CSVWriter(Writer writer, char separator, char quotechar, String lineEnd) { - this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER, lineEnd); - } - - - /** - * Constructs CSVWriter with supplied separator, quote char, escape char and line ending. - * - * @param writer the writer to an underlying CSV source. - * @param separator the delimiter to use for separating entries - * @param quotechar the character to use for quoted elements - * @param escapechar the character to use for escaping quotechars or escapechars - * @param lineEnd the line feed terminator to use - */ - public CSVWriter(Writer writer, char separator, char quotechar, char escapechar, String lineEnd) { - this.rawWriter = writer; - this.pw = new PrintWriter(writer); - this.separator = separator; - this.quotechar = quotechar; - this.escapechar = escapechar; - this.lineEnd = lineEnd; - } - - /** - * Writes the entire list to a CSV file. The list is assumed to be a - * String[] - * - * @param allLines a List of String[], with each String[] representing a line of - * the file. - * @param applyQuotesToAll true if all values are to be quoted. false if quotes only - * to be applied to values which contain the separator, escape, - * quote or new line characters. - */ - public void writeAll(List allLines, boolean applyQuotesToAll) { - for (String[] line : allLines) { - writeNext(line, applyQuotesToAll); - } - } - - /** - * Writes the entire list to a CSV file. The list is assumed to be a - * String[] - * - * @param allLines a List of String[], with each String[] representing a line of - * the file. - */ - public void writeAll(List allLines) { - for (String[] line : allLines) { - writeNext(line); - } - } - - /** - * Writes the next line to the file. - * - * @param nextLine a string array with each comma-separated element as a separate - * entry. - * @param applyQuotesToAll true if all values are to be quoted. false applies quotes only - * to values which contain the separator, escape, quote or new line characters. - */ - public void writeNext(String[] nextLine, boolean applyQuotesToAll) { - - if (nextLine == null) { - return; - } - - StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE); - for (int i = 0; i < nextLine.length; i++) { - - if (i != 0) { - sb.append(separator); - } - - String nextElement = nextLine[i]; - - if (nextElement == null) { - continue; - } - - Boolean stringContainsSpecialCharacters = stringContainsSpecialCharacters(nextElement); - - if ((applyQuotesToAll || stringContainsSpecialCharacters) && quotechar != NO_QUOTE_CHARACTER) { - sb.append(quotechar); - } - - if (stringContainsSpecialCharacters) { - sb.append(processLine(nextElement)); - } else { - sb.append(nextElement); - } - - if ((applyQuotesToAll || stringContainsSpecialCharacters) && quotechar != NO_QUOTE_CHARACTER) { - sb.append(quotechar); - } - } - - sb.append(lineEnd); - pw.write(sb.toString()); - } - - /** - * Writes the next line to the file. - * - * @param nextLine a string array with each comma-separated element as a separate - * entry. - */ - public void writeNext(String[] nextLine) { - writeNext(nextLine, true); - } - - /** - * checks to see if the line contains special characters. - * - * @param line - element of data to check for special characters. - * @return true if the line contains the quote, escape, separator, newline or return. - */ - private boolean stringContainsSpecialCharacters(String line) { - return line.indexOf(quotechar) != -1 || line.indexOf(escapechar) != -1 || line.indexOf(separator) != -1 || line.contains(DEFAULT_LINE_END) || line.contains("\r"); - } - - /** - * Processes all the characters in a line. - * - * @param nextElement - element to process. - * @return a StringBuilder with the elements data. - */ - protected StringBuilder processLine(String nextElement) { - StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE); - for (int j = 0; j < nextElement.length(); j++) { - char nextChar = nextElement.charAt(j); - processCharacter(sb, nextChar); - } - - return sb; - } - - /** - * Appends the character to the StringBuilder adding the escape character if needed. - * - * @param sb - StringBuffer holding the processed character. - * @param nextChar - character to process - */ - private void processCharacter(StringBuilder sb, char nextChar) { - if (escapechar != NO_ESCAPE_CHARACTER && (nextChar == quotechar || nextChar == escapechar)) { - sb.append(escapechar).append(nextChar); - } else { - sb.append(nextChar); - } - } - - /** - * Flush underlying stream to writer. - * - * @throws IOException if bad things happen - */ - public void flush() throws IOException { - - pw.flush(); - - } - - /** - * Close the underlying stream writer flushing any buffered content. - * - * @throws IOException if bad things happen - */ - public void close() throws IOException { - flush(); - pw.close(); - rawWriter.close(); - } - - /** - * Checks to see if the there has been an error in the printstream. - * - * @return true if the print stream has encountered an error, - * either on the underlying output stream or during a format - * conversion. - */ - public boolean checkError() { - return pw.checkError(); - } - - /** - * flushes the writer without throwing any exceptions. - */ - public void flushQuietly() { - try { - flush(); - } catch (IOException e) { - // catch exception and ignore. - } - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/LineReader.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/LineReader.java deleted file mode 100644 index f0231a75bf93..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/csv/LineReader.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This package contains a slightly modified version of opencsv library - * without unwanted functionality and dependencies, licensed under Apache 2.0. - * - * See https://search.maven.org/artifact/com.opencsv/opencsv/3.4/bundle - * See http://opencsv.sf.net/ - */ -package org.jkiss.utils.csv; - -import java.io.BufferedReader; -import java.io.IOException; - -/** - * This class was created for issue #106 (https://sourceforge.net/p/opencsv/bugs/106/) where - * carriage returns were being removed. This class allows the user to determine if they wish to keep or - * remove them from the data being read. - *

- * Created by scott on 2/19/15. - */ - -public class LineReader { - private final BufferedReader reader; - private final boolean keepCarriageReturns; - - /** - * LineReader constructor. - * - * @param reader - Reader that data will be read from. - * @param keepCarriageReturns - true if carriage returns should remain in the data, false to remove them. - */ - public LineReader(BufferedReader reader, boolean keepCarriageReturns) { - this.reader = reader; - this.keepCarriageReturns = keepCarriageReturns; - } - - /** - * Reads the next line from the Reader. - * - * @return - Line read from reader. - * @throws IOException - on error from BufferedReader - */ - public String readLine() throws IOException { - return keepCarriageReturns ? readUntilNewline() : reader.readLine(); - } - - private String readUntilNewline() throws IOException { - StringBuilder sb = new StringBuilder(CSVParser.INITIAL_READ_SIZE); - for (int c = reader.read(); c > -1 && c != '\n'; c = reader.read()) { - sb.append((char) c); - } - - return sb.length() > 0 ? sb.toString() : null; - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/io/BOMInputStream.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/io/BOMInputStream.java deleted file mode 100644 index 84b398f490bc..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/io/BOMInputStream.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.io; - -import org.jkiss.code.NotNull; -import org.jkiss.code.Nullable; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; - -/** - * This class wraps a stream that includes an - * encoded {@link ByteOrderMark} as its first bytes. - *

- * This class detects these bytes and skips them and - * return the subsequent byte as the first byte in the stream. - *

- * This class is highly inspired by the BOMInputStream - * class from the Apache Commons library. - * - * @see Wikipedia - Byte Order Mark - */ -public class BOMInputStream extends InputStream { - private static final Comparator BOM_LENGTH_COMPARATOR = Comparator.comparing(ByteOrderMark::length).reversed(); - - private final InputStream in; - private final List boms; - private ByteOrderMark bom; - private int[] firstBytes; - private int fbLength; - private int fbIndex; - private int markFbIndex; - private boolean markedAtStart; - - public BOMInputStream(@NotNull InputStream delegate, @NotNull ByteOrderMark... boms) { - if (boms.length == 0) { - throw new IllegalArgumentException("No BOMs specified"); - } - - this.in = delegate; - this.boms = Arrays.asList(boms); - this.boms.sort(BOM_LENGTH_COMPARATOR); - } - - public BOMInputStream(@NotNull InputStream delegate, @NotNull Charset charset) { - this(delegate, ByteOrderMark.fromCharset(charset)); - } - - public BOMInputStream(@NotNull InputStream delegate) { - this(delegate, ByteOrderMark.UTF_8); - } - - @Override - public int read() throws IOException { - getBOM(); - return fbIndex < fbLength ? firstBytes[fbIndex++] : in.read(); - } - - @Override - public synchronized void mark(int limit) { - markFbIndex = fbIndex; - markedAtStart = firstBytes == null; - in.mark(limit); - } - - @Override - public synchronized void reset() throws IOException { - fbIndex = markFbIndex; - if (markedAtStart) { - firstBytes = null; - } - in.reset(); - } - - @Nullable - public ByteOrderMark getBOM() throws IOException { - if (firstBytes == null) { - fbLength = 0; - firstBytes = new int[boms.get(0).length()]; - for (int i = 0; i < firstBytes.length; i++) { - firstBytes[i] = in.read(); - fbLength++; - if (firstBytes[i] < 0) { - break; - } - } - bom = find(); - if (bom != null) { - if (bom.length() < firstBytes.length) { - fbIndex = bom.length(); - } else { - fbLength = 0; - } - } - } - return bom; - } - - public boolean hasBOM() throws IOException { - return getBOM() != null; - } - - public boolean hasBOM(@NotNull ByteOrderMark bom) throws IOException { - if (!boms.contains(bom)) { - throw new IllegalArgumentException("Stream is not configured to detect " + bom); - } - getBOM(); - return this.bom != null && this.bom.equals(bom); - } - - @Nullable - private ByteOrderMark find() { - for (ByteOrderMark bom : boms) { - if (matches(bom)) { - return bom; - } - } - return null; - } - - private boolean matches(@NotNull ByteOrderMark bom) { - for (int i = 0; i < bom.length(); i++) { - if (bom.get(i) != firstBytes[i]) { - return false; - } - } - return true; - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/io/ByteOrderMark.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/io/ByteOrderMark.java deleted file mode 100644 index 5f69fcd88bcb..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/io/ByteOrderMark.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.io; - -import org.jkiss.code.NotNull; - -import java.nio.charset.Charset; - -public enum ByteOrderMark implements Comparable { - /** - * UTF-8 BOM - */ - UTF_8("UTF-8", new int[]{0xEF, 0xBB, 0xBF}), - - /** - * UTF-16BE BOM (Big-Endian) - */ - UTF_16BE("UTF-16BE", new int[]{0xFE, 0xFF}), - - /** - * UTF-16LE BOM (Little-Endian) - */ - UTF_16LE("UTF-16LE", new int[]{0xFF, 0xFE}), - - /** - * UTF-32BE BOM (Big-Endian) - */ - UTF_32BE("UTF-32BE", new int[]{0x00, 0x00, 0xFE, 0xFF}), - - /** - * UTF-32LE BOM (Little-Endian) - */ - UTF_32LE("UTF-32LE", new int[]{0xFF, 0xFE, 0x00, 0x00}); - - private final String charsetName; - private final int[] bytes; - - ByteOrderMark(@NotNull String charsetName, @NotNull int[] bytes) { - this.charsetName = charsetName; - this.bytes = bytes; - } - - @NotNull - public String getCharsetName() { - return charsetName; - } - - @NotNull - public byte[] getBytes() { - final byte[] buffer = new byte[bytes.length]; - for (int index = 0; index < bytes.length; index++) { - buffer[index] = (byte) (bytes[index] & 0xFF); - } - return buffer; - } - - public int get(int position) { - return bytes[position]; - } - - public int length() { - return bytes.length; - } - - @NotNull - public static ByteOrderMark fromCharset(@NotNull Charset charset) { - return fromCharset(charset.name()); - } - - @NotNull - public static ByteOrderMark fromCharset(@NotNull String charsetName) { - for (ByteOrderMark bom : values()) { - if (bom.charsetName.equalsIgnoreCase(charsetName)) { - return bom; - } - } - throw new IllegalArgumentException("Can't find BOM for charset " + charsetName); - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RequestMapping.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RequestMapping.java deleted file mode 100644 index 669deb6c94a6..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RequestMapping.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.rest; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface RequestMapping { - /** - * Mapping for the annotated method. - */ - String value() default ""; - - /** - * Timeout (in seconds) for this mapping. - */ - int timeout() default 0; -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RequestParameter.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RequestParameter.java deleted file mode 100644 index f80642d86c5b..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RequestParameter.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.rest; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface RequestParameter { - /** - * Name of the parameter. - */ - String value(); -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestClient.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestClient.java deleted file mode 100644 index c68d7f138ff9..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestClient.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.rest; - -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import org.jkiss.code.NotNull; -import org.jkiss.utils.BeanUtils; -import org.jkiss.utils.CommonUtils; - -import java.lang.reflect.*; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpRequest.BodyPublishers; -import java.net.http.HttpResponse; -import java.net.http.HttpResponse.BodySubscribers; -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class RestClient { - - private static final Pattern ST_LINE_PATTERN = Pattern.compile("\\s*at\\s+([\\w/.$]+)\\((.+)\\)"); - - private RestClient() { - // prevents instantiation - } - - @NotNull - public static T create(@NotNull URI uri, @NotNull Class cls, @NotNull Gson gson) { - final Object proxy = Proxy.newProxyInstance( - cls.getClassLoader(), - new Class[]{cls, RestProxy.class}, - new ClientInvocationHandler(cls, uri, gson) - ); - - return cls.cast(proxy); - } - - @NotNull - public static Builder builder(@NotNull URI uri, @NotNull Class cls) { - return new Builder<>(uri, cls); - } - - public static final class Builder { - private final URI uri; - private final Class cls; - private Gson gson; - - private Builder(@NotNull URI uri, @NotNull Class cls) { - this.uri = uri; - this.cls = cls; - this.gson = RestConstants.DEFAULT_GSON; - } - - @NotNull - public Builder setGson(@NotNull Gson gson) { - this.gson = gson; - return this; - } - - @NotNull - public T create() { - return RestClient.create(uri, cls, gson); - } - } - - private static class ClientInvocationHandler implements InvocationHandler, RestProxy { - @NotNull - private final Class clientClass; - private final URI uri; - private final Gson gson; - private final ExecutorService httpExecutor; - private final HttpClient client; - private final ThreadLocal resultType = new ThreadLocal<>(); - - private ClientInvocationHandler(@NotNull Class clientClass, @NotNull URI uri, @NotNull Gson gson) { - this.clientClass = clientClass; - this.uri = uri; - this.gson = gson; - this.httpExecutor = Executors.newSingleThreadExecutor(); - this.client = HttpClient.newBuilder() - .executor(httpExecutor) - .build(); - } - - @Override - public synchronized Object invoke(Object proxy, Method method, Object[] args) throws RestException { - Class declaringClass = method.getDeclaringClass(); - if (declaringClass == Object.class) { - return BeanUtils.handleObjectMethod(proxy, method, args); - } else if (declaringClass == RestProxy.class) { - setNextCallResultType((Type) args[0]); - return null; - } else if (method.getName().equals("close") && (declaringClass == AutoCloseable.class || declaringClass == clientClass)) { - closeClient(); - return null; - } - if (httpExecutor.isShutdown() || httpExecutor.isTerminated()) { - throw new RestException("Rest client has been terminated"); - } - - final RequestMapping mapping = method.getDeclaredAnnotation(RequestMapping.class); - - if (mapping == null) { - throw createException(method, "it's not annotated with @RequestMapping"); - } - - final Parameter[] parameters = method.getParameters(); - final Map values = new LinkedHashMap<>(parameters.length); - - for (int i = 0; i < parameters.length; i++) { - final Parameter p = parameters[i]; - final RequestParameter param = p.getDeclaredAnnotation(RequestParameter.class); - - if (param == null) { - throw createException(method, "one or more of its parameters are not annotated with @RequestParameter"); - } - - if (CommonUtils.isEmptyTrimmed(param.value())) { - throw createException(method, "one or more of its parameters has empty name specified in @RequestParameter"); - } - - if (values.put(param.value(), gson.toJsonTree(args[i])) != null) { - throw createException(method, "one or more of its parameters share the same name specified in @RequestParameter"); - } - } - - try { - String endpoint = mapping.value(); - if (CommonUtils.isEmpty(endpoint)) { - endpoint = method.getName(); - } - StringBuilder url = new StringBuilder(); - url.append(uri); - if (url.charAt(url.length() - 1) != '/') url.append('/'); - url.append(endpoint); - HttpResponse.BodyHandler readerBodyHandler = - info -> BodySubscribers.ofString(StandardCharsets.UTF_8); - String requestString = gson.toJson(values); - - final HttpRequest.Builder builder = HttpRequest.newBuilder() - .uri(URI.create(url.toString())) - .header("Content-Type", "application/json") - .POST(BodyPublishers.ofString(requestString)); - - if (mapping.timeout() > 0) { - builder.timeout(Duration.ofSeconds(mapping.timeout())); - } - - final HttpResponse response = client.send( - builder.build(), - readerBodyHandler - ); - - String contents = response.body(); - if (response.statusCode() != RestConstants.SC_OK) { - handleError(contents); - } - - Type returnType = resultType.get(); - if (returnType == null) { - returnType = method.getReturnType(); - } else { - resultType.remove(); - } - if (returnType == void.class) { - return null; - } - if (returnType instanceof TypeVariable) { - Type[] bounds = ((TypeVariable) returnType).getBounds(); - if (bounds.length > 0) { - returnType = bounds[0]; - } - } - if (returnType instanceof ParameterizedType && ((ParameterizedType) returnType).getRawType() == Class.class) { - // Convert to raw class type to force our serializer to work - returnType = Class.class; - } - - return gson.fromJson(contents, returnType); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new RestException(e); - } - } - - private void closeClient() { - if (!httpExecutor.isShutdown()) { - httpExecutor.shutdown(); - } - } - - @NotNull - private static RestException createException(@NotNull Method method, @NotNull String reason) { - return new RestException("Unable to invoke the method " + method + " because " + reason); - } - - @Override - public void setNextCallResultType(Type type) { - this.resultType.set(type); - } - } - - private static void handleError(String contents) throws RestException { - String[] stackTraceRows = contents.split("\n"); - String errorLine = stackTraceRows[0]; - List stackTraceElements = new ArrayList<>(); - for (int i = 1; i < stackTraceRows.length; i++) { - Matcher matcher = ST_LINE_PATTERN.matcher(stackTraceRows[i]); - if (matcher.find()) { - String methodRef = matcher.group(1); - int divPos = methodRef.lastIndexOf('.'); - String className = methodRef.substring(0, divPos); - String methodName = methodRef.substring(divPos + 1); - - String classRef = matcher.group(2); - divPos = classRef.indexOf(':'); - String fileName; - int fileLine; - if (divPos == -1) { - fileName = classRef; - fileLine = -1; - } else { - fileName = classRef.substring(0, divPos).trim(); - fileLine = CommonUtils.toInt(classRef.substring(divPos + 1).trim()); - } - stackTraceElements.add( - new StackTraceElement(className, methodName, fileName, fileLine)); - } - } - RestException runtimeException = new RestException(errorLine); - Collections.addAll(stackTraceElements, runtimeException.getStackTrace()); - runtimeException.setStackTrace(stackTraceElements.toArray(new StackTraceElement[0])); - - throw runtimeException; - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestConstants.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestConstants.java deleted file mode 100644 index eadf0fe31ec0..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestConstants.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.rest; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -public class RestConstants { - public static final int SC_OK = 200; - public static final int SC_FORBIDDEN = 403; - public static final int SC_UNSUPPORTED = 405; - public static final int SC_NOT_FOUND = 404; - public static final int SC_SERVER_ERROR = 500; - - static final Gson DEFAULT_GSON = new GsonBuilder() - .setLenient() - .disableHtmlEscaping() - .serializeNulls() - .create(); -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestException.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestException.java deleted file mode 100644 index 2b98b27bbd6a..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.rest; - -public class RestException extends RuntimeException { - public RestException(String message) { - super(message); - } - - public RestException(String message, Throwable cause) { - super(message, cause); - } - - public RestException(Throwable cause) { - super(cause); - } - - public RestException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestProxy.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestProxy.java deleted file mode 100644 index 097f598867fc..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestProxy.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.rest; - -import java.lang.reflect.Type; - -public interface RestProxy { - - void setNextCallResultType(Type resultType); -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestServer.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestServer.java deleted file mode 100644 index ceb9f19c10a0..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/rest/RestServer.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.rest; - -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; -import com.google.gson.reflect.TypeToken; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; -import org.jkiss.code.NotNull; -import org.jkiss.code.Nullable; -import org.jkiss.utils.CommonUtils; - -import java.io.*; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.lang.reflect.Type; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.*; -import java.util.function.Predicate; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class RestServer { - private static final Logger log = Logger.getLogger(RestServer.class.getName()); - private HttpServer server; - - public RestServer( - @NotNull Class cls, - @NotNull T object, - @NotNull Gson gson, - @NotNull Predicate filter, - int port, - int backlog - ) throws IOException { - InetSocketAddress listenAddr = new InetSocketAddress(InetAddress.getLoopbackAddress(), port); - server = HttpServer.create(listenAddr, backlog); - server.createContext("/", createHandler(cls, object, gson, filter)); - server.setExecutor(createExecutor()); - server.start(); - } - - @NotNull - public static Builder builder(@NotNull Class cls, @NotNull T object) { - return new Builder<>(object, cls); - } - - public boolean isRunning() { - return server != null; - } - - public void stop() { - stop(1); - } - - public void stop(int delay) { - try { - server.stop(delay); - - final Executor executor = server.getExecutor(); - if (executor instanceof ExecutorService) { - ((ExecutorService) executor).shutdown(); - } - } finally { - server = null; - } - } - - @NotNull - public InetSocketAddress getAddress() { - return server.getAddress(); - } - - @NotNull - protected Executor createExecutor() { - return new ThreadPoolExecutor(1, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); - } - - @NotNull - protected RequestHandler createHandler( - @NotNull Class cls, - @NotNull T object, - @NotNull Gson gson, - @NotNull Predicate filter - ) { - return new RequestHandler<>(cls, object, gson, filter); - } - - protected static class RequestHandler implements HttpHandler { - private static final Type REQUEST_TYPE = new TypeToken>() {}.getType(); - - private final T object; - private final Gson gson; - private final Map mappings; - private final Predicate filter; - - protected RequestHandler( - @NotNull Class cls, - @NotNull T object, - @NotNull Gson gson, - @NotNull Predicate filter - ) { - this.object = object; - this.gson = gson; - this.mappings = createMappings(cls); - this.filter = filter; - } - - @SuppressWarnings("TryFinallyCanBeTryWithResources") - @Override - public void handle(HttpExchange exchange) throws IOException { - Response response; - - try { - response = createResponse(exchange); - } catch (IOException e) { - log.log(Level.SEVERE, "IO error", e); - response = new Response<>(e.getMessage(), String.class, 500); - } - - try { - Object responseObject = response.object; - if (responseObject == null) { - responseObject = "Internal error"; - } - if (response.code == RestConstants.SC_OK) { - String responseText; - if (response.type == void.class) { - responseText = CommonUtils.toString(response.object); - exchange.getResponseHeaders().add("Content-Type", "text/plain"); - } else { - try { - responseText = gson.toJson(response.object, response.type); - } catch (Throwable e) { - // Serialization error - StringWriter buf = new StringWriter(); - new RestException("JSON serialization error: " + e.getMessage(), e).printStackTrace(new PrintWriter(buf, true)); - - sendError(exchange, RestConstants.SC_SERVER_ERROR, buf.toString()); - return; - } - exchange.getResponseHeaders().add("Content-Type", "application/json"); - } - byte[] responseBytes = responseText.getBytes(StandardCharsets.UTF_8); - - exchange.sendResponseHeaders(RestConstants.SC_OK, responseBytes.length); - try (OutputStream responseBody = exchange.getResponseBody()) { - responseBody.write(responseBytes); - } - } else { - sendError(exchange, response.code, responseObject); - } - } catch (Throwable e) { - log.log(Level.SEVERE, "Internal IO error", e); - throw e; - } finally { - exchange.close(); - } - } - - private void sendError(HttpExchange exchange, int resultCode, Object responseObject) throws IOException { - String responseText = responseObject.toString(); - byte[] result = responseText.getBytes(StandardCharsets.UTF_8); - - exchange.getResponseHeaders().add("Content-Type", "text/plain"); - exchange.sendResponseHeaders(resultCode, result.length); - try (OutputStream responseBody = exchange.getResponseBody()) { - responseBody.write(result); - } - } - - @NotNull - protected Response createResponse(@NotNull HttpExchange exchange) throws IOException { - if (!filter.test(exchange.getRemoteAddress())) { - return new Response<>("Access is forbidden", String.class, RestConstants.SC_FORBIDDEN); - } - - if (!exchange.getRequestMethod().equalsIgnoreCase("POST")) { - return new Response<>("Unsupported method", String.class, RestConstants.SC_UNSUPPORTED); - } - - final URI uri = exchange.getRequestURI(); - final String path = uri.getPath().replaceAll("^/+", ""); - final Method method = mappings.get(path); - - if (method == null) { - return new Response<>("Mapping " + path + " not found", String.class, RestConstants.SC_NOT_FOUND); - } - - final Map request; - - try (Reader reader = new BufferedReader(new InputStreamReader(exchange.getRequestBody()))) { - request = gson.fromJson(reader, REQUEST_TYPE); - } - - final Parameter[] parameters = method.getParameters(); - final Object[] values = new Object[parameters.length]; - - for (int i = 0; i < parameters.length; i++) { - final Parameter p = parameters[i]; - final RequestParameter param = p.getDeclaredAnnotation(RequestParameter.class); - final JsonElement element = request.getOrDefault(param.value(), JsonNull.INSTANCE); - values[i] = gson.fromJson(element, p.getParameterizedType()); - } - - try { - final Object result = method.invoke(object, values); - final Type type = method.getGenericReturnType(); - return new Response<>(result, type, RestConstants.SC_OK); - } catch (Throwable e) { - if (e instanceof InvocationTargetException) { - e = ((InvocationTargetException) e).getTargetException(); - } - log.log(Level.SEVERE, "RPC call '" + uri + "' failed: " + e.getMessage()); - StringWriter buf = new StringWriter(); - e.printStackTrace(new PrintWriter(buf, true)); - return new Response<>(buf.toString(), String.class, RestConstants.SC_SERVER_ERROR); - } - } - - @NotNull - protected Map createMappings(@NotNull Class cls) { - final Map mappings = new HashMap<>(); - - for (Method method : cls.getDeclaredMethods()) { - if (method.getDeclaringClass() == Object.class) { - continue; - } - - final RequestMapping mapping = method.getDeclaredAnnotation(RequestMapping.class); - - if (mapping == null) { - continue; - } - - String methodEndpoint = mapping.value(); - if (CommonUtils.isEmptyTrimmed(mapping.value())) { - methodEndpoint = method.getName(); - } - - if (mappings.containsKey(methodEndpoint)) { - log.warning("Method " + method + " has duplicate mapping, skipping"); - continue; - } - - method.setAccessible(true); - mappings.put(methodEndpoint, method); - } - - return Collections.unmodifiableMap(mappings); - } - } - - public static final class Builder { - private static final Predicate DEFAULT_PREDICATE = address -> true; - - private final T object; - private final Class cls; - private Gson gson; - private int port; - private int backlog; - private Predicate filter = DEFAULT_PREDICATE; - - private Builder(@NotNull T object, @NotNull Class cls) { - this.object = object; - this.cls = cls; - this.gson = RestConstants.DEFAULT_GSON; - this.port = 0; - this.backlog = 0; - } - - @NotNull - public Builder setGson(@NotNull Gson gson) { - this.gson = gson; - return this; - } - - @NotNull - public Builder setPort(int port) { - this.port = port; - return this; - } - - @NotNull - public Builder setBacklog(int backlog) { - this.backlog = backlog; - return this; - } - - @NotNull - public Builder setFilter(@NotNull Predicate filter) { - this.filter = filter; - return this; - } - - @NotNull - public RestServer create() { - try { - return new RestServer<>(cls, object, gson, filter, port, backlog); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - } - - private static class Response { - private final T object; - private final Type type; - private final int code; - - public Response(@Nullable T object, @NotNull Type type, int code) { - this.object = object; - this.type = type; - this.code = code; - } - } -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/time/ExtendedDateFormat.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/time/ExtendedDateFormat.java deleted file mode 100644 index 36d734d8e8cb..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/time/ExtendedDateFormat.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.time; - -import org.jkiss.code.NotNull; - -import java.sql.Timestamp; -import java.text.FieldPosition; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -/** - * Formatter adapted to support nanoseconds from java.sql.Timestanp. - */ -public class ExtendedDateFormat extends SimpleDateFormat { - - private static final String NINE_ZEROES = "000000000"; - private static final int MAX_NANO_LENGTH = 8; - - private int nanoStart = -1, nanoLength; - private boolean nanoOptional; - private String nanoPrefix, nanoPostfix; - - public ExtendedDateFormat(String pattern) - { - this(pattern, Locale.getDefault()); - } - - public ExtendedDateFormat(String pattern, Locale locale) - { - super(stripNanos(pattern), locale); - - int quoteCount = 0; - for (int i = 0; i < pattern.length(); i++) { - char c = pattern.charAt(i); - if (c == '\'') { - quoteCount++; - for (int k = i + 1; k < pattern.length(); k++) { - if (pattern.charAt(k) == '\'') { - if (k != i + 1) { - quoteCount++; - } - i = k; - break; - } - } - } else if (c == '[') { - nanoStart = i; - nanoOptional = true; - for (int k = i + 1; k < pattern.length(); k++) { - if (pattern.charAt(k) == 'f' || pattern.charAt(k) == 'S') { - nanoLength++; - if (nanoPrefix == null) { - nanoPrefix = pattern.substring(i + 1, k); - } - } - if (pattern.charAt(k) == ']') { - if (nanoPrefix == null){ - break; - } - nanoPostfix = pattern.substring(i + 1 + nanoPrefix.length() + nanoLength, k); - i = k + 1; - break; - } - } - } else if (c == 'f' || c == 'S') { - nanoStart = i - quoteCount; - nanoOptional = false; - for (int k = i + 1; k < pattern.length(); k++) { - if (pattern.charAt(k) != 'f' && pattern.charAt(k) != 'S') { - break; - } - nanoLength++; - } - nanoLength++; - i = i + nanoLength; - } - } - } - - @Override - public StringBuffer format(@NotNull Date date, @NotNull StringBuffer toAppendTo, @NotNull FieldPosition pos) - { - StringBuffer result = super.format(date, toAppendTo, pos); - if (nanoStart >= 0) { - long nanos = 0; - if (date instanceof Timestamp) { - nanos = ((Timestamp) date).getNanos(); - } - if (!nanoOptional || nanos > 0) { - StringBuilder nanosRes = new StringBuilder(nanoLength); - // Append nanos value in the end - if (nanoPrefix != null) { - nanosRes.append(nanoPrefix); - } - String nanoStr = String.valueOf(nanos); - - // nanoStr must be a string of exactly 9 chars in length. Pad with leading "0" if not - int nbZeroesToPad = 9 - nanoStr.length(); - if (nbZeroesToPad > 0) { - nanoStr = NINE_ZEROES.substring(0, nbZeroesToPad) + nanoStr; - } - - if (nanoLength < nanoStr.length()) { - // Truncate nanos string to fit in the pattern - nanoStr = nanoStr.substring(0, nanoLength); - } else { - // Pad with 0s - for (int i = 0; i < nanoLength - nanoStr.length(); i++) { - nanosRes.append("0"); - } - } - nanosRes.append(nanoStr); - if (nanoPostfix != null) { - nanosRes.append(nanoPostfix); - } - result.insert(nanoStart, nanosRes.toString()); - } - } - return result; - } - - @Override - public Date parse(@NotNull String text, @NotNull ParsePosition pos) - { - Date date = super.parse(text, pos); - if (date == null) { - return null; - } - int index = pos.getIndex(); - if (index < text.length() && nanoStart > 0) { - long nanos = 0; - if (nanoPrefix != null) { - index += nanoPrefix.length(); - } - for (int i = 0; i < nanoLength; i++) { - int digitPos = index + i; - if (digitPos == text.length()) { - break; - } - char c = text.charAt(digitPos); - if (!Character.isDigit(c)) { - pos.setErrorIndex(index); - pos.setIndex(index); - //throw new ParseException("Invalid nanosecond character at pos " + digitPos + ": " + c, index); - return null; - } - long digit = ((int)c - (int)'0'); - for (int k = MAX_NANO_LENGTH - i; k > 0; k--) { - digit *= 10; - } - nanos += digit; - } - if (nanos > 0) { - Timestamp ts = new Timestamp(date.getTime()); - ts.setNanos((int)nanos); - return ts; - } - } - return date; - } - - private static String stripNanos(String pattern) - { - for (int i = 0; i < pattern.length(); i++) { - char c = pattern.charAt(i); - if (c == '\'') { - for (int k = i + 1; k < pattern.length(); k++) { - if (pattern.charAt(k) == '\'') { - i = k; - break; - } - } - } else if (c == '[') { - for (int k = i + 1; k < pattern.length(); k++) { - if (pattern.charAt(k) == ']') { - return pattern.substring(0, i) + pattern.substring(k + 1); - } - } - } else if (c == 'f' || c == 'S') { - for (int k = i + 1; k < pattern.length(); k++) { - if (pattern.charAt(k) != 'f' && pattern.charAt(k) != 'S') { - return pattern.substring(0, i) + pattern.substring(k); - } - } - return pattern.substring(0, i); - } - } - return pattern; - } - - public static void main(String[] args) - { - test("'TIMESTAMP '''yyyy-MM-dd HH:mm:ss.ffffff''"); - test("yyyy-MM-dd Z hh:mm:ss[.fffffffff]"); - test("yyyy-MM-dd Z hh:mm:ss.fffffffff"); - test("yyyy-MM-dd Z hh:mm:ss"); - test("yyyy-MM-dd Z hh:mm:ss[.fffffffff nanos]"); - test("yyyy-MM-dd Z hh:mm:ss[.ffffff micros]"); - test("yyyy-MM-dd Z hh:mm:ss.ffffff"); - test("yyyy-MM-dd Z hh:mm:ss.f"); // 1/10 secs = 'S' - } - - private static void test(String pattern) - { - ExtendedDateFormat edf = new ExtendedDateFormat(pattern); - Timestamp date = new Timestamp(System.currentTimeMillis()); - System.out.println(edf.format(date)); - date.setNanos(0); - System.out.println(edf.format(date)); - } - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/SAXListener.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/SAXListener.java deleted file mode 100644 index b3a134cb83c2..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/SAXListener.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.utils.xml; - -import org.xml.sax.Attributes; - -/** - SAX document listener -*/ -public interface SAXListener { - - void saxStartElement( - SAXReader reader, - String namespaceURI, - String localName, - org.xml.sax.Attributes atts) - throws XMLException; - - void saxText( - SAXReader reader, - String data) - throws XMLException; - - void saxEndElement( - SAXReader reader, - String namespaceURI, - String localName) - throws XMLException; - - - /** - * Empty listener supposed to skip element subtrees - */ - class BaseListener implements SAXListener { - - @Override - public void saxStartElement(SAXReader reader, String namespaceURI, String localName, Attributes atts) throws XMLException { - } - - @Override - public void saxText(SAXReader reader, String data) throws XMLException { - } - - @Override - public void saxEndElement(SAXReader reader, String namespaceURI, String localName) throws XMLException { - } - } - SAXListener EMPTY_LISTENER = new BaseListener(); - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/SAXReader.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/SAXReader.java deleted file mode 100644 index 831b4a9a5009..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/SAXReader.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jkiss.utils.xml; - -import org.xml.sax.*; - -import javax.xml.parsers.FactoryConfigurationError; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * SAX document reader - */ -public final class SAXReader implements ContentHandler, EntityResolver, DTDHandler { - - public static final int DEFAULT_POOL_SIZE = 10; - - private static javax.xml.parsers.SAXParserFactory saxParserFactory = null; - private static List parsersPool = new ArrayList<>(); - - private org.xml.sax.InputSource inputSource; - private Locator locator; - - private Map attributes = new HashMap<>(); - private List elementLayers = new ArrayList<>(); - private SAXListener curListener; - private StringBuilder textValue = new StringBuilder(); - private int depth = 0; - private boolean handleWhiteSpaces = false; - - /** - * Private constructor. - * Initialize parser. - */ - private SAXReader() { - } - - /** - * Standard constructor. - * Initialize parser and prepare input stream for reading. - */ - public SAXReader(InputStream stream) { - this(); - inputSource = new org.xml.sax.InputSource(stream); - } - - /** - * Standard constructor. - * Initialize parser and prepare input stream for reading. - */ - public SAXReader(Reader reader) { - this(); - inputSource = new org.xml.sax.InputSource(reader); - } - - public boolean isHandleWhiteSpaces() { - return handleWhiteSpaces; - } - - public void setHandleWhiteSpaces( - boolean flag) { - handleWhiteSpaces = flag; - } - - public Locator getLocator() { - return locator; - } - - /** - * Parse input stream and handle XML tags. - */ - public void parse(SAXListener listener) throws IOException, XMLException { - // Initialize SAX parser - Parser parser = acquireParser(); - - // Get reader and parse using SAX2 API - try { - XMLReader saxReader = parser.getSAXParser().getXMLReader(); - saxReader.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true ); - saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - - saxReader.setErrorHandler(new ParseErrorHandler()); - saxReader.setContentHandler(this); - saxReader.setEntityResolver(this); - saxReader.setDTDHandler(this); - - curListener = listener; - - elementLayers.add(listener); - - saxReader.parse(inputSource); - } catch (SAXParseException toCatch) { - throw new XMLException( - "Document parse error (line " + toCatch.getLineNumber() + ", pos " + toCatch.getColumnNumber() + ")", - toCatch); - } catch (SAXException toCatch) { - throw new XMLException( - "Document reading SAX exception", - XMLUtils.adaptSAXException(toCatch)); - } finally { - parser.close(); - } - } - - public synchronized static Parser acquireParser() throws XMLException { - try { - if (saxParserFactory == null) { - try { - saxParserFactory = javax.xml.parsers.SAXParserFactory.newInstance(); - saxParserFactory.setNamespaceAware(true); - saxParserFactory.setValidating(false); - } catch (FactoryConfigurationError toCatch) { - throw new XMLException( - "SAX factory configuration error", - toCatch); - } - } - - for (int i = 0; i < parsersPool.size(); i++) { - Parser parser = parsersPool.get(i); - if (parser != null) { - if (!parser.isAcquired()) { - parser.acquire(); - return parser; - } - } else { - parsersPool.remove(i); - parser = new Parser(saxParserFactory.newSAXParser(), true); - parsersPool.add(parser); - return parser; - } - } - if (parsersPool.size() == DEFAULT_POOL_SIZE) { - throw new XMLException( - "Maximum SAX Parsers Number Exceeded (" + DEFAULT_POOL_SIZE + ")"); - } - Parser parser = new Parser(saxParserFactory.newSAXParser(), true); - parsersPool.add(parser); - return parser; - } catch (ParserConfigurationException toCatch) { - throw new XMLException( - "SAX Parser Configuration error", - toCatch); - } catch (SAXException toCatch) { - throw new XMLException( - "SAX Parser error", - toCatch); - } - } - - /** - * Closes parser and frees all resources. - */ - public void close() { - if (elementLayers != null) { - elementLayers.clear(); - elementLayers = null; - } - inputSource = null; - curListener = null; - } - - /** - * Set listener for next event. - */ - public void setListener( - SAXListener listener) { - curListener = listener; - } - - public boolean hasAttribute( - String name) { - return attributes.get(name) != null; - } - - public Object getAttribute( - String name) { - return attributes.get(name); - } - - public void setAttribute( - String name, - Object value) { - attributes.put(name, value); - } - - public Object removeAttribute( - String name) { - return attributes.remove(name); - } - - private void handleText() - throws SAXException { - curListener = elementLayers.get(elementLayers.size() - 1); - try { - String value = textValue.toString(); - - curListener.saxText(this, value); - } catch (Exception toCatch) { - throw new SAXException(toCatch); - } finally { - textValue.setLength(0); - } - } - - /////////////////////////////////////////////////////////////// - // SAX Context Handler overrides - /////////////////////////////////////////////////////////////// - - @Override - public void startDocument() { - // just do-nothing - } - - @Override - public void endDocument() { - this.close(); - } - - @Override - public void startElement( - String namespaceURI, - String localName, - String qName, - org.xml.sax.Attributes attributes) - throws SAXException { - if (depth++ > 0) { - this.handleText(); - } - - curListener = elementLayers.get(elementLayers.size() - 1); - - try { - curListener.saxStartElement(this, namespaceURI, localName, attributes); - } catch (XMLException toCatch) { - throw new SAXException(toCatch); - } - - elementLayers.add(curListener); - } - - @Override - public void endElement( - String namespaceURI, - String localName, - String qName) - throws SAXException { - this.handleText(); - - elementLayers.remove(elementLayers.size() - 1); - - curListener = elementLayers.get(elementLayers.size() - 1); - try { - curListener.saxEndElement(this, namespaceURI, localName); - } catch (XMLException toCatch) { - throw new SAXException(toCatch); - } - depth--; - } - - @Override - public void startPrefixMapping(String prefix, String uri) { - // just do-nothing - } - - @Override - public void endPrefixMapping(String prefix) { - // just do-nothing - } - - @Override - public void characters(char[] ch, int start, int length) { - textValue.append(ch, start, length); - } - - @Override - public void ignorableWhitespace(char[] ch, int start, int length) { - if (handleWhiteSpaces) { - textValue.append(ch, start, length); - } - } - - @Override - public void processingInstruction(String target, String data) { - // just do-nothing - } - - @Override - public void setDocumentLocator(Locator locator) { - this.locator = locator; - } - - @Override - public void skippedEntity(String name) { - // just do-nothing - } - - @Override - public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { - // Return empty stream - we don't need entities by default - return new InputSource(new StringReader("")); - } - - @Override - public void notationDecl(String name, String publicId, String systemId) throws SAXException { - // do nothing - } - - @Override - public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException { - // do nothing - } - - static public class Parser { - private javax.xml.parsers.SAXParser saxParser; - private boolean isAcquired; - - public Parser(javax.xml.parsers.SAXParser saxParser, boolean isAcquired) { - this.saxParser = saxParser; - this.isAcquired = isAcquired; - } - - public void setSAXParser(javax.xml.parsers.SAXParser saxParser) { - this.saxParser = saxParser; - } - - public void acquire() { - isAcquired = true; - } - - public void close() { - isAcquired = false; - } - - public javax.xml.parsers.SAXParser getSAXParser() { - return saxParser; - } - - public boolean isAcquired() { - return isAcquired; - } - } - - static class ParseErrorHandler implements org.xml.sax.ErrorHandler { - - @Override - public void error(SAXParseException exception) { - - } - - @Override - public void fatalError(SAXParseException exception) { - - } - - @Override - public void warning(SAXParseException exception) { - - } - - } - - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLBuilder.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLBuilder.java deleted file mode 100644 index fedec3aec6d3..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLBuilder.java +++ /dev/null @@ -1,634 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.utils.xml; - -import org.jkiss.utils.Base64; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Stream oriented XML document builder. - */ -public class XMLBuilder -{ - - public final class Element implements AutoCloseable - { - - private Element parent; - private String name; - private Map nsStack = null; - private int level; - - Element( - Element parent, - String name) - { - this.init(parent, name); - } - - void init( - Element parent, - String name) - { - this.parent = parent; - this.name = name; - this.nsStack = null; - this.level = parent == null ? 0 : parent.level + 1; - } - - public String getName() - { - return name; - } - - public int getLevel() - { - return level; - } - - public void addNamespace(String nsURI, String nsPrefix) - { - if (nsStack == null) { - nsStack = new HashMap<>(); - } - nsStack.put(nsURI, nsPrefix); - } - - public String getNamespacePrefix(String nsURI) - { - if (nsURI.equals(XMLConstants.NS_XML)) { - return XMLConstants.PREFIX_XML; - } - String prefix = (nsStack == null ? null : nsStack.get(nsURI)); - return prefix != null ? - prefix : - (parent != null ? parent.getNamespacePrefix(nsURI) : null); - } - - @Override - public void close() throws IOException { - XMLBuilder.this.endElement(); - } - } - - // At the beginning and after tag closing - private static final int STATE_NOTHING = 0; - // After tag opening - private static final int STATE_ELEM_OPENED = 1; - // After text added - private static final int STATE_TEXT_ADDED = 2; - - private static final int IO_BUFFER_SIZE = 8192; - - private java.io.Writer writer; - - private int state = STATE_NOTHING; - - private Element element = null; - private boolean butify = false; - - private List trashElements = new java.util.ArrayList<>(); - - public XMLBuilder( - java.io.OutputStream stream, - String documentEncoding) - throws java.io.IOException - { - this(stream, documentEncoding, true); - } - - public XMLBuilder( - java.io.OutputStream stream, - String documentEncoding, - boolean printHeader) - throws java.io.IOException - { - if (documentEncoding == null) { - this.init(new java.io.OutputStreamWriter(stream), null, printHeader); - } else { - this.init( - new java.io.OutputStreamWriter(stream, documentEncoding), - documentEncoding, - printHeader); - } - } - - public XMLBuilder( - java.io.Writer writer, - String documentEncoding) - throws java.io.IOException - { - this(writer, documentEncoding, true); - } - - public XMLBuilder( - java.io.Writer writer, - String documentEncoding, - boolean printHeader) - throws java.io.IOException - { - this.init(writer, documentEncoding, printHeader); - } - - private Element createElement( - Element parent, - String name) - { - if (trashElements.isEmpty()) { - return new Element(parent, name); - } else { - Element element = trashElements.remove(trashElements.size() - 1); - element.init(parent, name); - return element; - } - } - - private void deleteElement( - Element element) - { - trashElements.add(element); - } - - private void init( - java.io.Writer writer, - String documentEncoding, - boolean printHeader) - throws java.io.IOException - { - this.writer = new java.io.BufferedWriter(writer, IO_BUFFER_SIZE); - - if (printHeader) { - if (documentEncoding != null) { - this.writer.write(XMLConstants.XML_HEADER(documentEncoding)); - } else { - this.writer.write(XMLConstants.XML_HEADER()); - } - } - } - - public boolean isButify() - { - return butify; - } - - public void setButify(boolean butify) - { - this.butify = butify; - } - - public Element startElement( - String elementName) - throws java.io.IOException - { - return this.startElement(null, null, elementName); - } - - public Element startElement( - String nsURI, - String elementName) - throws java.io.IOException - { - return this.startElement(nsURI, null, elementName); - } - - /* - NS prefix will be used in element name if its directly specified - as nsPrefix parameter or if nsURI has been declared above - */ - public Element startElement( - String nsURI, - String nsPrefix, - String elementName) - throws java.io.IOException - { - switch (state) { - case STATE_ELEM_OPENED: - writer.write('>'); - case STATE_NOTHING: - if (butify) { - writer.write('\n'); - } - break; - default: - break; - } - if (butify) { - if (element != null) { - for (int i = 0; i <= element.getLevel(); i++) { - writer.write('\t'); - } - } - } - writer.write('<'); - - boolean addNamespace = (nsURI != null); - - // If old nsURI specified - use prefix - if (nsURI != null) { - if (nsPrefix == null && element != null) { - nsPrefix = element.getNamespacePrefix(nsURI); - if (nsPrefix != null) { - // Do not add NS declaration - it was declared somewhere above - addNamespace = false; - } - } - } - - // If we have prefix - use it in tag name - if (nsPrefix != null) { - elementName = nsPrefix + ':' + elementName; - } - - writer.write(elementName); - state = STATE_ELEM_OPENED; - - element = this.createElement(element, elementName); - - if (addNamespace) { - this.addNamespace(nsURI, nsPrefix); - element.addNamespace(nsURI, nsPrefix); - } - - return element; - } - - public XMLBuilder endElement() - throws java.io.IOException, IllegalStateException - { - if (element == null) { - throw new IllegalStateException("Close tag without open"); - } - - switch (state) { - case STATE_ELEM_OPENED: - writer.write("/>"); - break; - case STATE_NOTHING: - if (butify) { - writer.write('\n'); - for (int i = 0; i < element.getLevel(); i++) { - writer.write('\t'); - } - } - case STATE_TEXT_ADDED: - writer.write("'); - default: - break; - } - - this.deleteElement(element); - element = element.parent; - state = STATE_NOTHING; - - return this; - } - - public XMLBuilder addNamespace(String nsURI) - throws java.io.IOException - { - return this.addNamespace(nsURI, null); - } - - public XMLBuilder addNamespace( - String nsURI, - String nsPrefix) - throws java.io.IOException, IllegalStateException - { - if (element == null) { - throw new IllegalStateException("Namespace outside of element"); - } - String attrName = XMLConstants.XMLNS; - if (nsPrefix != null) { - attrName = attrName + ':' + nsPrefix; - element.addNamespace(nsURI, nsPrefix); - } - this.addAttribute(null, attrName, nsURI, true); - - return this; - } - - public XMLBuilder addAttribute( - String attributeName, - String attributeValue) - throws java.io.IOException - { - return this.addAttribute(null, attributeName, attributeValue, true); - } - - public XMLBuilder addAttribute( - String attributeName, - int attributeValue) - throws java.io.IOException - { - return this.addAttribute(null, attributeName, String.valueOf(attributeValue), false); - } - - public XMLBuilder addAttribute( - String attributeName, - long attributeValue) - throws java.io.IOException - { - return this.addAttribute(null, attributeName, String.valueOf(attributeValue), false); - } - - public XMLBuilder addAttribute( - String attributeName, - boolean attributeValue) - throws java.io.IOException - { - return this.addAttribute(null, attributeName, String.valueOf(attributeValue), false); - } - - public XMLBuilder addAttribute( - String attributeName, - float attributeValue) - throws java.io.IOException - { - return this.addAttribute(null, attributeName, String.valueOf(attributeValue), false); - } - - public XMLBuilder addAttribute( - String attributeName, - double attributeValue) - throws java.io.IOException - { - return this.addAttribute(null, attributeName, String.valueOf(attributeValue), false); - } - - public XMLBuilder addAttribute( - String nsURI, - String attributeName, - String attributeValue) - throws java.io.IOException - { - return this.addAttribute(nsURI, attributeName, attributeValue, true); - } - - private XMLBuilder addAttribute( - String nsURI, - String attributeName, - String attributeValue, - boolean escape) - throws java.io.IOException, IllegalStateException - { - switch (state) { - case STATE_ELEM_OPENED: { - if (nsURI != null) { - String nsPrefix = element.getNamespacePrefix(nsURI); - if (nsPrefix == null) { - throw new IllegalStateException( - "Unknown attribute '" + attributeName + "' namespace URI '" + nsURI + "' in element '" + element.getName() + "'"); - } - attributeName = nsPrefix + ':' + attributeName; - } - writer.write(' '); - writer.write(attributeName); - writer.write("=\""); - writer.write(escape ? XMLUtils.escapeXml(attributeValue) : attributeValue); - writer.write('"'); - break; - } - case STATE_TEXT_ADDED: - case STATE_NOTHING: - throw new IllegalStateException( - "Attribute ouside of element"); - default: - break; - } - - return this; - } - - public XMLBuilder addText( - CharSequence textValue) - throws java.io.IOException - { - return addText(textValue, true); - } - - public XMLBuilder addText( - CharSequence textValue, - boolean escape) - throws java.io.IOException - { - switch (state) { - case STATE_ELEM_OPENED: - writer.write('>'); - case STATE_TEXT_ADDED: - case STATE_NOTHING: - break; - default: - break; - } - this.writeText(textValue, escape); - - state = STATE_TEXT_ADDED; - - return this; - } - - /** - * Adds entire content of specified reader as text - * - * @param reader text reader - * @return self reference - * @throws java.io.IOException on IO error - */ - public XMLBuilder addText( - java.io.Reader reader) - throws java.io.IOException - { - switch (state) { - case STATE_ELEM_OPENED: - writer.write('>'); - case STATE_TEXT_ADDED: - case STATE_NOTHING: - break; - default: - break; - } - - writer.write(""); - - state = STATE_TEXT_ADDED; - - return this; - } - - public XMLBuilder addTextData( - String text) - throws java.io.IOException - { - switch (state) { - case STATE_ELEM_OPENED: - writer.write('>'); - case STATE_TEXT_ADDED: - case STATE_NOTHING: - break; - default: - break; - } - - writer.write(""); - - state = STATE_TEXT_ADDED; - - return this; - } - - /** - * Adds content of specified stream as Base64 encoded text - * - * @param stream Input content stream - * @param length Content length (this parameter must be correctly specified) - * @return self reference - * @throws java.io.IOException on IO error - */ - public XMLBuilder addBinary( - java.io.InputStream stream, - int length) - throws java.io.IOException - { - switch (state) { - case STATE_ELEM_OPENED: - writer.write('>'); - case STATE_TEXT_ADDED: - case STATE_NOTHING: - break; - default: - break; - } - - Base64.encode(stream, length, writer); - state = STATE_TEXT_ADDED; - - return this; - } - - public XMLBuilder addBinary( - byte[] buffer) - throws java.io.IOException - { - switch (state) { - case STATE_ELEM_OPENED: - writer.write('>'); - case STATE_TEXT_ADDED: - case STATE_NOTHING: - break; - default: - break; - } - - Base64.encode(buffer, 0, buffer.length, writer); - state = STATE_TEXT_ADDED; - - return this; - } - - /** - * Adds character content as is without any escaping or validation - * @param textValue content - * @return self reference - * @throws java.io.IOException - */ - public XMLBuilder addContent( - CharSequence textValue) - throws java.io.IOException - { - writer.write(textValue.toString()); - return this; - } - - public XMLBuilder addComment( - String commentValue) - throws java.io.IOException - { - switch (state) { - case STATE_ELEM_OPENED: - writer.write('>'); - case STATE_NOTHING: - if (butify) { - writer.write('\n'); - } - break; - default: - break; - } - writer.write(""); - if (butify) { - writer.write('\n'); - } - state = STATE_TEXT_ADDED; - - return this; - } - - public XMLBuilder addElement( - String elementName, - String elementValue) - throws java.io.IOException - { - this.startElement(elementName); - this.addText(elementValue); - this.endElement(); - return this; - } - - public XMLBuilder addElementText( - String elementName, - String elementValue) - throws java.io.IOException - { - this.startElement(elementName); - this.addTextData(elementValue); - this.endElement(); - return this; - } - - public XMLBuilder flush() - throws java.io.IOException - { - writer.flush(); - return this; - } - - private XMLBuilder writeText(CharSequence textValue, boolean escape) - throws java.io.IOException - { - if (textValue != null) { - writer.write(escape ? XMLUtils.escapeXml(textValue) : textValue.toString()); - } - return this; - } - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLConstants.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLConstants.java deleted file mode 100644 index b5ffebc211af..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLConstants.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.utils.xml; - -/** - XML Constants -*/ -public class XMLConstants { - - public static final String XMLNS = "xmlns"; - public static final String NS_XML = "http://www.w3.org/TR/REC-xml"; - public static final String PREFIX_XML = "xml"; - public static final String ATTR_LANG = "lang"; - - public static String XML_HEADER() - { - return ""; - } - - public static String XML_HEADER(String encoding) - { - return ""; - } - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLException.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLException.java deleted file mode 100644 index 4a7fd1909967..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.utils.xml; - -/** - * XMLException - */ -public class XMLException extends Exception -{ - public XMLException(String message) - { - super(message); - } - - public XMLException(String message, Throwable cause) - { - super(message, cause); - } - -} diff --git a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLUtils.java b/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLUtils.java deleted file mode 100644 index 6aa88c4bf15b..000000000000 --- a/bundles/org.jkiss.utils/src/org/jkiss/utils/xml/XMLUtils.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jkiss.utils.xml; - -import org.jkiss.code.NotNull; -import org.jkiss.code.Nullable; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.xml.sax.InputSource; - -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * Common XML utils - */ -public class XMLUtils { - - public static Document parseDocument(String fileName) - throws XMLException { - return parseDocument(new java.io.File(fileName)); - } - - public static Document parseDocument(java.io.File file) throws XMLException { - try (InputStream is = new FileInputStream(file)) { - return parseDocument(new InputSource(is)); - } catch (IOException e) { - throw new XMLException("Error opening file '" + file + "'", e); - } - } - - public static Document parseDocument(java.io.InputStream is) throws XMLException { - return parseDocument(new InputSource(is)); - } - - public static Document parseDocument(java.io.Reader is) throws XMLException { - return parseDocument(new InputSource(is)); - } - - public static Document parseDocument(InputSource source) throws XMLException { - try { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - DocumentBuilder xmlBuilder = dbf.newDocumentBuilder(); - return xmlBuilder.parse(source); - } catch (Exception er) { - throw new XMLException("Error parsing XML document", er); - } - } - - public static Document createDocument() - throws XMLException { - try { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder xmlBuilder = dbf.newDocumentBuilder(); - return xmlBuilder.newDocument(); - } catch (Exception er) { - throw new XMLException("Error creating XML document", er); - } - } - - public static Element getChildElement(Element element, @NotNull String childName) { - if (element == null) { - return null; - } - for (Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) { - if (node.getNodeType() == Node.ELEMENT_NODE && - ((Element) node).getTagName().equals(childName)) { - return (Element) node; - } - } - return null; - } - - @Nullable - public static String getChildElementBody(Element element, @NotNull String childName) { - if (element == null) { - return null; - } - for (Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) { - if (node.getNodeType() == Node.ELEMENT_NODE && - ((Element) node).getTagName().equals(childName)) { - return getElementBody((Element) node); - } - } - return null; - } - - @Nullable - public static String getElementBody(@NotNull Element element) { - return element.getTextContent(); - } - - // Get list of all child elements of specified node - @NotNull - public static List getChildElementList( - Element parent, - String nodeName) { - List list = new ArrayList<>(); - if (parent != null) { - for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) { - if (node.getNodeType() == Node.ELEMENT_NODE && - nodeName.equals(node.getNodeName())) { - list.add((Element) node); - } - } - } - return list; - } - - // Get list of all child elements of specified node - @NotNull - public static Collection getChildElementListNS( - Element parent, - String nsURI) { - List list = new ArrayList<>(); - if (parent != null) { - for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) { - if (node.getNodeType() == Node.ELEMENT_NODE && - node.getNamespaceURI().equals(nsURI)) { - list.add((Element) node); - } - } - } - return list; - } - - // Get list of all child elements of specified node - public static Collection getChildElementListNS( - Element parent, - String nodeName, - String nsURI) { - List list = new ArrayList<>(); - for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) { - if (node.getNodeType() == Node.ELEMENT_NODE && - node.getLocalName().equals(nodeName) && - node.getNamespaceURI().equals(nsURI)) { - list.add((Element) node); - } - } - return list; - } - - // Get list of all child elements of specified node - @NotNull - public static Collection getChildElementList( - Element parent, - String[] nodeNameList) { - List list = new ArrayList<>(); - for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) { - if (node.getNodeType() == Node.ELEMENT_NODE) { - for (String s : nodeNameList) { - if (node.getNodeName().equals(s)) { - list.add((Element) node); - } - } - } - } - return list; - } - - // Find one child element with specified name - @Nullable - public static Element findChildElement( - Element parent) { - for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) { - if (node.getNodeType() == Node.ELEMENT_NODE) { - return (Element) node; - } - } - return null; - } - - public static Object escapeXml(Object obj) { - if (obj == null) { - return null; - } else if (obj instanceof CharSequence) { - return escapeXml((CharSequence) obj); - } else { - return obj; - } - } - - public static String escapeXml(CharSequence str) { - if (str == null) { - return null; - } - StringBuilder res = null; - int strLength = str.length(); - for (int i = 0; i < strLength; i++) { - char c = str.charAt(i); - String repl = encodeXMLChar(c); - if (repl == null) { - if (res != null) { - res.append(c); - } - } else { - if (res == null) { - res = new StringBuilder(str.length() + 5); - for (int k = 0; k < i; k++) { - res.append(str.charAt(k)); - } - } - res.append(repl); - } - } - return res == null ? str.toString() : res.toString(); - } - - public static boolean isValidXMLChar(char c) { - return (c >= 32 || c == '\n' || c == '\r' || c == '\t'); - } - - /** - * Encodes a char to XML-valid form replacing &,',",<,> with special XML encoding. - * - * @param ch char to convert - * @return XML-encoded text - */ - public static String encodeXMLChar(char ch) { - return switch (ch) { - case '&' -> "&"; - case '\"' -> """; - case '\'' -> "'"; - case '<' -> "<"; - case '>' -> ">"; - default -> null; - }; - } - - public static XMLException adaptSAXException(Exception toCatch) { - if (toCatch instanceof XMLException) { - return (XMLException) toCatch; - } else if (toCatch instanceof org.xml.sax.SAXException) { - String message = toCatch.getMessage(); - Exception embedded = ((org.xml.sax.SAXException) toCatch).getException(); - if (embedded != null && embedded.getMessage() != null && embedded.getMessage().equals(message)) { - // Just SAX wrapper - skip it - return adaptSAXException(embedded); - } else { - return new XMLException( - message, - embedded != null ? adaptSAXException(embedded) : null); - } - } else { - return new XMLException(toCatch.getMessage(), toCatch); - } - } - - public static Collection getChildElementList(Element element) { - List children = new ArrayList<>(); - if (element != null) { - for (Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) { - if (node.getNodeType() == Node.ELEMENT_NODE) { - children.add((Element) node); - } - } - } - return children; - } -} diff --git a/bundles/org.jkiss.wmi/META-INF/MANIFEST.MF b/bundles/org.jkiss.wmi/META-INF/MANIFEST.MF deleted file mode 100644 index ab5ab31700b5..000000000000 --- a/bundles/org.jkiss.wmi/META-INF/MANIFEST.MF +++ /dev/null @@ -1,11 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: WMI native interface -Bundle-SymbolicName: org.jkiss.wmi -Bundle-Version: 2.0.217.qualifier -Bundle-Release-Date: 20240205 -Bundle-RequiredExecutionEnvironment: JavaSE-17 -Bundle-Vendor: DBeaver Corp -Bundle-ActivationPolicy: lazy -Export-Package: org.jkiss.wmi.service -Automatic-Module-Name: org.jkiss.wmi diff --git a/bundles/org.jkiss.wmi/build.properties b/bundles/org.jkiss.wmi/build.properties deleted file mode 100644 index 4a21684e6007..000000000000 --- a/bundles/org.jkiss.wmi/build.properties +++ /dev/null @@ -1,5 +0,0 @@ -source.. = src/java -output.. = target/classes/ -bin.includes = META-INF/,\ - .,\ - native/ diff --git a/bundles/org.jkiss.wmi/copy_contrib.cmd b/bundles/org.jkiss.wmi/copy_contrib.cmd deleted file mode 100644 index e12c14486d12..000000000000 --- a/bundles/org.jkiss.wmi/copy_contrib.cmd +++ /dev/null @@ -1,2 +0,0 @@ -copy .\lib\jkiss_wmi_x86.dll ..\..\contrib\drivers\wmi\x86\jkiss_wmi.dll -copy .\lib\jkiss_wmi_x64.dll ..\..\contrib\drivers\wmi\x64\jkiss_wmi.dll \ No newline at end of file diff --git a/bundles/org.jkiss.wmi/native/x86/jkiss_wmi.dll b/bundles/org.jkiss.wmi/native/x86/jkiss_wmi.dll deleted file mode 100644 index 44ef5b99bc06682ce1e6af07e9bae4a080dd517f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 159744 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

?G&*Q=Md^G~}r5 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 a)<9STVGV>e5Y|9g17Qt>HSm9!2L2bWcfSMx diff --git a/bundles/org.jkiss.wmi/pom.xml b/bundles/org.jkiss.wmi/pom.xml deleted file mode 100644 index 059aaf840cb9..000000000000 --- a/bundles/org.jkiss.wmi/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - org.jkiss.dbeaver - bundles - 1.0.0-SNAPSHOT - ../ - - org.jkiss.wmi - 2.0.217-SNAPSHOT - eclipse-plugin - - - ${project.basedir}/src/java - - - diff --git a/bundles/pom.xml b/bundles/pom.xml deleted file mode 100644 index f29f2c9fddaf..000000000000 --- a/bundles/pom.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - 4.0.0 - - org.jkiss.dbeaver - dbeaver - 1.0.0-SNAPSHOT - ../ - - bundles - pom - - - org.jkiss.utils - org.jkiss.wmi - - - diff --git a/features/org.jkiss.dbeaver.db.feature/feature.xml b/features/org.jkiss.dbeaver.db.feature/feature.xml index e0b2b97542b5..52541584cf61 100644 --- a/features/org.jkiss.dbeaver.db.feature/feature.xml +++ b/features/org.jkiss.dbeaver.db.feature/feature.xml @@ -51,7 +51,6 @@ - diff --git a/plugins/org.jkiss.dbeaver.ext.wmi/META-INF/MANIFEST.MF b/plugins/org.jkiss.dbeaver.ext.wmi/META-INF/MANIFEST.MF index 44d6f016fb23..b8164748ed17 100644 --- a/plugins/org.jkiss.dbeaver.ext.wmi/META-INF/MANIFEST.MF +++ b/plugins/org.jkiss.dbeaver.ext.wmi/META-INF/MANIFEST.MF @@ -12,8 +12,7 @@ Require-Bundle: org.eclipse.ui, org.eclipse.jface.text, org.jkiss.dbeaver.core, org.jkiss.dbeaver.model, - org.eclipse.ui.workbench.texteditor, - org.jkiss.wmi;visibility:=reexport + org.eclipse.ui.workbench.texteditor Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-Vendor: DBeaver Corp diff --git a/plugins/org.jkiss.dbeaver.ext.wmi/build.properties b/plugins/org.jkiss.dbeaver.ext.wmi/build.properties index 13a8aa73a617..6b83020b11ae 100644 --- a/plugins/org.jkiss.dbeaver.ext.wmi/build.properties +++ b/plugins/org.jkiss.dbeaver.ext.wmi/build.properties @@ -1,7 +1,8 @@ source.. = src/ output.. = target/classes/ bin.includes = .,\ - META-INF/,\ - OSGI-INF/,\ - icons/,\ - plugin.xml + META-INF/,\ + OSGI-INF/,\ + icons/,\ + native/,\ + plugin.xml diff --git a/bundles/org.jkiss.wmi/native/x64/jkiss_wmi.dll b/plugins/org.jkiss.dbeaver.ext.wmi/native/x64/jkiss_wmi.dll similarity index 100% rename from bundles/org.jkiss.wmi/native/x64/jkiss_wmi.dll rename to plugins/org.jkiss.dbeaver.ext.wmi/native/x64/jkiss_wmi.dll diff --git a/bundles/org.jkiss.wmi/src/native/JNIMetaData.cpp b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/JNIMetaData.cpp similarity index 100% rename from bundles/org.jkiss.wmi/src/native/JNIMetaData.cpp rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/JNIMetaData.cpp diff --git a/bundles/org.jkiss.wmi/src/native/JNIMetaData.h b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/JNIMetaData.h similarity index 100% rename from bundles/org.jkiss.wmi/src/native/JNIMetaData.h rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/JNIMetaData.h diff --git a/bundles/org.jkiss.wmi/src/native/WMIObject.cpp b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObject.cpp similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIObject.cpp rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObject.cpp diff --git a/bundles/org.jkiss.wmi/src/native/WMIObject.h b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObject.h similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIObject.h rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObject.h diff --git a/bundles/org.jkiss.wmi/src/native/WMIObjectJNI.cpp b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObjectJNI.cpp similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIObjectJNI.cpp rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObjectJNI.cpp diff --git a/bundles/org.jkiss.wmi/src/native/WMIObjectJNI.h b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObjectJNI.h similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIObjectJNI.h rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObjectJNI.h diff --git a/bundles/org.jkiss.wmi/src/native/WMIObjectSink.cpp b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObjectSink.cpp similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIObjectSink.cpp rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObjectSink.cpp diff --git a/bundles/org.jkiss.wmi/src/native/WMIObjectSink.h b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObjectSink.h similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIObjectSink.h rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIObjectSink.h diff --git a/bundles/org.jkiss.wmi/src/native/WMIService.cpp b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIService.cpp similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIService.cpp rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIService.cpp diff --git a/bundles/org.jkiss.wmi/src/native/WMIService.h b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIService.h similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIService.h rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIService.h diff --git a/bundles/org.jkiss.wmi/src/native/WMIService.sln b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIService.sln similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIService.sln rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIService.sln diff --git a/bundles/org.jkiss.wmi/src/native/WMIService.vcproj b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIService.vcproj similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIService.vcproj rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIService.vcproj diff --git a/bundles/org.jkiss.wmi/src/native/WMIServiceJNI.cpp b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIServiceJNI.cpp similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIServiceJNI.cpp rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIServiceJNI.cpp diff --git a/bundles/org.jkiss.wmi/src/native/WMIServiceJNI.h b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIServiceJNI.h similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIServiceJNI.h rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIServiceJNI.h diff --git a/bundles/org.jkiss.wmi/src/native/WMIServiceModule.cpp b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIServiceModule.cpp similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIServiceModule.cpp rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIServiceModule.cpp diff --git a/bundles/org.jkiss.wmi/src/native/WMIUtils.cpp b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIUtils.cpp similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIUtils.cpp rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIUtils.cpp diff --git a/bundles/org.jkiss.wmi/src/native/WMIUtils.h b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIUtils.h similarity index 100% rename from bundles/org.jkiss.wmi/src/native/WMIUtils.h rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/WMIUtils.h diff --git a/bundles/org.jkiss.wmi/src/native/gen_headers.cmd b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/gen_headers.cmd similarity index 100% rename from bundles/org.jkiss.wmi/src/native/gen_headers.cmd rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/gen_headers.cmd diff --git a/bundles/org.jkiss.wmi/src/native/show_sigs.cmd b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/show_sigs.cmd similarity index 100% rename from bundles/org.jkiss.wmi/src/native/show_sigs.cmd rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/show_sigs.cmd diff --git a/bundles/org.jkiss.wmi/src/native/stdafx.cpp b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/stdafx.cpp similarity index 100% rename from bundles/org.jkiss.wmi/src/native/stdafx.cpp rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/stdafx.cpp diff --git a/bundles/org.jkiss.wmi/src/native/stdafx.h b/plugins/org.jkiss.dbeaver.ext.wmi/src-native/stdafx.h similarity index 100% rename from bundles/org.jkiss.wmi/src/native/stdafx.h rename to plugins/org.jkiss.dbeaver.ext.wmi/src-native/stdafx.h diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIConstants.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIConstants.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIConstants.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIConstants.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIDataType.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIDataType.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIDataType.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIDataType.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIException.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIException.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIException.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIException.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObject.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObject.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObject.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObject.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObjectAttribute.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObjectAttribute.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObjectAttribute.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObjectAttribute.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObjectElement.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObjectElement.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObjectElement.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObjectElement.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObjectMethod.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObjectMethod.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObjectMethod.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObjectMethod.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObjectSink.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObjectSink.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObjectSink.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObjectSink.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObjectSinkStatus.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObjectSinkStatus.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIObjectSinkStatus.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIObjectSinkStatus.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIQualifiedObject.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIQualifiedObject.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIQualifiedObject.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIQualifiedObject.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIQualifier.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIQualifier.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIQualifier.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIQualifier.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIService.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIService.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMIService.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMIService.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMISinkStatus.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMISinkStatus.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/service/WMISinkStatus.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/service/WMISinkStatus.java diff --git a/bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/test/TestService.java b/plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/test/TestService.java similarity index 100% rename from bundles/org.jkiss.wmi/src/java/org/jkiss/wmi/test/TestService.java rename to plugins/org.jkiss.dbeaver.ext.wmi/src/org/jkiss/wmi/test/TestService.java diff --git a/pom.xml b/pom.xml index 08ee5b219140..49a16b7bc494 100644 --- a/pom.xml +++ b/pom.xml @@ -3,6 +3,14 @@ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 + + + com.dbeaver.common + com.dbeaver.common.main + 1.0.0-SNAPSHOT + ../dbeaver-common/pom.xml + + org.jkiss.dbeaver dbeaver 1.0.0-SNAPSHOT @@ -11,19 +19,10 @@ 23.3.4 DBeaver - 4.0.4 - 2023-12 - https://download.eclipse.org/releases - UTF-8 - yyyyMMddHHmm - - 17 - 17 ${dbeaver-version} https://p2.dev.dbeaver.com/eclipse-repo/${local-p2-repo.version} - ${eclipse-repo-url}/${eclipse-version}/ https://download.eclipse.org/tools/orbit/downloads/drops/R20230531010532/repository @@ -32,7 +31,6 @@ - bundles plugins features @@ -43,11 +41,6 @@ ${local-p2-repo.url} p2 - - eclipse-p2-repo - ${eclipse-p2-repo.url} - p2 - orbit-repo ${orbit-repo.url} diff --git a/project.deps b/project.deps new file mode 100644 index 000000000000..400e936c9701 --- /dev/null +++ b/project.deps @@ -0,0 +1 @@ +dbeaver-common \ No newline at end of file