diff --git a/org.eclipse.scout.rt.dataobject.test/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractIdCodecTest.java b/org.eclipse.scout.rt.dataobject.test/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractIdCodecTest.java index 9b01792f072..2102ce62f1a 100644 --- a/org.eclipse.scout.rt.dataobject.test/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractIdCodecTest.java +++ b/org.eclipse.scout.rt.dataobject.test/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractIdCodecTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -11,9 +11,12 @@ import static org.junit.Assert.*; +import java.nio.charset.StandardCharsets; import java.util.Date; +import java.util.HashSet; import java.util.Locale; import java.util.Objects; +import java.util.Set; import java.util.UUID; import org.eclipse.scout.rt.dataobject.fixture.FixtureCompositeId; @@ -22,11 +25,17 @@ import org.eclipse.scout.rt.dataobject.fixture.FixtureStringId; import org.eclipse.scout.rt.dataobject.fixture.FixtureUuId; import org.eclipse.scout.rt.dataobject.fixture.FixtureWrapperCompositeId; +import org.eclipse.scout.rt.dataobject.id.IdCodec.IdCodecFlag; import org.eclipse.scout.rt.platform.BEANS; +import org.eclipse.scout.rt.platform.BeanMetaData; +import org.eclipse.scout.rt.platform.IBean; import org.eclipse.scout.rt.platform.exception.PlatformException; import org.eclipse.scout.rt.platform.util.Assertions.AssertionException; import org.eclipse.scout.rt.platform.util.StringUtility; import org.eclipse.scout.rt.platform.util.date.IDateProvider; +import org.eclipse.scout.rt.testing.platform.BeanTestingHelper; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; /** @@ -40,6 +49,18 @@ public abstract class AbstractIdCodecTest { protected static final String TEST_STRING_2 = "bazäöl"; protected static final Date TEST_DATE = new Date(123456789); + protected static IBean s_bean; + + @BeforeClass + public static void beforeClass() { + s_bean = BeanTestingHelper.get().registerBean(new BeanMetaData(P_IdCodec.class).withReplace(true)); + } + + @AfterClass + public static void afterClass() { + BeanTestingHelper.get().unregisterBean(s_bean); + } + /** * @return IdCodec instance used for tests */ @@ -571,13 +592,13 @@ public void testFromQualified_UnsupportedWrappedType() { @Test public void testFromQualifiedLenient_Default() { FixtureUuId id = FixtureUuId.of(TEST_UUID); - IId id2 = getCodec().fromQualifiedLenient("scout.FixtureUuId:" + TEST_UUID); + IId id2 = getCodec().fromQualified("scout.FixtureUuId:" + TEST_UUID, IdCodecFlag.LENIENT); assertEquals(id, id2); } @Test public void testFromQualifiedLenient_UnknownType() { - IId id = getCodec().fromQualifiedLenient("DoesNotExist:" + TEST_UUID); + IId id = getCodec().fromQualified("DoesNotExist:" + TEST_UUID, IdCodecFlag.LENIENT); assertTrue(id instanceof UnknownId); UnknownId uid = (UnknownId) id; assertEquals("DoesNotExist", uid.getIdTypeName()); @@ -589,7 +610,7 @@ public void testFromQualifiedLenient_UnknownType() { @Test public void testFromQualifiedLenient_CompositeUnknownType() { - IId id = getCodec().fromQualifiedLenient("DoesNotExist:abc;123"); + IId id = getCodec().fromQualified("DoesNotExist:abc;123", IdCodecFlag.LENIENT); assertTrue(id instanceof UnknownId); UnknownId uid = (UnknownId) id; assertEquals("DoesNotExist", uid.getIdTypeName()); @@ -601,7 +622,7 @@ public void testFromQualifiedLenient_CompositeUnknownType() { @Test public void testFromQualifiedLenient_WrongFormat() { - IId id = getCodec().fromQualifiedLenient("Does:Not:Exist:" + TEST_UUID); + IId id = getCodec().fromQualified("Does:Not:Exist:" + TEST_UUID, IdCodecFlag.LENIENT); assertTrue(id instanceof UnknownId); UnknownId uid = (UnknownId) id; assertEquals("Does", uid.getIdTypeName()); @@ -613,7 +634,7 @@ public void testFromQualifiedLenient_WrongFormat() { @Test public void testFromQualifiedLenient_NoIdTypeName() { - IId id = getCodec().fromQualifiedLenient("Foo" + TEST_UUID); + IId id = getCodec().fromQualified("Foo" + TEST_UUID, IdCodecFlag.LENIENT); assertTrue(id instanceof UnknownId); UnknownId uid = (UnknownId) id; assertNull(uid.getIdTypeName()); @@ -625,7 +646,7 @@ public void testFromQualifiedLenient_NoIdTypeName() { @Test public void testFromQualifiedLenient_CompositeWrongCardinalityToSmall() { - IId id = getCodec().fromQualifiedLenient("scout.FixtureCompositeId:" + TEST_UUID); + IId id = getCodec().fromQualified("scout.FixtureCompositeId:" + TEST_UUID, IdCodecFlag.LENIENT); assertTrue(id instanceof UnknownId); UnknownId uid = (UnknownId) id; assertEquals("scout.FixtureCompositeId", uid.getIdTypeName()); @@ -637,7 +658,7 @@ public void testFromQualifiedLenient_CompositeWrongCardinalityToSmall() { @Test public void testFromQualifiedLenient_CompositeWrongCardinalityToHigh() { - IId id = getCodec().fromQualifiedLenient("scout.FixtureCompositeId:" + "a;b;c"); + IId id = getCodec().fromQualified("scout.FixtureCompositeId:" + "a;b;c", IdCodecFlag.LENIENT); assertTrue(id instanceof UnknownId); UnknownId uid = (UnknownId) id; assertEquals("scout.FixtureCompositeId", uid.getIdTypeName()); @@ -654,6 +675,66 @@ public void testRegisterTypeMapper() { assertThrows(AssertionException.class, () -> getCodec().registerRawTypeMapper(String.class, x -> x, null)); } + @Test + public void testQualifiedEncryption() { + var ids = new HashSet(); + collectEncryptionIds(ids); + ids.forEach(id -> { + String encrypted = getCodec().toQualified(id, IdCodecFlag.ENCRYPTION); + IId decrypted = getCodec().fromQualified(encrypted, IdCodecFlag.ENCRYPTION); + assertQualifiedEncryption(id, encrypted, decrypted); + + encrypted = getCodec().toQualified(id, Set.of(IdCodecFlag.ENCRYPTION)); + decrypted = getCodec().fromQualified(encrypted, Set.of(IdCodecFlag.ENCRYPTION)); + assertQualifiedEncryption(id, encrypted, decrypted); + }); + } + + @Test + public void testUnqualifiedEncryption() { + var ids = new HashSet(); + collectEncryptionIds(ids); + ids.forEach(id -> { + String encrypted = getCodec().toUnqualified(id, IdCodecFlag.ENCRYPTION); + IId decrypted = getCodec().fromUnqualified(id.getClass(), encrypted, IdCodecFlag.ENCRYPTION); + assertUnqualifiedEncryption(id, encrypted, decrypted); + + encrypted = getCodec().toUnqualified(id, Set.of(IdCodecFlag.ENCRYPTION)); + decrypted = getCodec().fromUnqualified(id.getClass(), encrypted, Set.of(IdCodecFlag.ENCRYPTION)); + assertUnqualifiedEncryption(id, encrypted, decrypted); + }); + } + + protected void assertQualifiedEncryption(IId id, String encrypted, IId decrypted) { + assertEncryption(id, encrypted, decrypted); + } + + protected void assertUnqualifiedEncryption(IId id, String encrypted, IId decrypted) { + assertEncryption(id, encrypted, decrypted); + } + + protected void assertEncryption(IId id, String encrypted, IId decrypted) { + assertEquals(id, decrypted); + } + + protected void collectEncryptionIds(Set ids) { + ids.add(FixtureUuId.of(TEST_UUID)); + ids.add(FixtureStringId.of(TEST_STRING)); + ids.add(FixtureDateId.of(TEST_DATE)); + ids.add(FixtureLocaleId.of(Locale.ITALY)); + ids.add(FixtureCompositeId.of(TEST_STRING, TEST_UUID)); + ids.add(FixtureWrapperCompositeId.of(TEST_STRING, TEST_UUID, TEST_STRING_2)); + ids.add(FixtureCompositeWithNullValuesId.of(null, UUID.fromString("711dc5d6-0a42-4f54-b79c-50110b9e742a"))); + ids.add(FixtureCompositeWithNullStringValuesId.of("foo", "")); + ids.add(FixtureCompositeWithNullStringValuesId.of("", "bar")); + ids.add(FixtureCompositeWithAllTypesId.of("foo", null, null, null, null, null)); + ids.add(FixtureCompositeWithAllTypesId.of(null, TEST_UUID, null, null, null, null)); + ids.add(FixtureCompositeWithAllTypesId.of(null, null, 42L, null, null, null)); + ids.add(FixtureCompositeWithAllTypesId.of(null, null, null, 43, null, null)); + ids.add(FixtureCompositeWithAllTypesId.of(null, null, null, null, TEST_DATE, null)); + ids.add(FixtureCompositeWithAllTypesId.of(null, null, null, null, null, Locale.GERMANY)); + } + @IdTypeName("scout.FixtureDateId") protected static final class FixtureDateId extends AbstractRootId { private static final long serialVersionUID = 1L; @@ -812,4 +893,12 @@ public static FixtureCustomComparableRawDataId of(CustomComparableRawDataType da return new FixtureCustomComparableRawDataId(date); } } + + protected static class P_IdCodec extends IdCodec { + + @Override + protected byte[] getEncryptionPrivateKey() { + return "42".getBytes(StandardCharsets.UTF_8); + } + } } diff --git a/org.eclipse.scout.rt.dataobject.test/src/test/java/org/eclipse/scout/rt/dataobject/id/IdInventoryTest.java b/org.eclipse.scout.rt.dataobject.test/src/test/java/org/eclipse/scout/rt/dataobject/id/IdInventoryTest.java index f96bfc2bae7..a0ffd6e8df3 100644 --- a/org.eclipse.scout.rt.dataobject.test/src/test/java/org/eclipse/scout/rt/dataobject/id/IdInventoryTest.java +++ b/org.eclipse.scout.rt.dataobject.test/src/test/java/org/eclipse/scout/rt/dataobject/id/IdInventoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -59,6 +59,19 @@ public void testRegisterIdTypeName() { assertThrows(AssertionException.class, () -> m_inventory.registerIdTypeName("scout.FixtureMockId", FixtureMockId.class)); } + @Test + public void testIdEncryption() { + assertTrue(m_inventory.isIdEncryption(ExplicitlyOverriddenEncryptedId.class)); + assertTrue(m_inventory.isIdEncryption(ImplicitlyOverriddenEncryptedId.class)); + assertTrue(m_inventory.isIdEncryption(ExplicitlyEncryptedId.class)); + assertTrue(m_inventory.isIdEncryption(ImplicitlyEncryptedId.class)); + + assertFalse(m_inventory.isIdEncryption(ImplicitlyUnencryptedId.class)); + assertFalse(m_inventory.isIdEncryption(ExplicitlyUnencryptedId.class)); + assertFalse(m_inventory.isIdEncryption(ImplicitlyOverriddenUnencryptedId.class)); + assertFalse(m_inventory.isIdEncryption(ExplicitlyOverriddenUnencryptedId.class)); + } + @IgnoreBean protected static final class FixtureMockId extends AbstractStringId { private static final long serialVersionUID = 1L; @@ -67,4 +80,116 @@ private FixtureMockId(String id) { super(id); } } + + @IdEncryption + protected abstract static class AbstractImplicitlyEncryptedId extends AbstractStringId { + private static final long serialVersionUID = 1L; + + protected AbstractImplicitlyEncryptedId(String id) { + super(id); + } + } + + @IgnoreBean + protected static class ImplicitlyEncryptedId extends AbstractImplicitlyEncryptedId { + private static final long serialVersionUID = 1L; + + protected ImplicitlyEncryptedId(String id) { + super(id); + } + } + + @IgnoreBean + @IdEncryption + protected static class ExplicitlyEncryptedId extends AbstractStringId { + private static final long serialVersionUID = 1L; + + protected ExplicitlyEncryptedId(String id) { + super(id); + } + } + + @IdEncryption(false) + protected abstract static class AbstractImplicitlyUnencryptedId extends AbstractStringId { + private static final long serialVersionUID = 1L; + + protected AbstractImplicitlyUnencryptedId(String id) { + super(id); + } + } + + @IgnoreBean + protected static class ImplicitlyUnencryptedId extends AbstractImplicitlyUnencryptedId { + private static final long serialVersionUID = 1L; + + protected ImplicitlyUnencryptedId(String id) { + super(id); + } + } + + @IgnoreBean + @IdEncryption(false) + protected static class ExplicitlyUnencryptedId extends AbstractStringId { + private static final long serialVersionUID = 1L; + + protected ExplicitlyUnencryptedId(String id) { + super(id); + } + } + + @IdEncryption + protected abstract static class AbstractImplicitlyOverriddenEncryptedId extends AbstractImplicitlyUnencryptedId { + private static final long serialVersionUID = 1L; + + protected AbstractImplicitlyOverriddenEncryptedId(String id) { + super(id); + } + } + + @IgnoreBean + protected static class ImplicitlyOverriddenEncryptedId extends AbstractImplicitlyOverriddenEncryptedId { + private static final long serialVersionUID = 1L; + + protected ImplicitlyOverriddenEncryptedId(String id) { + super(id); + } + } + + @IgnoreBean + @IdEncryption + protected static class ExplicitlyOverriddenEncryptedId extends AbstractImplicitlyUnencryptedId { + private static final long serialVersionUID = 1L; + + protected ExplicitlyOverriddenEncryptedId(String id) { + super(id); + } + } + + @IdEncryption(false) + protected abstract static class AbstractImplicitlyOverriddenUnencryptedId extends AbstractImplicitlyEncryptedId { + private static final long serialVersionUID = 1L; + + protected AbstractImplicitlyOverriddenUnencryptedId(String id) { + super(id); + } + } + + @IgnoreBean + protected static class ImplicitlyOverriddenUnencryptedId extends AbstractImplicitlyOverriddenUnencryptedId { + private static final long serialVersionUID = 1L; + + protected ImplicitlyOverriddenUnencryptedId(String id) { + super(id); + } + } + + @IgnoreBean + @IdEncryption(false) + protected static class ExplicitlyOverriddenUnencryptedId extends AbstractImplicitlyEncryptedId { + private static final long serialVersionUID = 1L; + + protected ExplicitlyOverriddenUnencryptedId(String id) { + super(id); + } + } } diff --git a/org.eclipse.scout.rt.dataobject.test/src/test/java/org/eclipse/scout/rt/dataobject/security/AbstractEncryptDecryptSupportTest.java b/org.eclipse.scout.rt.dataobject.test/src/test/java/org/eclipse/scout/rt/dataobject/security/AbstractEncryptDecryptSupportTest.java new file mode 100644 index 00000000000..44d6137c081 --- /dev/null +++ b/org.eclipse.scout.rt.dataobject.test/src/test/java/org/eclipse/scout/rt/dataobject/security/AbstractEncryptDecryptSupportTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.dataobject.security; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Various test methods for {@link AbstractEncryptDecryptSupport} + */ +public class AbstractEncryptDecryptSupportTest { + + protected static class P_Support extends AbstractEncryptDecryptSupport { + + @Override + protected char[] getPassword() { + return new char[]{1, 2, 3, 4}; + } + + @Override + protected byte[] getSalt() { + return new byte[]{0, 0, 0, 0}; + } + } + + protected AbstractEncryptDecryptSupport m_support = new P_Support(); + + @Test + public void testEncrypt() { + assertEquals("+nvT/fa95nTCLVq030bKyyMdzg==", m_support.encrypt("abc")); + assertNull(m_support.encrypt(null)); + assertNull(m_support.encrypt("")); + } + + @Test + public void testEncryptUrlSafe() { + assertEquals("-nvT_fa95nTCLVq030bKyyMdzg==", m_support.encryptUrlSafe("abc")); + assertNull(m_support.encryptUrlSafe(null)); + assertNull(m_support.encryptUrlSafe("")); + } + + @Test + public void testDecrypt() { + assertEquals("abc", m_support.decrypt("+nvT/fa95nTCLVq030bKyyMdzg==")); + assertNull(m_support.decrypt(null)); + assertNull(m_support.decrypt("")); + } + + @Test + public void testDecryptUrlSafe() { + assertEquals("abc", m_support.decryptUrlSafe("-nvT_fa95nTCLVq030bKyyMdzg==")); + assertNull(m_support.decryptUrlSafe(null)); + assertNull(m_support.decryptUrlSafe("")); + } +} diff --git a/org.eclipse.scout.rt.dataobject.test/src/test/java/org/eclipse/scout/rt/dataobject/security/IdCrypterTest.java b/org.eclipse.scout.rt.dataobject.test/src/test/java/org/eclipse/scout/rt/dataobject/security/IdCrypterTest.java new file mode 100644 index 00000000000..77f109e74b9 --- /dev/null +++ b/org.eclipse.scout.rt.dataobject.test/src/test/java/org/eclipse/scout/rt/dataobject/security/IdCrypterTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.dataobject.security; + +import static org.junit.Assert.*; + +import org.eclipse.scout.rt.dataobject.fixture.FixtureUuId; +import org.eclipse.scout.rt.dataobject.id.IId; +import org.eclipse.scout.rt.dataobject.security.IdCrypter.IdEncryptDecryptSupport; +import org.eclipse.scout.rt.platform.BEANS; +import org.eclipse.scout.rt.platform.BeanMetaData; +import org.eclipse.scout.rt.platform.IBean; +import org.eclipse.scout.rt.testing.platform.BeanTestingHelper; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Testcases for {@link IdCrypter}. + */ +public class IdCrypterTest { + + protected static class P_IdEncryptDecryptSupport extends IdEncryptDecryptSupport { + @Override + protected char[] getPassword() { + return new char[]{1, 2, 3, 4}; + } + + @Override + protected byte[] getSalt() { + return new byte[]{0, 0, 0, 0}; + } + } + + protected static final IId TEST_ID = FixtureUuId.of("4876bae4-0d43-43a5-a00f-7eb26dc80036"); + + protected static IBean s_bean; + + protected IdCrypter m_idCrypter = BEANS.get(IdCrypter.class); + + @BeforeClass + public static void beforeClass() { + s_bean = BeanTestingHelper.get().registerBean(new BeanMetaData(P_IdEncryptDecryptSupport.class).withReplace(true)); + } + + @AfterClass + public static void afterClass() { + BeanTestingHelper.get().unregisterBean(s_bean); + } + + @Test + public void testEncrypt() { + assertEquals("6HrfJ0Xq0tLjbz04YTADZzyniDKCzr45IPKUpixsUlPB5qRPmolZNCk9FA-gQJNNEno8HTuSnlnlnh95q9rkJtOrx2EYjA==", m_idCrypter.encrypt(TEST_ID)); + } + + @Test + public void testEncryptNull() { + assertNull(m_idCrypter.encrypt(null)); + } + + @Test + public void testDecrypt() { + assertEquals(TEST_ID, m_idCrypter.decrypt("6HrfJ0Xq0tLjbz04YTADZzyniDKCzr45IPKUpixsUlPB5qRPmolZNCk9FA-gQJNNEno8HTuSnlnlnh95q9rkJtOrx2EYjA==")); + } + + @Test + public void testDecryptNull() { + assertNull(m_idCrypter.decrypt(null)); + } + + @Test + public void testDecryptEmpty() { + assertNull(m_idCrypter.decrypt("")); + } +} diff --git a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/CompositeIdDataObjectVisitorExtension.java b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/CompositeIdDataObjectVisitorExtension.java index 49380d22750..accb8ccb4fa 100644 --- a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/CompositeIdDataObjectVisitorExtension.java +++ b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/CompositeIdDataObjectVisitorExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -20,6 +20,7 @@ import org.eclipse.scout.rt.dataobject.id.IIds; import org.eclipse.scout.rt.dataobject.id.IRootId; import org.eclipse.scout.rt.dataobject.id.IdCodec; +import org.eclipse.scout.rt.dataobject.id.IdCodec.IIdCodecFlag; import org.eclipse.scout.rt.platform.exception.PlatformException; /** @@ -50,7 +51,7 @@ public ICompositeId replaceOrVisit(ICompositeId value, UnaryOperator cha } /** - * Similar as in {@link IdCodec#toUnqualified(IId)}. + * Similar as in {@link IdCodec#toUnqualified(IId, IIdCodecFlag...)}. */ protected void unwrap(IId component, List unwrappedComponents) { if (component instanceof IRootId) { diff --git a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/IIdEncryptionDataObjectMapper.java b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/IIdEncryptionDataObjectMapper.java new file mode 100644 index 00000000000..9a52c364e51 --- /dev/null +++ b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/IIdEncryptionDataObjectMapper.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.dataobject; + +import org.eclipse.scout.rt.dataobject.id.IId; + +/** + * Interface to a data mapper that uses encryption/decryption for all {@link IId} instances. + * + * @see IDataObjectMapper + */ +public interface IIdEncryptionDataObjectMapper extends IDataObjectMapper { +} diff --git a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractUuId.java b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractUuId.java index 8a5f53d3ac3..61504d162fd 100644 --- a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractUuId.java +++ b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/AbstractUuId.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -17,6 +17,7 @@ *

* For details, see {@link IUuId}. */ +@IdEncryption(false) public abstract class AbstractUuId extends AbstractRootId implements IUuId { private static final long serialVersionUID = 1L; diff --git a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdCodec.java b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdCodec.java index b71e2e5c582..06bdd0c986d 100644 --- a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdCodec.java +++ b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -9,21 +9,32 @@ */ package org.eclipse.scout.rt.dataobject.id; -import static org.eclipse.scout.rt.platform.util.Assertions.assertNotNull; +import static org.eclipse.scout.rt.platform.security.SecurityUtility.createMac; +import static org.eclipse.scout.rt.platform.util.Assertions.*; +import static org.eclipse.scout.rt.platform.util.Base64Utility.encodeUrlSafe; +import static org.eclipse.scout.rt.platform.util.CollectionUtility.hashSet; +import static org.eclipse.scout.rt.platform.util.ObjectUtility.isOneOf; +import static org.eclipse.scout.rt.platform.util.StringUtility.isNullOrEmpty; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.Collectors; import jakarta.annotation.PostConstruct; +import org.eclipse.scout.rt.dataobject.security.IdCrypter.IdEncryptDecryptSupport.IdCrypterPasswordProperty; import org.eclipse.scout.rt.platform.ApplicationScoped; +import org.eclipse.scout.rt.platform.config.CONFIG; import org.eclipse.scout.rt.platform.exception.PlatformException; import org.eclipse.scout.rt.platform.util.LazyValue; import org.eclipse.scout.rt.platform.util.StringUtility; @@ -35,6 +46,7 @@ public class IdCodec { protected static final String ID_TYPENAME_DELIMITER = ":"; + protected static final String ENCRYPTION_SIGNATURE_DELIMITER = encodeUrlSafe("###".getBytes(StandardCharsets.UTF_8)); protected final LazyValue m_idFactory = new LazyValue<>(IdFactory.class); protected final LazyValue m_idInventory = new LazyValue<>(IdInventory.class); @@ -42,6 +54,28 @@ public class IdCodec { protected final Map, Function> m_rawTypeFromStringMapper = new HashMap<>(); protected final Map, Function> m_rawTypeToStringMapper = new HashMap<>(); + /** + * Interface for flags used to parametrize conversion between {@link IId} instances and their qualified/unqualified + * representation as {@link String}. This interface is used for all method declarations and allows extension of the + * {@link IdCodecFlag} enum with custom flags. + */ + public interface IIdCodecFlag { + } + + public enum IdCodecFlag implements IIdCodecFlag { + /** + * Does not throw an exception but return {@code null} if the given string does not match the expected format or the + * referenced class is not found. + */ + LENIENT, + /** + * Serialize and deserialize using encryption. This will create a signature using the unqualified serialized + * {@link IId} and add it as a suffix. If this suffix is incorrect an error is thrown during deserialization. + * {@link IId}s can be excluded from using encryption using {@link IdEncryption}. + */ + ENCRYPTION + } + @PostConstruct protected void initialize() { // setup default type mappings between raw type <--> string @@ -53,6 +87,14 @@ protected void initialize() { registerRawTypeMapper(Locale.class, Locale::forLanguageTag, Locale::toLanguageTag); } + public IdFactory idFactory() { + return m_idFactory.get(); + } + + public IdInventory idInventory() { + return m_idInventory.get(); + } + // ---------------- IId to String ---------------- /** @@ -64,21 +106,28 @@ protected void initialize() { * converted to their string representation, separated by ';'. * */ - public String toQualified(IId id) { + public String toQualified(IId id, IIdCodecFlag... flags) { + return toQualified(id, hashSet(flags)); + } + + /** + * @see #toQualified(IId, IIdCodecFlag...) + */ + public String toQualified(IId id, Set flags) { if (id == null) { return null; } - String typeName = m_idInventory.get().getTypeName(id); - if (StringUtility.isNullOrEmpty(typeName)) { + String typeName = idInventory().getTypeName(id); + if (isNullOrEmpty(typeName)) { if (id instanceof UnknownId) { // typeName of unknown id could be null, retain unknown id as-is for later migration - return StringUtility.join(ID_TYPENAME_DELIMITER, ((UnknownId) id).getIdTypeName(), toUnqualified(id)); + return StringUtility.join(ID_TYPENAME_DELIMITER, ((UnknownId) id).getIdTypeName(), toUnqualified(id, flags)); } else { throw new PlatformException("Missing @{} in class {}", IdTypeName.class.getSimpleName(), id.getClass()); } } - return typeName + ID_TYPENAME_DELIMITER + toUnqualified(id); + return typeName + ID_TYPENAME_DELIMITER + toUnqualified(id, flags); } /** @@ -89,7 +138,14 @@ public String toQualified(IId id) { * converted to their string representation, separated by ';'. * */ - public String toUnqualified(IId id) { + public String toUnqualified(IId id, IIdCodecFlag... flags) { + return toUnqualified(id, hashSet(flags)); + } + + /** + * @see #toUnqualified(IId, IIdCodecFlag...) + */ + public String toUnqualified(IId id, Set flags) { if (id == null) { return null; } @@ -99,19 +155,60 @@ public String toUnqualified(IId id) { if (mapper == null) { throw new PlatformException("Missing raw type mapper for wrapped type {}, id type {}", value.getClass(), id.getClass()); } - return mapper.apply(value); + return encryptUnqualified(id.getClass(), mapper.apply(value), flags); } else if (id instanceof ICompositeId) { List components = ((ICompositeId) id).unwrap(); - return components.stream() - .map(this::toUnqualified) + Set flagsWithoutEncryption = flags.stream() + .filter(Predicate.not(IdCodecFlag.ENCRYPTION::equals)) + .collect(Collectors.toSet()); + return encryptUnqualified(id.getClass(), components.stream() + .map(comp -> toUnqualified(comp, flagsWithoutEncryption)) .map(s -> s == null ? "" : s) // empty string if component is null just in case of composite id - .collect(Collectors.joining(";")); + .collect(Collectors.joining(";")), flags); } else if (id instanceof UnknownId) { - return ((UnknownId) id).getId(); + return encryptUnqualified(UnknownId.class, ((UnknownId) id).getId(), flags); } - return handleToUnqualifiedUnknownIdType(id); + return encryptUnqualified(id.getClass(), handleToUnqualifiedUnknownIdType(id, flags), flags); + } + + /** + * Encrypts the given unqualifiedId iff + *

    + *
  • the given idClass needs to be encrypted (see {@link IdEncryption}) + *
  • the given flags contain {@link IdCodecFlag#ENCRYPTION} + *
+ * This will create a signature (see {@link #createSignature(String)} and add it and a delimiter as a suffix to the + * given unqualifiedId. + */ + protected String encryptUnqualified(Class idClass, String unqualifiedId, Set flags) { + if (isNullOrEmpty(unqualifiedId) || !isOneOf(IdCodecFlag.ENCRYPTION, flags) || !idInventory().isIdEncryption(idClass)) { + return unqualifiedId; + } + return unqualifiedId + ENCRYPTION_SIGNATURE_DELIMITER + createSignature(unqualifiedId); + } + + /** + * Create a signature of the given unqualifiedId. Subclasses can override this method and use e.g. the current user id + * as well. + * + * @return an url safe signature + */ + protected String createSignature(String unqualifiedId) { + if (isNullOrEmpty(unqualifiedId)) { + return unqualifiedId; + } + return encodeUrlSafe(createMac(getEncryptionPrivateKey(), unqualifiedId.getBytes(StandardCharsets.UTF_8))); + } + + /** + * @return private key used to create a signature (see {@link #createSignature(String)}). + */ + protected byte[] getEncryptionPrivateKey() { + return Optional.ofNullable(CONFIG.getPropertyValue(IdCrypterPasswordProperty.class)) + .map(v -> v.getBytes(StandardCharsets.UTF_8)) + .orElse(null); } // ---------------- String to IId ---------------- @@ -123,18 +220,15 @@ else if (id instanceof UnknownId) { * @throws PlatformException * if the given string does not match the expected format or the referenced class is not found. */ - public IId fromQualified(String qualifiedId) { - return fromQualifiedInternal(qualifiedId, false); + public IId fromQualified(String qualifiedId, IIdCodecFlag... flags) { + return fromQualified(qualifiedId, hashSet(flags)); } /** - * Parses a string in the format {@code [type-name]:[raw-id;raw-id;...]}. - * - * @return {@code IId} parsed from {@code qualifiedId} or {@code null} if the given string does not match the expected - * format or the referenced class is not found. + * @see #fromQualified(String, IIdCodecFlag...) */ - public IId fromQualifiedLenient(String qualifiedId) { - return fromQualifiedInternal(qualifiedId, true); + public IId fromQualified(String qualifiedId, Set flags) { + return fromQualifiedInternal(qualifiedId, flags); } /** @@ -144,14 +238,21 @@ public IId fromQualifiedLenient(String qualifiedId) { * @throws PlatformException * if the given string does not match the expected format */ - public ID fromUnqualified(Class idClass, String unqualifiedId) { + public ID fromUnqualified(Class idClass, String unqualifiedId, IIdCodecFlag... flags) { + return fromUnqualified(idClass, unqualifiedId, hashSet(flags)); + } + + /** + * @see #fromUnqualified(Class, String, IIdCodecFlag...) + */ + public ID fromUnqualified(Class idClass, String unqualifiedId, Set flags) { if (idClass == null) { throw new PlatformException("Missing id class to parse unqualified id {}", unqualifiedId); } - if (StringUtility.isNullOrEmpty(unqualifiedId)) { + if (isNullOrEmpty(unqualifiedId)) { return null; } - return fromUnqualifiedUnchecked(idClass, unqualifiedId); + return fromUnqualifiedUnchecked(idClass, unqualifiedId, flags); } /** @@ -188,23 +289,23 @@ public void unregisterRawTypeMapper(Class rawType) { /** * Callback method to implement if the codec should be extended to handle qualification of unknown {@link IId} types. */ - protected String handleToUnqualifiedUnknownIdType(IId id) { + protected String handleToUnqualifiedUnknownIdType(IId id, Set flags) { throw new PlatformException("Unsupported id type {}, cannot convert id {}", id.getClass(), id); } /** * Parses a string in the format {@code [type-name]:[raw-id;raw-id;...]}. * - * @param lenient - * If the structure of the given {@code qualifiedId} is invalid and {@code lenient} flag is set to - * {@code true}, value {@code null} is returned. If {@code lenient} flag is set to {@code false}, an - * exception is thrown. + * @param flags + * If the structure of the given {@code qualifiedId} is invalid and {@code IdCodecFlag.LENIENT} flag is set, + * value {@code null} is returned. If {@code IdCodecFlag.LENIENT} flag is not set, an exception is thrown. * @return {@code IId} parsed from {@code qualifiedId} */ - protected IId fromQualifiedInternal(String qualifiedId, boolean lenient) { - if (StringUtility.isNullOrEmpty(qualifiedId)) { + protected IId fromQualifiedInternal(String qualifiedId, Set flags) { + if (isNullOrEmpty(qualifiedId)) { return null; } + boolean lenient = isOneOf(IdCodecFlag.LENIENT, flags); String[] tmp = qualifiedId.split(ID_TYPENAME_DELIMITER, 2); // split into at most two parts if (tmp.length < 2) { // no ":" found if (lenient) { @@ -216,7 +317,7 @@ protected IId fromQualifiedInternal(String qualifiedId, boolean lenient) { } } String typeName = tmp[0]; - Class idClass = m_idInventory.get().getIdClass(typeName); + Class idClass = idInventory().getIdClass(typeName); if (idClass == null) { if (lenient) { //noinspection deprecation @@ -228,7 +329,7 @@ protected IId fromQualifiedInternal(String qualifiedId, boolean lenient) { } try { - return fromUnqualified(idClass, tmp[1]); + return fromUnqualified(idClass, tmp[1], flags); } catch (Exception e) { // handle any deserialization issues in lenient mode by retaining the raw id as UnknownId instance @@ -248,17 +349,60 @@ protected IId fromQualifiedInternal(String qualifiedId, boolean lenient) { * @throws PlatformException * if the given string does not match the expected format */ - protected ID fromUnqualifiedUnchecked(Class idClass, String unqualifiedId) { + protected ID fromUnqualifiedUnchecked(Class idClass, String unqualifiedId, Set flags) { + unqualifiedId = decryptUnqualified(idClass, unqualifiedId, flags); String[] rawComponents = unqualifiedId.split(";", -1 /* force empty strings for empty components */); - Object[] components = parseComponents(idClass, rawComponents); - return m_idFactory.get().createInternal(idClass, components); + Object[] components = parseComponents(idClass, rawComponents, flags); + return idFactory().createInternal(idClass, components); + } + + /** + * Decrypts the given unqualifiedId iff + *
    + *
  • the given idClass needs to be encrypted (see {@link IdEncryption}) + *
  • the given flags contain {@link IdCodecFlag#ENCRYPTION} + *
+ * This will split the encrypted unqualifiedId into the id and its signature and assert the signature's validity. + */ + protected String decryptUnqualified(Class idClass, String unqualifiedId, Set flags) { + String[] unqualifiedIdEncryptionParts = splitToEncryptionParts(unqualifiedId); + assertEncrypted(idClass, unqualifiedIdEncryptionParts, flags); + return unqualifiedIdEncryptionParts[0]; + } + + /** + * Assert the validity of the given unqualifiedIdEncryptionParts (see {@link #splitToEncryptionParts(String)}). The id + * needs to be encrypted iff + *
    + *
  • the given idClass needs to be encrypted (see {@link IdEncryption}) + *
  • the given flags contain {@link IdCodecFlag#ENCRYPTION} + *
+ * This will check the presence and a signature if the id needs to be encrypted and the absence of such a signature if + * the id needs to be unencrypted. In addition, the signature is verified for an encrypted id. + */ + protected void assertEncrypted(Class idClass, String[] unqualifiedIdEncryptionParts, Set flags) { + if (isOneOf(IdCodecFlag.ENCRYPTION, flags) && idInventory().isIdEncryption(idClass)) { + assertEqual(unqualifiedIdEncryptionParts.length, 2, "Unqualified id must be encrypted."); + } + else { + assertEqual(unqualifiedIdEncryptionParts.length, 1, "Unqualified id must not be encrypted."); + return; + } + assertEqual(unqualifiedIdEncryptionParts[1], createSignature(unqualifiedIdEncryptionParts[0]), "Signature of unqualified id does not match."); + } + + /** + * Split the given unqualifiedId into id and signature using the {@link #ENCRYPTION_SIGNATURE_DELIMITER}. + */ + protected String[] splitToEncryptionParts(String unqualifiedId) { + return unqualifiedId.split(ENCRYPTION_SIGNATURE_DELIMITER); } /** * Parses given {@code rawComponents} based on the declared component types of given {@code idClass}. */ - protected Object[] parseComponents(Class idClass, String[] rawComponents) { - List> componentTypes = m_idFactory.get().getRawTypes(idClass); + protected Object[] parseComponents(Class idClass, String[] rawComponents, Set flags) { + List> componentTypes = idFactory().getRawTypes(idClass); if (!(componentTypes.size() == rawComponents.length)) { throw new PlatformException("Wrong argument size, expected {} parameter, got {} raw components {}, idType={}", componentTypes.size(), rawComponents.length, Arrays.toString(rawComponents), idClass.getName()); } @@ -272,7 +416,7 @@ protected Object[] parseComponents(Class idClass, String[] rawCom } try { String raw = rawComponents[i]; - if (StringUtility.isNullOrEmpty(raw)) { + if (isNullOrEmpty(raw)) { components[i] = null; } else { diff --git a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdEncryption.java b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdEncryption.java new file mode 100644 index 00000000000..daa11964883 --- /dev/null +++ b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdEncryption.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.dataobject.id; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates whether an {@link IId} is serialized and deserialized using encryption or not. This annotation is inherited + * and can be overridden by subclasses. Only annotations from superclasses are inherited, interfaces are not taken into + * account. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface IdEncryption { + /** + * Whether encryption is enabled or not. Default is {@code true}. + */ + boolean value() default true; +} diff --git a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdInventory.java b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdInventory.java index 19fa060d302..a156d02e228 100644 --- a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdInventory.java +++ b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdInventory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -9,10 +9,14 @@ */ package org.eclipse.scout.rt.dataobject.id; +import static java.util.Collections.emptyList; import static org.eclipse.scout.rt.platform.util.Assertions.*; import java.util.HashMap; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; import jakarta.annotation.PostConstruct; @@ -31,6 +35,7 @@ public class IdInventory { protected final Map> m_nameToClassMap = new HashMap<>(); protected final Map, String> m_classToNameMap = new HashMap<>(); + protected final Map, Boolean> m_classToIdEncryptionMap = new HashMap<>(); @PostConstruct protected void createClassCache() { @@ -46,6 +51,22 @@ protected void createClassCache() { } } LOG.debug("Registered {} id types", m_nameToClassMap.size()); + + ClassInventory.get().getKnownAnnotatedTypes(IdEncryption.class).stream() + .map(IClassInfo::resolveClass) + // log all classes that do not extend/implement IId and continue with those who are + .collect(Collectors.collectingAndThen( + Collectors.partitioningBy(IId.class::isAssignableFrom), + map -> { + // false -> classes that do not extend/implement IId + map.getOrDefault(false, emptyList()).forEach(clazz -> LOG.warn("Class {} is annotated with @{} but does not implement {}. Skipping class.", clazz.getName(), IdEncryption.class.getSimpleName(), IId.class.getName())); + // true -> classes that extend/implement IId + return map.getOrDefault(true, emptyList()).stream(); + })) + // register IdEncryption + .> map(clazz -> clazz.asSubclass(IId.class)) + .forEach(idClass -> registerIdEncryption(idClass, idClass.getAnnotation(IdEncryption.class).value())); + LOG.debug("Registered {} id encryption mappings", m_classToIdEncryptionMap.size()); } /** @@ -69,6 +90,17 @@ protected void checkDuplicateIdTypeNames(Class clazz, String typeName, Class< assertNull(existingName, "{} is annotated with @{} value '{}', but was already registered with type name '{}'. Register each class only once.", clazz, IdTypeName.class.getSimpleName(), typeName, existingName); } + /** + * Register id class with {@link IdEncryption} annotation present. + *

+ * Note: The access to the data structure is not synchronized and therefore not thread safe. Use this method to set up + * the {@link IdInventory} instance directly after platform start and not to change the {@link IdInventory} behavior + * dynamically at runtime. + */ + public void registerIdEncryption(Class idClass, boolean encryption) { + m_classToIdEncryptionMap.put(idClass, encryption); + } + /** * @return the type name of the id class as defined by the {@link IdTypeName} annotation or null if the * annotation is not present. @@ -96,4 +128,31 @@ public String getTypeName(IId id) { public Class getIdClass(String typeName) { return m_nameToClassMap.get(typeName); } + + /** + * @return Whether the {@link IId} needs to be serialized and deserialized using encryption or not. For more details + * see {@link IdEncryption}. + */ + public boolean isIdEncryption(Class idClass) { + synchronized (m_classToIdEncryptionMap) { + if (m_classToIdEncryptionMap.containsKey(idClass)) { + return m_classToIdEncryptionMap.get(idClass); + } + + m_classToIdEncryptionMap.put(idClass, Optional.ofNullable(idClass.getAnnotation(IdEncryption.class)) + .map(IdEncryption::value) + // check all super class + .orElseGet(() -> Optional.of(idClass.getSuperclass()) + // only consider those that extend/implement IId + .filter(Objects::nonNull) + .filter(IId.class::isAssignableFrom) + .> map(c -> c.asSubclass(IId.class)) + // check isIdEncryption + .map(this::isIdEncryption) + // true if optional is empty + .orElse(true))); + + return m_classToIdEncryptionMap.get(idClass); + } + } } diff --git a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdTypeName.java b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdTypeName.java index acbc31047dd..71e9524686a 100644 --- a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdTypeName.java +++ b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/id/IdTypeName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -17,12 +17,14 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; +import org.eclipse.scout.rt.dataobject.id.IdCodec.IIdCodecFlag; + /** * Annotation used to define the unique type name for an {@link IId} class, used when serializing or deserializing * instances. * - * @see IdCodec#toQualified(IId) - * @see IdCodec#fromQualified(String) + * @see IdCodec#toQualified(IId, IIdCodecFlag...) + * @see IdCodec#fromQualified(String, IIdCodecFlag...) * @see TypedId */ @Documented diff --git a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/security/AbstractEncryptDecryptSupport.java b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/security/AbstractEncryptDecryptSupport.java new file mode 100644 index 00000000000..02b86b0651c --- /dev/null +++ b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/security/AbstractEncryptDecryptSupport.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.dataobject.security; + +import java.nio.charset.StandardCharsets; + +import jakarta.annotation.PostConstruct; + +import org.eclipse.scout.rt.platform.ApplicationScoped; +import org.eclipse.scout.rt.platform.security.EncryptionKey; +import org.eclipse.scout.rt.platform.security.SecurityUtility; +import org.eclipse.scout.rt.platform.util.Base64Utility; +import org.eclipse.scout.rt.platform.util.StringUtility; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Abstract implementation of an encrypt-/decrypt support using a given password and salt. Based on given password and + * salt a {@link EncryptionKey} is created and then cached and re-used for all invocations. + */ +@ApplicationScoped +public abstract class AbstractEncryptDecryptSupport { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractEncryptDecryptSupport.class); + + private volatile int m_encryptionKeyLength = 128; + private volatile EncryptionKey m_encryptionKey; + + @PostConstruct + protected void initialize() { + checkPasswordProperty(); + } + + protected void checkPasswordProperty() { + if (getPassword() == null || getPassword().length < 10) { + LOG.error("Please provide a password with minimal length 10"); + } + } + + /** + * @return password to use for this encrypt-decrypt support + */ + protected abstract char[] getPassword(); + + /** + * @return salt to use for this encrypt-decrypt support + */ + protected abstract byte[] getSalt(); + + /** + * @return 128, 192, 256, see {@link SecurityUtility} + */ + protected int getEncryptionKeyLength() { + return m_encryptionKeyLength; + } + + /** + * Must be one of 128, 192, 256, see {@link SecurityUtility} + */ + protected void setEncryptionKeyLength(int encryptionKeyLength) { + if (m_encryptionKeyLength == encryptionKeyLength) { + return; + } + + m_encryptionKeyLength = encryptionKeyLength; + m_encryptionKey = null; + } + + /** + * Warning: This key must only be used for encryption. Decryption must be backwards compatible and uses meta + * parameters stored at beginning of stream. Therefore, never use an {@link EncryptionKey} directly to decrypt but + * always with {@link SecurityUtility#decrypt(byte[], char[], byte[], int, EncryptionKey)} + */ + protected final EncryptionKey getKey() { + EncryptionKey key = m_encryptionKey; + if (key == null) { + key = SecurityUtility.createEncryptionKey(getPassword(), getSalt(), getEncryptionKeyLength()); + m_encryptionKey = key; + } + return key; + } + + /** + * @return Encrypted {@code clearTextData}. + */ + public String encrypt(String clearTextData) { + return encrypt(clearTextData, false); + } + + /** + * @return Encrypted {@code clearTextData} using a URL-safe encoding. + */ + public String encryptUrlSafe(String clearTextData) { + return encrypt(clearTextData, true); + } + + protected String encrypt(String clearTextData, boolean urlSafe) { + if (StringUtility.isNullOrEmpty(clearTextData)) { + return null; + } + byte[] encryption = SecurityUtility.encrypt(clearTextData.getBytes(StandardCharsets.UTF_8), getKey()); + return Base64Utility.encode(encryption, urlSafe); + } + + /** + * @return Decrypted {@code encryptedData}. + */ + public String decrypt(String encryptedData) { + return decrypt(encryptedData, false); + } + + /** + * @return Decrypted {@code encryptedData} using a URL-safe decoding. + */ + public String decryptUrlSafe(String encryptedData) { + return decrypt(encryptedData, true); + } + + protected String decrypt(String encryptedData, boolean urlSafe) { + if (StringUtility.isNullOrEmpty(encryptedData)) { + return null; + } + byte[] encrypted = Base64Utility.decode(encryptedData, urlSafe); + byte[] decrypted = SecurityUtility.decrypt(encrypted, getPassword(), getSalt(), getEncryptionKeyLength(), getKey()); + return new String(decrypted, StandardCharsets.UTF_8); + } +} diff --git a/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/security/IdCrypter.java b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/security/IdCrypter.java new file mode 100644 index 00000000000..db3cf626787 --- /dev/null +++ b/org.eclipse.scout.rt.dataobject/src/main/java/org/eclipse/scout/rt/dataobject/security/IdCrypter.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.dataobject.security; + +import org.eclipse.scout.rt.dataobject.id.IId; +import org.eclipse.scout.rt.dataobject.id.IdCodec; +import org.eclipse.scout.rt.platform.ApplicationScoped; +import org.eclipse.scout.rt.platform.BEANS; +import org.eclipse.scout.rt.platform.config.AbstractBinaryConfigProperty; +import org.eclipse.scout.rt.platform.config.AbstractStringConfigProperty; +import org.eclipse.scout.rt.platform.config.CONFIG; + +/** + * Encodes and encrypts or decrypts and decodes {@link IId}. + *

+ * This default implementation uses the {@link IdCodec} to convert {@link IId} from/to their {@link String} + * representation and then applies URL-safe encryption using {@link IdEncryptDecryptSupport}. + * + * @see IdCodec + * @see IdEncryptDecryptSupport + */ +@ApplicationScoped +public class IdCrypter { + + protected final IdCodec m_codec = BEANS.get(IdCodec.class); + protected final IdEncryptDecryptSupport m_encryptDecryptSupport = BEANS.get(IdEncryptDecryptSupport.class); + + /** + * @return {@code id} converted to its {@link String} representation and then encrypted using a URL-safe encoding. + */ + public String encrypt(IId id) { + String encoded = m_codec.toQualified(id); + return m_encryptDecryptSupport.encryptUrlSafe(encoded); + } + + /** + * @return {@code id} converted to its corresponding {@link IId} representation, decrypted using a URL-safe decoding. + */ + public IId decrypt(String id) { + String decrypted = m_encryptDecryptSupport.decryptUrlSafe(id); + return m_codec.fromQualified(decrypted); + } + + /** + * {@link AbstractEncryptDecryptSupport} implementation used for {@link IId} handled by {@link IdCrypter} + */ + public static class IdEncryptDecryptSupport extends AbstractEncryptDecryptSupport { + + @Override + protected char[] getPassword() { + String value = CONFIG.getPropertyValue(IdCrypterPasswordProperty.class); + return value != null ? value.toCharArray() : null; + } + + @Override + protected byte[] getSalt() { + return CONFIG.getPropertyValue(IdCrypterSaltProperty.class); + } + + public static class IdCrypterPasswordProperty extends AbstractStringConfigProperty { + + @Override + public String getKey() { + return "scout.idCrypterPassword"; + } + + @Override + public String description() { + return String.format("Password to encrypt data identifiers (e.g. entity ids) before transmitting to an external " + + "interface. The value of this password must be different for each app zone (e.g. 'int' or 'prod'). " + + "See helper class %s loading and caching secret password", IdEncryptDecryptSupport.class.getName()); + } + } + + public static class IdCrypterSaltProperty extends AbstractBinaryConfigProperty { + + @Override + public String getKey() { + return "scout.idCrypterSalt"; + } + + @Override + public String description() { + return String.format("Salt to encrypt data identifiers (e.g entity ids) before transmitting to an external " + + "interface. See helper class %s loading and caching secret salt", IdEncryptDecryptSupport.class.getName()); + } + } + } +} diff --git a/org.eclipse.scout.rt.jackson.test/src/test/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdSerializationTest.java b/org.eclipse.scout.rt.jackson.test/src/test/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdSerializationTest.java index 4dfecbe40d1..77305c6bcd6 100644 --- a/org.eclipse.scout.rt.jackson.test/src/test/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdSerializationTest.java +++ b/org.eclipse.scout.rt.jackson.test/src/test/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdSerializationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -117,7 +117,7 @@ protected static class QualifiedIIdSerializationTest_DataObjectSerializerProvide @Override public JsonSerializer findSerializer(ScoutDataObjectModuleContext moduleContext, JavaType type, SerializationConfig config, BeanDescription beanDesc) { if (type.hasRawClass(FixtureStringId.class) || type.hasRawClass(FixtureUuId.class) || type.hasRawClass(FixtureCompositeId.class)) { - return new QualifiedIIdSerializer(); + return new QualifiedIIdSerializer(moduleContext); } return null; @@ -134,7 +134,7 @@ public JsonDeserializer findDeserializer(ScoutDataObjectModuleContext moduleC @Override public JsonSerializer findKeySerializer(ScoutDataObjectModuleContext moduleContext, JavaType type, SerializationConfig config, BeanDescription beanDesc) { if (type.hasRawClass(FixtureStringId.class) || type.hasRawClass(FixtureUuId.class) || type.hasRawClass(FixtureCompositeId.class)) { - return new QualifiedIIdMapKeySerializer(); + return new QualifiedIIdMapKeySerializer(moduleContext); } return null; } diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/JacksonIdEncryptionDataObjectMapper.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/JacksonIdEncryptionDataObjectMapper.java new file mode 100644 index 00000000000..1ffff5a3717 --- /dev/null +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/JacksonIdEncryptionDataObjectMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.jackson.dataobject; + +import org.eclipse.scout.rt.dataobject.IDataObjectMapper; +import org.eclipse.scout.rt.dataobject.IIdEncryptionDataObjectMapper; +import org.eclipse.scout.rt.platform.IBean; +import org.eclipse.scout.rt.platform.Order; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * {@link IDataObjectMapper} implementation based on jackson {@link ObjectMapper} with id encrypted + * serialization/deserialization. + */ +@Order(IBean.DEFAULT_BEAN_ORDER + 100) +public class JacksonIdEncryptionDataObjectMapper extends JacksonDataObjectMapper implements IIdEncryptionDataObjectMapper { + + @Override + protected void prepareScoutDataModuleContext(ScoutDataObjectModuleContext moduleContext) { + super.prepareScoutDataModuleContext(moduleContext); + moduleContext.withIdEncryption(true); + } +} diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/ScoutDataObjectModuleContext.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/ScoutDataObjectModuleContext.java index a1198a09330..83ce358a2dd 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/ScoutDataObjectModuleContext.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/ScoutDataObjectModuleContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -41,6 +41,8 @@ public class ScoutDataObjectModuleContext { protected static final String LENIENT_MODE_KEY = "lenientModeKey"; + protected static final String ID_ENCRYPTION_KEY = "idEncryptionKey"; + protected LazyValue m_comparator = new LazyValue<>(() -> BEANS.get(DoEntitySerializerAttributeNameComparator.class).init(this)); protected final Map m_contextMap = new HashMap<>(); @@ -138,7 +140,16 @@ public boolean isLenientMode() { } public ScoutDataObjectModuleContext withLenientMode(boolean lenientMode) { - put(LENIENT_MODE_KEY, true); + put(LENIENT_MODE_KEY, lenientMode); + return this; + } + + public boolean isIdEncryption() { + return BooleanUtility.nvl(get(ID_ENCRYPTION_KEY, Boolean.class)); + } + + public ScoutDataObjectModuleContext withIdEncryption(boolean idEncryption) { + put(ID_ENCRYPTION_KEY, idEncryption); return this; } } diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/ScoutDataObjectSerializerProvider.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/ScoutDataObjectSerializerProvider.java index 64e78e0c6af..bf1ad929439 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/ScoutDataObjectSerializerProvider.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/ScoutDataObjectSerializerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -75,14 +75,14 @@ else if (BinaryResource.class.isAssignableFrom(rawClass)) { } else if (IId.class.isAssignableFrom(rawClass)) { if (type.isConcrete()) { - return new UnqualifiedIIdSerializer(type); + return new UnqualifiedIIdSerializer(moduleContext, type); } else { - return new QualifiedIIdSerializer(); + return new QualifiedIIdSerializer(moduleContext); } } else if (TypedId.class.isAssignableFrom(rawClass)) { - return new TypedIdSerializer(); + return new TypedIdSerializer(moduleContext); } else if (IEnum.class.isAssignableFrom(rawClass)) { return new EnumSerializer(type); @@ -125,7 +125,7 @@ else if (BinaryResource.class.isAssignableFrom(rawClass)) { else if (IId.class.isAssignableFrom(rawClass)) { Class idClass = rawClass.asSubclass(IId.class); if (type.isConcrete()) { - return new UnqualifiedIIdDeserializer(idClass); + return new UnqualifiedIIdDeserializer(moduleContext, idClass); } else { return new QualifiedIIdDeserializer(moduleContext, idClass); @@ -146,10 +146,10 @@ public JsonSerializer findKeySerializer(ScoutDataObjectModuleContext moduleCo } if (IId.class.isAssignableFrom(rawClass)) { if (type.isConcrete()) { - return new UnqualifiedIIdMapKeySerializer(); + return new UnqualifiedIIdMapKeySerializer(moduleContext); } else { - return new QualifiedIIdMapKeySerializer(); + return new QualifiedIIdMapKeySerializer(moduleContext); } } if (IEnum.class.isAssignableFrom(rawClass)) { diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecDeserializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecDeserializer.java new file mode 100644 index 00000000000..beff5a47541 --- /dev/null +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecDeserializer.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.jackson.dataobject.id; + +import static java.util.Collections.unmodifiableSet; + +import java.util.Set; + +import org.eclipse.scout.rt.dataobject.id.IdCodec; +import org.eclipse.scout.rt.dataobject.id.IdCodec.IIdCodecFlag; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; +import org.eclipse.scout.rt.platform.util.LazyValue; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +/** + * Abstract {@link StdDeserializer} with {@link ScoutDataObjectModuleContext} that provides an {@link IdCodec} and + * information about the {@link IIdCodecFlag}s of the context. + */ +public abstract class AbstractIdCodecDeserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + protected final ScoutDataObjectModuleContext m_moduleContext; + + protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); + protected final LazyValue> m_idCodecFlags = new LazyValue<>(() -> unmodifiableSet(computeIdCodecFlags())); + + public AbstractIdCodecDeserializer(ScoutDataObjectModuleContext moduleContext, Class valueClass) { + super(valueClass); + m_moduleContext = moduleContext; + } + + public AbstractIdCodecDeserializer(ScoutDataObjectModuleContext moduleContext, JavaType valueType) { + super(valueType); + m_moduleContext = moduleContext; + } + + protected ScoutDataObjectModuleContext moduleContext() { + return m_moduleContext; + } + + protected IdCodec idCodec() { + return m_idCodec.get(); + } + + protected Set computeIdCodecFlags() { + return IdCodecUtility.getIdCodecFlags(moduleContext()); + } + + protected Set idCodecFlags() { + return m_idCodecFlags.get(); + } +} diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecMapKeyDeserializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecMapKeyDeserializer.java new file mode 100644 index 00000000000..6469db2db69 --- /dev/null +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecMapKeyDeserializer.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.jackson.dataobject.id; + +import static java.util.Collections.unmodifiableSet; + +import java.util.Set; + +import org.eclipse.scout.rt.dataobject.id.IdCodec; +import org.eclipse.scout.rt.dataobject.id.IdCodec.IIdCodecFlag; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; +import org.eclipse.scout.rt.platform.util.LazyValue; + +import com.fasterxml.jackson.databind.KeyDeserializer; + +/** + * Abstract {@link KeyDeserializer} with {@link ScoutDataObjectModuleContext} that provides an {@link IdCodec} and + * information about the {@link IIdCodecFlag}s of the context. + */ +public abstract class AbstractIdCodecMapKeyDeserializer extends KeyDeserializer { + + protected final ScoutDataObjectModuleContext m_moduleContext; + + protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); + protected final LazyValue> m_idCodecFlags = new LazyValue<>(() -> unmodifiableSet(computeIdCodecFlags())); + + public AbstractIdCodecMapKeyDeserializer(ScoutDataObjectModuleContext moduleContext) { + m_moduleContext = moduleContext; + } + + protected ScoutDataObjectModuleContext moduleContext() { + return m_moduleContext; + } + + protected IdCodec idCodec() { + return m_idCodec.get(); + } + + protected Set computeIdCodecFlags() { + return IdCodecUtility.getIdCodecFlags(moduleContext()); + } + + protected Set idCodecFlags() { + return m_idCodecFlags.get(); + } +} diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecMapKeySerializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecMapKeySerializer.java new file mode 100644 index 00000000000..e1734a1635e --- /dev/null +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecMapKeySerializer.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.jackson.dataobject.id; + +import static java.util.Collections.unmodifiableSet; + +import java.util.Set; + +import org.eclipse.scout.rt.dataobject.id.IdCodec; +import org.eclipse.scout.rt.dataobject.id.IdCodec.IIdCodecFlag; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; +import org.eclipse.scout.rt.platform.util.LazyValue; + +import com.fasterxml.jackson.databind.JsonSerializer; + +/** + * Abstract {@link JsonSerializer} with {@link ScoutDataObjectModuleContext} that provides an {@link IdCodec} and + * information about the {@link IIdCodecFlag}s of the context. + */ +public abstract class AbstractIdCodecMapKeySerializer extends JsonSerializer { + + protected final ScoutDataObjectModuleContext m_moduleContext; + + protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); + protected final LazyValue> m_idCodecFlags = new LazyValue<>(() -> unmodifiableSet(computeIdCodecFlags())); + + public AbstractIdCodecMapKeySerializer(ScoutDataObjectModuleContext moduleContext) { + m_moduleContext = moduleContext; + } + + protected ScoutDataObjectModuleContext moduleContext() { + return m_moduleContext; + } + + protected IdCodec idCodec() { + return m_idCodec.get(); + } + + protected Set computeIdCodecFlags() { + return IdCodecUtility.getIdCodecFlags(moduleContext()); + } + + protected Set idCodecFlags() { + return m_idCodecFlags.get(); + } +} diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecSerializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecSerializer.java new file mode 100644 index 00000000000..95afc08b87d --- /dev/null +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/AbstractIdCodecSerializer.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.jackson.dataobject.id; + +import static java.util.Collections.unmodifiableSet; + +import java.util.Set; + +import org.eclipse.scout.rt.dataobject.id.IdCodec; +import org.eclipse.scout.rt.dataobject.id.IdCodec.IIdCodecFlag; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; +import org.eclipse.scout.rt.platform.util.LazyValue; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +/** + * Abstract {@link StdSerializer} with {@link ScoutDataObjectModuleContext} that provides an {@link IdCodec} and + * information about the {@link IIdCodecFlag}s of the context. + */ +public abstract class AbstractIdCodecSerializer extends StdSerializer { + private static final long serialVersionUID = 1L; + + protected final ScoutDataObjectModuleContext m_moduleContext; + + protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); + protected final LazyValue> m_idCodecFlags = new LazyValue<>(() -> unmodifiableSet(computeIdCodecFlags())); + + public AbstractIdCodecSerializer(ScoutDataObjectModuleContext moduleContext, Class valueClass) { + super(valueClass, false); + m_moduleContext = moduleContext; + } + + public AbstractIdCodecSerializer(ScoutDataObjectModuleContext moduleContext, JavaType valueType) { + super(valueType); + m_moduleContext = moduleContext; + } + + protected ScoutDataObjectModuleContext moduleContext() { + return m_moduleContext; + } + + protected IdCodec idCodec() { + return m_idCodec.get(); + } + + protected Set computeIdCodecFlags() { + return IdCodecUtility.getIdCodecFlags(moduleContext()); + } + + protected Set idCodecFlags() { + return m_idCodecFlags.get(); + } +} diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/IdCodecUtility.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/IdCodecUtility.java new file mode 100644 index 00000000000..eadba8b2843 --- /dev/null +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/IdCodecUtility.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.scout.rt.jackson.dataobject.id; + +import java.util.Set; + +import org.eclipse.scout.rt.dataobject.id.IdCodec.IIdCodecFlag; +import org.eclipse.scout.rt.dataobject.id.IdCodec.IdCodecFlag; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; +import org.eclipse.scout.rt.platform.util.CollectionUtility; + +public final class IdCodecUtility { + + private IdCodecUtility() { + } + + /** + * Computes the {@link IIdCodecFlag}s for the given {@link ScoutDataObjectModuleContext}. E.g.: + * {@link IdCodecFlag#ENCRYPTION} if {@link ScoutDataObjectModuleContext#isIdEncryption()} returns {@code true}. The + * resulting set is mutable. + */ + public static Set getIdCodecFlags(ScoutDataObjectModuleContext moduleContext) { + var flags = CollectionUtility. emptyHashSet(); + if (moduleContext == null) { + return flags; + } + if (moduleContext.isLenientMode()) { + flags.add(IdCodecFlag.LENIENT); + } + if (moduleContext.isIdEncryption()) { + flags.add(IdCodecFlag.ENCRYPTION); + } + return flags; + } +} diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdDeserializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdDeserializer.java index 90a4f645575..66afc73f339 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdDeserializer.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -10,46 +10,43 @@ package org.eclipse.scout.rt.jackson.dataobject.id; import static org.eclipse.scout.rt.platform.util.Assertions.assertInstance; +import static org.eclipse.scout.rt.platform.util.ObjectUtility.isOneOf; import java.io.IOException; import org.eclipse.scout.rt.dataobject.id.IId; import org.eclipse.scout.rt.dataobject.id.IdCodec; +import org.eclipse.scout.rt.dataobject.id.IdCodec.IdCodecFlag; import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; -import org.eclipse.scout.rt.platform.util.LazyValue; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.exc.InvalidFormatException; /** * Custom deserializer for {@link IId} instances - like {@link TypedIdDeserializer} it uses {@link IdCodec} for * serialization. It may be used as a replacement for {@link UnqualifiedIIdDeserializer}. */ -public class QualifiedIIdDeserializer extends StdDeserializer { +public class QualifiedIIdDeserializer extends AbstractIdCodecDeserializer { private static final long serialVersionUID = 1L; - protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); protected final Class m_idClass; - protected final ScoutDataObjectModuleContext m_moduleContext; - - public QualifiedIIdDeserializer(ScoutDataObjectModuleContext context, Class idClass) { - super(idClass); + public QualifiedIIdDeserializer(ScoutDataObjectModuleContext moduleContext, Class idClass) { + super(moduleContext, idClass); m_idClass = idClass; - m_moduleContext = context; } @Override public IId deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String rawValue = p.getText(); try { - if (m_moduleContext.isLenientMode()) { - return m_idCodec.get().fromQualifiedLenient(rawValue); + IId id = idCodec().fromQualified(rawValue, idCodecFlags()); + if (!isOneOf(IdCodecFlag.LENIENT, idCodecFlags())) { + // check required to prevent returning an instance that isn't compatible with requested ID class + assertInstance(id, m_idClass); } - // check required to prevent returning an instance that isn't compatible with requested ID class - return assertInstance(m_idCodec.get().fromQualified(rawValue), m_idClass); + return id; } catch (RuntimeException e) { throw InvalidFormatException.from(p, "Failed to deserialize qualified IId: " + e.getMessage(), rawValue, m_idClass); diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdMapKeyDeserializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdMapKeyDeserializer.java index 7931d398271..8aec4f827da 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdMapKeyDeserializer.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdMapKeyDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -10,42 +10,40 @@ package org.eclipse.scout.rt.jackson.dataobject.id; import static org.eclipse.scout.rt.platform.util.Assertions.assertInstance; +import static org.eclipse.scout.rt.platform.util.ObjectUtility.isOneOf; import java.io.IOException; import org.eclipse.scout.rt.dataobject.id.IId; import org.eclipse.scout.rt.dataobject.id.IdCodec; +import org.eclipse.scout.rt.dataobject.id.IdCodec.IdCodecFlag; import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; -import org.eclipse.scout.rt.platform.util.LazyValue; import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.KeyDeserializer; import com.fasterxml.jackson.databind.exc.InvalidFormatException; /** * Custom deserializer for {@link IId} instances - like {@link TypedIdDeserializer} it uses {@link IdCodec} for * serialization. It may be used as a replacement for {@link UnqualifiedIIdDeserializer}. */ -public class QualifiedIIdMapKeyDeserializer extends KeyDeserializer { +public class QualifiedIIdMapKeyDeserializer extends AbstractIdCodecMapKeyDeserializer { - protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); - - protected final ScoutDataObjectModuleContext m_moduleContext; protected final Class m_idClass; public QualifiedIIdMapKeyDeserializer(ScoutDataObjectModuleContext moduleContext, Class idClass) { - m_moduleContext = moduleContext; + super(moduleContext); m_idClass = idClass; } @Override public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException { try { - if (m_moduleContext.isLenientMode()) { - return m_idCodec.get().fromQualifiedLenient(key); + IId id = idCodec().fromQualified(key, idCodecFlags()); + if (!isOneOf(IdCodecFlag.LENIENT, idCodecFlags())) { + // check required to prevent returning an instance that isn't compatible with requested ID class + assertInstance(id, m_idClass); } - // check required to prevent returning an instance that isn't compatible with requested ID class - return assertInstance(m_idCodec.get().fromQualified(key), m_idClass); + return id; } catch (RuntimeException e) { throw InvalidFormatException.from(null, "Failed to deserialize qualified IId map key: " + e.getMessage(), key, m_idClass); diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdMapKeySerializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdMapKeySerializer.java index 860a450a9c3..9ef3083f11f 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdMapKeySerializer.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdMapKeySerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -13,22 +13,23 @@ import org.eclipse.scout.rt.dataobject.id.IId; import org.eclipse.scout.rt.dataobject.id.IdCodec; -import org.eclipse.scout.rt.platform.util.LazyValue; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; /** * Custom serializer for {@link IId} instances - like {@link TypedIdSerializer} it uses {@link IdCodec} for * serialization. It may be used as a replacement for {@link UnqualifiedIIdMapKeySerializer}. */ -public class QualifiedIIdMapKeySerializer extends JsonSerializer { +public class QualifiedIIdMapKeySerializer extends AbstractIdCodecMapKeySerializer { - protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); + public QualifiedIIdMapKeySerializer(ScoutDataObjectModuleContext moduleContext) { + super(moduleContext); + } @Override public void serialize(IId value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - gen.writeFieldName(m_idCodec.get().toQualified(value)); + gen.writeFieldName(idCodec().toQualified(value, idCodecFlags())); } } diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdSerializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdSerializer.java index 994fdc37815..e0cb68b4221 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdSerializer.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/QualifiedIIdSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -13,27 +13,24 @@ import org.eclipse.scout.rt.dataobject.id.IId; import org.eclipse.scout.rt.dataobject.id.IdCodec; -import org.eclipse.scout.rt.platform.util.LazyValue; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; /** * Custom serializer for {@link IId} instances - like {@link TypedIdSerializer} it uses {@link IdCodec} for * serialization. It may be used as a replacement for {@link UnqualifiedIIdSerializer}. */ -public class QualifiedIIdSerializer extends StdSerializer { +public class QualifiedIIdSerializer extends AbstractIdCodecSerializer { private static final long serialVersionUID = 1L; - protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); - - public QualifiedIIdSerializer() { - super(IId.class, false); + public QualifiedIIdSerializer(ScoutDataObjectModuleContext moduleContext) { + super(moduleContext, IId.class); } @Override public void serialize(IId value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - gen.writeString(m_idCodec.get().toQualified(value)); + gen.writeString(idCodec().toQualified(value, idCodecFlags())); } } diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/TypedIdDeserializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/TypedIdDeserializer.java index ee431284cd3..728bb47977b 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/TypedIdDeserializer.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/TypedIdDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -12,38 +12,28 @@ import java.io.IOException; import org.eclipse.scout.rt.dataobject.id.IId; -import org.eclipse.scout.rt.dataobject.id.IdCodec; import org.eclipse.scout.rt.dataobject.id.TypedId; import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; -import org.eclipse.scout.rt.platform.util.LazyValue; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.exc.InvalidFormatException; /** * Custom deserializer for {@link TypedId} values. */ -public class TypedIdDeserializer extends StdDeserializer> { +public class TypedIdDeserializer extends AbstractIdCodecDeserializer> { private static final long serialVersionUID = 1L; - protected final ScoutDataObjectModuleContext m_moduleContext; - protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); - public TypedIdDeserializer(ScoutDataObjectModuleContext moduleContext) { - super(TypedId.class); - m_moduleContext = moduleContext; + super(moduleContext, TypedId.class); } @Override public TypedId deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String rawValue = p.getText(); try { - if (m_moduleContext.isLenientMode()) { - return TypedId.of(m_idCodec.get().fromQualifiedLenient(rawValue)); - } - return TypedId.of(m_idCodec.get().fromQualified(rawValue)); + return TypedId.of(idCodec().fromQualified(rawValue, idCodecFlags())); } catch (RuntimeException e) { throw InvalidFormatException.from(p, "Failed to deserialize TypedId: " + e.getMessage(), rawValue, TypedId.class); diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/TypedIdSerializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/TypedIdSerializer.java index 64eb4368962..9feb8448c44 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/TypedIdSerializer.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/TypedIdSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -12,28 +12,24 @@ import java.io.IOException; import org.eclipse.scout.rt.dataobject.id.IId; -import org.eclipse.scout.rt.dataobject.id.IdCodec; import org.eclipse.scout.rt.dataobject.id.TypedId; -import org.eclipse.scout.rt.platform.util.LazyValue; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; /** * Custom serializer for all {@link TypedId} instances. */ -public class TypedIdSerializer extends StdSerializer> { +public class TypedIdSerializer extends AbstractIdCodecSerializer> { private static final long serialVersionUID = 1L; - protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); - - public TypedIdSerializer() { - super(TypedId.class, false); + public TypedIdSerializer(ScoutDataObjectModuleContext moduleContext) { + super(moduleContext, TypedId.class); } @Override public void serialize(TypedId value, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeString(m_idCodec.get().toQualified(value.getId())); + gen.writeString(idCodec().toQualified(value.getId(), idCodecFlags())); } } diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdDeserializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdDeserializer.java index cc0d809e609..722b8bdebc3 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdDeserializer.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -12,25 +12,22 @@ import java.io.IOException; import org.eclipse.scout.rt.dataobject.id.IId; -import org.eclipse.scout.rt.dataobject.id.IdCodec; -import org.eclipse.scout.rt.platform.util.LazyValue; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.exc.InvalidFormatException; /** * Custom deserializer for {@link IId} values. */ -public class UnqualifiedIIdDeserializer extends StdDeserializer { +public class UnqualifiedIIdDeserializer extends AbstractIdCodecDeserializer { private static final long serialVersionUID = 1L; - protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); protected final Class m_idClass; - public UnqualifiedIIdDeserializer(Class idClass) { - super(idClass); + public UnqualifiedIIdDeserializer(ScoutDataObjectModuleContext moduleContext, Class idClass) { + super(moduleContext, idClass); m_idClass = idClass; } @@ -38,7 +35,7 @@ public UnqualifiedIIdDeserializer(Class idClass) { public IId deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String rawValue = p.getText(); try { - return m_idCodec.get().fromUnqualified(m_idClass, rawValue); + return idCodec().fromUnqualified(m_idClass, rawValue, idCodecFlags()); } catch (RuntimeException e) { throw InvalidFormatException.from(p, "Failed to deserialize unqualified IId: " + e.getMessage(), rawValue, m_idClass); diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdMapKeyDeserializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdMapKeyDeserializer.java index 90e41fae015..8b75b3445a8 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdMapKeyDeserializer.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdMapKeyDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -12,33 +12,27 @@ import java.io.IOException; import org.eclipse.scout.rt.dataobject.id.IId; -import org.eclipse.scout.rt.dataobject.id.IdCodec; import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; -import org.eclipse.scout.rt.platform.util.LazyValue; import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.KeyDeserializer; import com.fasterxml.jackson.databind.exc.InvalidFormatException; /** * Custom deserializer used for map keys of type {@link IId}. */ -public class UnqualifiedIIdMapKeyDeserializer extends KeyDeserializer { +public class UnqualifiedIIdMapKeyDeserializer extends AbstractIdCodecMapKeyDeserializer { - protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); - - protected final ScoutDataObjectModuleContext m_moduleContext; protected final Class m_idClass; public UnqualifiedIIdMapKeyDeserializer(ScoutDataObjectModuleContext moduleContext, Class idClass) { - m_moduleContext = moduleContext; + super(moduleContext); m_idClass = idClass; } @Override public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException { try { - return m_idCodec.get().fromUnqualified(m_idClass, key); + return idCodec().fromUnqualified(m_idClass, key, idCodecFlags()); } catch (RuntimeException e) { if (m_moduleContext.isLenientMode()) { diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdMapKeySerializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdMapKeySerializer.java index 5b8995d3897..56265409efc 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdMapKeySerializer.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdMapKeySerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -12,22 +12,22 @@ import java.io.IOException; import org.eclipse.scout.rt.dataobject.id.IId; -import org.eclipse.scout.rt.dataobject.id.IdCodec; -import org.eclipse.scout.rt.platform.util.LazyValue; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; /** * Custom serializer used for map keys of type {@link IId}. */ -public class UnqualifiedIIdMapKeySerializer extends JsonSerializer { +public class UnqualifiedIIdMapKeySerializer extends AbstractIdCodecMapKeySerializer { - protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); + public UnqualifiedIIdMapKeySerializer(ScoutDataObjectModuleContext moduleContext) { + super(moduleContext); + } @Override public void serialize(IId value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - gen.writeFieldName(m_idCodec.get().toUnqualified(value)); + gen.writeFieldName(idCodec().toUnqualified(value, idCodecFlags())); } } diff --git a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdSerializer.java b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdSerializer.java index 267a031bb82..f9ca22d0094 100644 --- a/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdSerializer.java +++ b/org.eclipse.scout.rt.jackson/src/main/java/org/eclipse/scout/rt/jackson/dataobject/id/UnqualifiedIIdSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023 BSI Business Systems Integration AG + * Copyright (c) 2010, 2024 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -12,28 +12,24 @@ import java.io.IOException; import org.eclipse.scout.rt.dataobject.id.IId; -import org.eclipse.scout.rt.dataobject.id.IdCodec; -import org.eclipse.scout.rt.platform.util.LazyValue; +import org.eclipse.scout.rt.jackson.dataobject.ScoutDataObjectModuleContext; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; /** * Custom serializer for all {@link IId} instances. */ -public class UnqualifiedIIdSerializer extends StdSerializer { +public class UnqualifiedIIdSerializer extends AbstractIdCodecSerializer { private static final long serialVersionUID = 1L; - protected final LazyValue m_idCodec = new LazyValue<>(IdCodec.class); - - public UnqualifiedIIdSerializer(JavaType type) { - super(type); + public UnqualifiedIIdSerializer(ScoutDataObjectModuleContext moduleContext, JavaType type) { + super(moduleContext, type); } @Override public void serialize(IId value, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeObject(m_idCodec.get().toUnqualified(value)); + gen.writeObject(idCodec().toUnqualified(value, idCodecFlags())); } } diff --git a/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.core.resources.prefs b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..13d34f372ba --- /dev/null +++ b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,18 @@ +eclipse.preferences.version=1 +encoding//src/main/client=UTF-8 +encoding//src/main/fixture=UTF-8 +encoding//src/main/java=UTF-8 +encoding//src/main/java-jcl=UTF-8 +encoding//src/main/java-log4j=UTF-8 +encoding//src/main/java-original=UTF-8 +encoding//src/main/js=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/main/shared=UTF-8 +encoding//src/main/webapp=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/js=UTF-8 +encoding//src/test/resources=UTF-8 +encoding//target/generated-sources/annotations=UTF-8 +encoding//target/generated-sources/wsimport=UTF-8 +encoding/=UTF-8 +encoding/files=UTF-8 diff --git a/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 00000000000..5a0ad22d2a7 --- /dev/null +++ b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.apt.core.prefs b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.apt.core.prefs new file mode 100644 index 00000000000..d4313d4b25e --- /dev/null +++ b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.apt.core.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.apt.aptEnabled=false diff --git a/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..91af6f20512 --- /dev/null +++ b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,399 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.codeComplete.argumentPrefixes= +org.eclipse.jdt.core.codeComplete.argumentSuffixes= +org.eclipse.jdt.core.codeComplete.fieldPrefixes=m_ +org.eclipse.jdt.core.codeComplete.fieldSuffixes= +org.eclipse.jdt.core.codeComplete.localPrefixes= +org.eclipse.jdt.core.codeComplete.localSuffixes= +org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= +org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.processAnnotations=disabled +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=11 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_assignment=16 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true +org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=false +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=120 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=2 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=false +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true +org.eclipse.jdt.core.formatter.lineSplit=240 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=true +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=2 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.launching.prefs b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.launching.prefs new file mode 100644 index 00000000000..d211d326335 --- /dev/null +++ b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.launching.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=warning diff --git a/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..a52f8c4ad0a --- /dev/null +++ b/org.eclipse.scout.rt.rest.jersey.server/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,127 @@ +cleanup.add_default_serial_version_id=true +cleanup.add_generated_serial_version_id=false +cleanup.add_missing_annotations=true +cleanup.add_missing_deprecated_annotations=false +cleanup.add_missing_methods=false +cleanup.add_missing_nls_tags=false +cleanup.add_missing_override_annotations=true +cleanup.add_missing_override_annotations_interface_methods=true +cleanup.add_serial_version_id=false +cleanup.always_use_blocks=true +cleanup.always_use_parentheses_in_expressions=false +cleanup.always_use_this_for_non_static_field_access=false +cleanup.always_use_this_for_non_static_method_access=false +cleanup.convert_functional_interfaces=false +cleanup.convert_to_enhanced_for_loop=false +cleanup.correct_indentation=true +cleanup.format_source_code=true +cleanup.format_source_code_changes_only=false +cleanup.insert_inferred_type_arguments=false +cleanup.make_local_variable_final=true +cleanup.make_parameters_final=false +cleanup.make_private_fields_final=true +cleanup.make_type_abstract_if_missing_method=false +cleanup.make_variable_declarations_final=false +cleanup.never_use_blocks=false +cleanup.never_use_parentheses_in_expressions=true +cleanup.organize_imports=true +cleanup.qualify_static_field_accesses_with_declaring_class=false +cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false +cleanup.qualify_static_member_accesses_with_declaring_class=false +cleanup.qualify_static_method_accesses_with_declaring_class=false +cleanup.remove_private_constructors=true +cleanup.remove_redundant_type_arguments=true +cleanup.remove_trailing_whitespaces=true +cleanup.remove_trailing_whitespaces_all=true +cleanup.remove_trailing_whitespaces_ignore_empty=false +cleanup.remove_unnecessary_casts=false +cleanup.remove_unnecessary_nls_tags=false +cleanup.remove_unused_imports=true +cleanup.remove_unused_local_variables=false +cleanup.remove_unused_private_fields=true +cleanup.remove_unused_private_members=false +cleanup.remove_unused_private_methods=true +cleanup.remove_unused_private_types=true +cleanup.sort_members=false +cleanup.sort_members_all=false +cleanup.use_anonymous_class_creation=false +cleanup.use_blocks=false +cleanup.use_blocks_only_for_return_and_throw=false +cleanup.use_lambda=true +cleanup.use_parentheses_in_expressions=false +cleanup.use_this_for_non_static_field_access=false +cleanup.use_this_for_non_static_field_access_only_if_necessary=true +cleanup.use_this_for_non_static_method_access=false +cleanup.use_this_for_non_static_method_access_only_if_necessary=true +cleanup.use_type_arguments=false +cleanup_profile=_Eclipse Scout +cleanup_settings_version=2 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Eclipse Scout +formatter_settings_version=12 +org.eclipse.jdt.ui.exception.name=e +org.eclipse.jdt.ui.gettersetter.use.is=true +org.eclipse.jdt.ui.javadoc=true +org.eclipse.jdt.ui.keywordthis=false +org.eclipse.jdt.ui.overrideannotation=true +org.eclipse.jdt.ui.text.custom_code_templates=