You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2016/08/25 09:49:56 UTC

[1/4] cayenne git commit: CAY-2107 cayenne-crypto: Lazy initialization of crypto subsystem

Repository: cayenne
Updated Branches:
  refs/heads/master a5b833d5f -> aecf9aa31


CAY-2107 cayenne-crypto: Lazy initialization of crypto subsystem


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/3d96be62
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/3d96be62
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/3d96be62

Branch: refs/heads/master
Commit: 3d96be6237382993a06c35a1071403cb5bd6cad7
Parents: a5b833d
Author: Andrus Adamchik <an...@objectstyle.com>
Authored: Thu Aug 25 11:54:10 2016 +0300
Committer: Andrus Adamchik <an...@objectstyle.com>
Committed: Thu Aug 25 11:54:37 2016 +0300

----------------------------------------------------------------------
 .../cayenne/crypto/CryptoModuleBuilder.java     |  7 +++
 .../bytes/LazyBytesTransformerFactory.java      | 62 +++++++++++++++++++
 .../value/LazyValueTransformerFactory.java      | 64 ++++++++++++++++++++
 docs/doc/src/main/resources/RELEASE-NOTES.txt   |  3 +-
 4 files changed, 135 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/3d96be62/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java
index 151e320..4162409 100644
--- a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModuleBuilder.java
@@ -32,6 +32,7 @@ import org.apache.cayenne.crypto.transformer.DefaultTransformerFactory;
 import org.apache.cayenne.crypto.transformer.TransformerFactory;
 import org.apache.cayenne.crypto.transformer.bytes.BytesTransformerFactory;
 import org.apache.cayenne.crypto.transformer.bytes.DefaultBytesTransformerFactory;
+import org.apache.cayenne.crypto.transformer.bytes.LazyBytesTransformerFactory;
 import org.apache.cayenne.crypto.transformer.value.Base64StringConverter;
 import org.apache.cayenne.crypto.transformer.value.BigDecimalConverter;
 import org.apache.cayenne.crypto.transformer.value.BigIntegerConverter;
@@ -43,6 +44,7 @@ import org.apache.cayenne.crypto.transformer.value.DefaultValueTransformerFactor
 import org.apache.cayenne.crypto.transformer.value.DoubleConverter;
 import org.apache.cayenne.crypto.transformer.value.FloatConverter;
 import org.apache.cayenne.crypto.transformer.value.IntegerConverter;
+import org.apache.cayenne.crypto.transformer.value.LazyValueTransformerFactory;
 import org.apache.cayenne.crypto.transformer.value.LongConverter;
 import org.apache.cayenne.crypto.transformer.value.ShortConverter;
 import org.apache.cayenne.crypto.transformer.value.Utf8StringConverter;
@@ -380,6 +382,11 @@ public class CryptoModuleBuilder {
 
                 binder.decorate(BatchTranslatorFactory.class).before(CryptoBatchTranslatorFactoryDecorator.class);
                 binder.decorate(RowReaderFactory.class).before(CryptoRowReaderFactoryDecorator.class);
+
+                // decorate our own services to allow Cayenne to operate over plaintext entities
+                // even if crypto keys are not available.
+                binder.decorate(ValueTransformerFactory.class).after(LazyValueTransformerFactory.class);
+                binder.decorate(BytesTransformerFactory.class).after(LazyBytesTransformerFactory.class);
             }
         };
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/3d96be62/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/LazyBytesTransformerFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/LazyBytesTransformerFactory.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/LazyBytesTransformerFactory.java
new file mode 100644
index 0000000..ee7a3ad
--- /dev/null
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/bytes/LazyBytesTransformerFactory.java
@@ -0,0 +1,62 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.crypto.transformer.bytes;
+
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Provider;
+
+/**
+ * A decorator of {@link BytesTransformerFactory} that allows to defer its initialization and hence allows Cayenne stack
+ * to operate without crypto keys over a subset of entities that do not require encryption. Useful e.g. when the crypto
+ * keys are supplied at a later point after startup.
+ *
+ * @since 4.0
+ */
+public class LazyBytesTransformerFactory implements BytesTransformerFactory {
+
+    private Provider<BytesTransformerFactory> delegateProvider;
+    private volatile BytesTransformerFactory delegate;
+
+    public LazyBytesTransformerFactory(@Inject Provider<BytesTransformerFactory> delegateProvider) {
+        this.delegateProvider = delegateProvider;
+    }
+
+    @Override
+    public BytesEncryptor encryptor() {
+        return ensureInit().encryptor();
+    }
+
+    @Override
+    public BytesDecryptor decryptor() {
+        return ensureInit().decryptor();
+    }
+
+    protected BytesTransformerFactory ensureInit() {
+
+        if (delegate == null) {
+            synchronized (this) {
+                if (delegate == null) {
+                    delegate = delegateProvider.get();
+                }
+            }
+        }
+
+        return delegate;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/3d96be62/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/value/LazyValueTransformerFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/value/LazyValueTransformerFactory.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/value/LazyValueTransformerFactory.java
new file mode 100644
index 0000000..62c4529
--- /dev/null
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/value/LazyValueTransformerFactory.java
@@ -0,0 +1,64 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.crypto.transformer.value;
+
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Provider;
+import org.apache.cayenne.map.DbAttribute;
+
+/**
+ * A {@link ValueTransformerFactory} that  allows to defer its initialization and hence allows Cayenne stack
+ * to operate without cryto keys over a subset of entities that do not require encryption. Useful e.g. when the
+ * crypto keys are supplied at a later point after startup.
+ *
+ * @since 4.0
+ */
+public class LazyValueTransformerFactory implements ValueTransformerFactory {
+
+    private Provider<ValueTransformerFactory> delegateProvider;
+    private volatile ValueTransformerFactory delegate;
+
+    public LazyValueTransformerFactory(@Inject Provider<ValueTransformerFactory> delegateProvider) {
+        this.delegateProvider = delegateProvider;
+    }
+
+    @Override
+    public ValueEncryptor encryptor(DbAttribute a) {
+        return ensureInit().encryptor(a);
+    }
+
+    @Override
+    public ValueDecryptor decryptor(DbAttribute a) {
+        return ensureInit().decryptor(a);
+    }
+
+    protected ValueTransformerFactory ensureInit() {
+
+        if (delegate == null) {
+            synchronized (this) {
+                if (delegate == null) {
+                    delegate = delegateProvider.get();
+                }
+            }
+        }
+
+        return delegate;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/3d96be62/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index cd3d28a..e65f57c 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -27,7 +27,8 @@ CAY-2090 Untangle HttpRemoteService from ServiceContext thread local setup
 CAY-2100 Add supporting generated keys for PostgreSQL
 CAY-2102 EJBQL: db: path not supported in select columns
 CAY-2103 cayenne-crypto: support for mapping non-String and non-binary types
-CAY-2106: cayenne-crypto: allow DI contribution of type converters inside ValueTransformerFactory
+CAY-2106 cayenne-crypto: allow DI contribution of type converters inside ValueTransformerFactory
+CAY-2107 cayenne-crypto: Lazy initialization of crypto subsystem
 
 Bug Fixes:
 


[3/4] cayenne git commit: CAY-2107 cayenne-crypto: Lazy initialization of crypto subsystem

Posted by aa...@apache.org.
CAY-2107 cayenne-crypto: Lazy initialization of crypto subsystem


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/37c7e0fb
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/37c7e0fb
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/37c7e0fb

Branch: refs/heads/master
Commit: 37c7e0fbd382456acb361c1f49fe7fbc3ee3323d
Parents: 023d5f1
Author: Andrus Adamchik <an...@objectstyle.com>
Authored: Thu Aug 25 12:45:36 2016 +0300
Committer: Andrus Adamchik <an...@objectstyle.com>
Committed: Thu Aug 25 12:45:36 2016 +0300

----------------------------------------------------------------------
 .../cayenne/crypto/Runtime_AES128_Base.java     |  39 ++++--
 .../cayenne/crypto/Runtime_LazyInit_IT.java     | 139 +++++++++++++++++++
 .../org/apache/cayenne/crypto/db/Table4.java    |   9 ++
 .../apache/cayenne/crypto/db/auto/_Table4.java  |  36 +++++
 .../src/test/resources/datamap.map.xml          |   9 ++
 5 files changed, 220 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/37c7e0fb/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_Base.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_Base.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_Base.java
index 8703c4a..4b5774c 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_Base.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_Base.java
@@ -25,29 +25,24 @@ import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 
 import java.net.URL;
+import java.sql.SQLException;
 
 public class Runtime_AES128_Base {
 
     protected ServerRuntime runtime;
     protected TableHelper table1;
     protected TableHelper table2;
+    protected TableHelper table4;
 
     protected void setUp(boolean compress) throws Exception {
 
-        URL keyStoreUrl = JceksKeySourceTest.class.getResource(JceksKeySourceTest.KS1_JCEKS);
-
-        CryptoModuleBuilder builder = new CryptoModuleBuilder().keyStore(keyStoreUrl, JceksKeySourceTest.TEST_KEY_PASS,
-                "k3");
-
-        if (compress) {
-            builder.compress();
-        }
-
-        Module crypto = builder.build();
+        Module crypto = createCryptoModule(compress);
+        this.runtime = createRuntime(crypto);
 
-        this.runtime = new ServerRuntime("cayenne-crypto.xml", crypto);
+        setupTestTables(new DBHelper(runtime.getDataSource(null)));
+    }
 
-        DBHelper dbHelper = new DBHelper(runtime.getDataSource(null));
+    protected void setupTestTables(DBHelper dbHelper) throws SQLException {
 
         this.table2 = new TableHelper(dbHelper, "TABLE2").setColumns("ID", "PLAIN_BYTES", "CRYPTO_BYTES");
         table2.deleteAll();
@@ -55,6 +50,26 @@ public class Runtime_AES128_Base {
         this.table1 = new TableHelper(dbHelper, "TABLE1").setColumns("ID", "PLAIN_STRING", "CRYPTO_STRING",
                 "PLAIN_INT", "CRYPTO_INT");
         table1.deleteAll();
+
+        this.table4 = new TableHelper(dbHelper, "TABLE4").setColumns("ID", "PLAIN_STRING", "PLAIN_INT");
+        table4.deleteAll();
+    }
+
+    protected ServerRuntime createRuntime(Module crypto) {
+        return new ServerRuntime("cayenne-crypto.xml", crypto);
+    }
+
+    protected Module createCryptoModule(boolean compress) {
+        URL keyStoreUrl = JceksKeySourceTest.class.getResource(JceksKeySourceTest.KS1_JCEKS);
+
+        CryptoModuleBuilder builder = new CryptoModuleBuilder().keyStore(keyStoreUrl, JceksKeySourceTest.TEST_KEY_PASS,
+                "k3");
+
+        if (compress) {
+            builder.compress();
+        }
+
+        return builder.build();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/37c7e0fb/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_LazyInit_IT.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_LazyInit_IT.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_LazyInit_IT.java
new file mode 100644
index 0000000..bf79489
--- /dev/null
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_LazyInit_IT.java
@@ -0,0 +1,139 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.crypto;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.crypto.db.Table1;
+import org.apache.cayenne.crypto.db.Table4;
+import org.apache.cayenne.crypto.key.KeySource;
+import org.apache.cayenne.di.Binder;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Module;
+import org.apache.cayenne.query.ObjectSelect;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.security.Key;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+public class Runtime_LazyInit_IT extends Runtime_AES128_Base {
+
+
+    protected static boolean UNLOCKED;
+
+    @Before
+    public void before() throws Exception {
+        setUp(false);
+        UNLOCKED = false;
+    }
+
+    @Override
+    protected ServerRuntime createRuntime(final Module crypto) {
+        Module cryptoWrapper = new Module() {
+            @Override
+            public void configure(Binder binder) {
+
+                crypto.configure(binder);
+
+                binder.decorate(KeySource.class).after(LockingKeySourceDecorator.class);
+            }
+        };
+
+        return super.createRuntime(cryptoWrapper);
+    }
+
+    @Test
+    public void testCryptoLocked() {
+
+        assertFalse(UNLOCKED);
+
+        Table4 t4 = runtime.newContext().newObject(Table4.class);
+        t4.setPlainInt(56);
+        t4.setPlainString("XX");
+        t4.getObjectContext().commitChanges();
+
+        assertEquals(t4.getObjectId(), ObjectSelect.query(Table4.class).selectOne(runtime.newContext()).getObjectId());
+    }
+
+    @Test
+    public void testCryptoLocked_Unlocked() {
+
+
+        assertFalse(UNLOCKED);
+
+        try {
+            Table1 t1 = runtime.newContext().newObject(Table1.class);
+            t1.setPlainInt(56);
+            t1.setCryptoInt(77);
+            t1.setPlainString("XX");
+            t1.setCryptoString("YY");
+            t1.getObjectContext().commitChanges();
+
+            fail("Must have thrown on crypto access");
+        } catch (CayenneRuntimeException e) {
+            // expected
+        }
+
+        UNLOCKED = true;
+
+        Table1 t1 = runtime.newContext().newObject(Table1.class);
+        t1.setPlainInt(56);
+        t1.setCryptoInt(77);
+        t1.setPlainString("XX");
+        t1.setCryptoString("YY");
+        t1.getObjectContext().commitChanges();
+
+        assertEquals(t1.getObjectId(), ObjectSelect.query(Table1.class).selectOne(runtime.newContext()).getObjectId());
+
+    }
+
+
+    public static class LockingKeySourceDecorator implements KeySource {
+
+        private KeySource keySource;
+
+        public LockingKeySourceDecorator(@Inject KeySource keySource) {
+            this.keySource = keySource;
+        }
+
+        @Override
+        public Key getKey(String alias) {
+            return ensureKeySource().getKey(alias);
+        }
+
+        @Override
+        public String getDefaultKeyAlias() {
+            return ensureKeySource().getDefaultKeyAlias();
+        }
+
+        private KeySource ensureKeySource() {
+
+            if (!UNLOCKED) {
+                throw new IllegalStateException("Crypto is locked");
+            }
+
+            return keySource;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/37c7e0fb/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table4.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table4.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table4.java
new file mode 100644
index 0000000..89ffe67
--- /dev/null
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table4.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.crypto.db;
+
+import org.apache.cayenne.crypto.db.auto._Table4;
+
+public class Table4 extends _Table4 {
+
+    private static final long serialVersionUID = 1L; 
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/37c7e0fb/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table4.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table4.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table4.java
new file mode 100644
index 0000000..3f825bc
--- /dev/null
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table4.java
@@ -0,0 +1,36 @@
+package org.apache.cayenne.crypto.db.auto;
+
+import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.exp.Property;
+
+/**
+ * Class _Table4 was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _Table4 extends CayenneDataObject {
+
+    private static final long serialVersionUID = 1L; 
+
+    public static final String ID_PK_COLUMN = "ID";
+
+    public static final Property<Integer> PLAIN_INT = new Property<Integer>("plainInt");
+    public static final Property<String> PLAIN_STRING = new Property<String>("plainString");
+
+    public void setPlainInt(int plainInt) {
+        writeProperty("plainInt", plainInt);
+    }
+    public int getPlainInt() {
+        Object value = readProperty("plainInt");
+        return (value != null) ? (Integer) value : 0;
+    }
+
+    public void setPlainString(String plainString) {
+        writeProperty("plainString", plainString);
+    }
+    public String getPlainString() {
+        return (String)readProperty("plainString");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/37c7e0fb/cayenne-crypto/src/test/resources/datamap.map.xml
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/resources/datamap.map.xml b/cayenne-crypto/src/test/resources/datamap.map.xml
index 2ea6a80..b71de41 100644
--- a/cayenne-crypto/src/test/resources/datamap.map.xml
+++ b/cayenne-crypto/src/test/resources/datamap.map.xml
@@ -20,6 +20,11 @@
 		<db-attribute name="CRYPTO_BYTES" type="VARBINARY"/>
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 	</db-entity>
+	<db-entity name="TABLE4">
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="PLAIN_INT" type="INTEGER"/>
+		<db-attribute name="PLAIN_STRING" type="VARCHAR" length="200"/>
+	</db-entity>
 	<obj-entity name="Table1" className="org.apache.cayenne.crypto.db.Table1" dbEntityName="TABLE1">
 		<obj-attribute name="cryptoInt" type="int" db-attribute-path="CRYPTO_INT"/>
 		<obj-attribute name="cryptoString" type="java.lang.String" db-attribute-path="CRYPTO_STRING"/>
@@ -33,4 +38,8 @@
 	<obj-entity name="Table3" className="org.apache.cayenne.crypto.db.Table3" dbEntityName="TABLE3">
 		<obj-attribute name="cryptoString" type="java.lang.String" db-attribute-path="CRYPTO_BYTES"/>
 	</obj-entity>
+	<obj-entity name="Table4" className="org.apache.cayenne.crypto.db.Table4" dbEntityName="TABLE4">
+		<obj-attribute name="plainInt" type="int" db-attribute-path="PLAIN_INT"/>
+		<obj-attribute name="plainString" type="java.lang.String" db-attribute-path="PLAIN_STRING"/>
+	</obj-entity>
 </data-map>


[4/4] cayenne git commit: CAY-2108 cayenne-di: StackOverflow for decorator that takes Provider of the delegate

Posted by aa...@apache.org.
CAY-2108 cayenne-di: StackOverflow for decorator that takes Provider of the delegate


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/aecf9aa3
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/aecf9aa3
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/aecf9aa3

Branch: refs/heads/master
Commit: aecf9aa318484ecc1e349c00f717add94accb9f8
Parents: 37c7e0f
Author: Andrus Adamchik <an...@objectstyle.com>
Authored: Thu Aug 25 12:46:26 2016 +0300
Committer: Andrus Adamchik <an...@objectstyle.com>
Committed: Thu Aug 25 12:46:26 2016 +0300

----------------------------------------------------------------------
 docs/doc/src/main/resources/RELEASE-NOTES.txt | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/aecf9aa3/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index e65f57c..1d302c8 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -45,6 +45,7 @@ CAY-2089 HTTP connections aren't always closed in new ROP implementation
 CAY-2097 NullPointerException while updating relationships for entities with vertical inheritance
 CAY-2101 DataContext.currentSnapshot() doesn't set snapshot entity name
 CAY-2105 Add missing elements to the reverseEngineering.xsd
+CAY-2108 cayenne-di: StackOverflow for decorator that takes Provider of the delegate
 
 ----------------------------------
 Release: 4.0.M3


[2/4] cayenne git commit: CAY-2108 cayenne-di: StackOverflow for decorator that takes Provider of the delegate

Posted by aa...@apache.org.
CAY-2108 cayenne-di: StackOverflow for decorator that takes Provider of the delegate


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/023d5f18
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/023d5f18
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/023d5f18

Branch: refs/heads/master
Commit: 023d5f18f8fb97f66b23bc13accf015c6d4f11b4
Parents: 3d96be6
Author: Andrus Adamchik <an...@objectstyle.com>
Authored: Thu Aug 25 12:38:06 2016 +0300
Committer: Andrus Adamchik <an...@objectstyle.com>
Committed: Thu Aug 25 12:43:59 2016 +0300

----------------------------------------------------------------------
 .../ConstructorInjectingDecoratorProvider.java  | 21 +++++++++--
 .../di/spi/FieldInjectingDecoratorProvider.java | 23 ++++++++++--
 .../di/mock/MockInterface1_Decorator4.java      | 36 ++++++++++++++++++
 .../di/mock/MockInterface1_Decorator5.java      | 33 +++++++++++++++++
 .../di/spi/DefaultInjectorDecorationTest.java   | 39 ++++++++++++++++++++
 5 files changed, 146 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/023d5f18/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingDecoratorProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingDecoratorProvider.java b/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingDecoratorProvider.java
index 4ad974f..a235847 100644
--- a/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingDecoratorProvider.java
+++ b/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingDecoratorProvider.java
@@ -18,11 +18,11 @@
  ****************************************************************/
 package org.apache.cayenne.di.spi;
 
-import java.lang.reflect.Type;
-
 import org.apache.cayenne.di.DIRuntimeException;
 import org.apache.cayenne.di.Provider;
 
+import java.lang.reflect.Type;
+
 /**
  * @since 4.0
  */
@@ -43,7 +43,22 @@ public class ConstructorInjectingDecoratorProvider<T> implements DecoratorProvid
             @Override
             protected Object value(Class<?> parameter, Type genericType, String bindingName, InjectionStack stack) {
 
-                if (parameter.isAssignableFrom(implementation)) {
+                // delegate (possibly) injected as Provider
+                if (Provider.class.equals(parameter)) {
+
+                    Class<?> objectClass = DIUtil.parameterClass(genericType);
+
+                    if (objectClass == null) {
+                        throw new DIRuntimeException("Constructor provider parameter %s must be "
+                                + "parameterized to be usable for injection", parameter.getName());
+                    }
+
+                    if(objectClass.isAssignableFrom(implementation)) {
+                        return undecorated;
+                    }
+                }
+                // delegate injected as value
+                else if (parameter.isAssignableFrom(implementation)) {
                     return undecorated.get();
                 }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/023d5f18/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingDecoratorProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingDecoratorProvider.java b/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingDecoratorProvider.java
index e6c072b..6cbbad0 100644
--- a/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingDecoratorProvider.java
+++ b/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingDecoratorProvider.java
@@ -18,11 +18,11 @@
  ****************************************************************/
 package org.apache.cayenne.di.spi;
 
-import java.lang.reflect.Field;
-
 import org.apache.cayenne.di.DIRuntimeException;
 import org.apache.cayenne.di.Provider;
 
+import java.lang.reflect.Field;
+
 /**
  * @since 4.0
  */
@@ -45,7 +45,24 @@ class FieldInjectingDecoratorProvider<T> implements DecoratorProvider<T> {
 
             @Override
             protected Object value(Field field, String bindingName) {
-                if (field.getType().isAssignableFrom(implementation)) {
+                Class<?> fieldType = field.getType();
+
+                // delegate (possibly) injected as Provider
+                if (Provider.class.equals(fieldType)) {
+
+                    Class<?> objectClass = DIUtil.parameterClass(field.getGenericType());
+
+                    if (objectClass == null) {
+                        throw new DIRuntimeException("Provider field %s.%s of type %s must be "
+                                + "parameterized to be usable for injection", field.getDeclaringClass().getName(),
+                                field.getName(), fieldType.getName());
+                    }
+
+                    if(objectClass.isAssignableFrom(implementation)) {
+                        return undecorated;
+                    }
+                }
+                else if (fieldType.isAssignableFrom(implementation)) {
                     return undecorated.get();
                 }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/023d5f18/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator4.java
----------------------------------------------------------------------
diff --git a/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator4.java b/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator4.java
new file mode 100644
index 0000000..d30f358
--- /dev/null
+++ b/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator4.java
@@ -0,0 +1,36 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.di.mock;
+
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Provider;
+
+public class MockInterface1_Decorator4 implements MockInterface1 {
+
+    private Provider<MockInterface1> delegate;
+
+    public MockInterface1_Decorator4(@Inject Provider<MockInterface1> delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public String getName() {
+        return "[4" + delegate.get().getName() + "4]";
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/023d5f18/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator5.java
----------------------------------------------------------------------
diff --git a/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator5.java b/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator5.java
new file mode 100644
index 0000000..0b3cd35
--- /dev/null
+++ b/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator5.java
@@ -0,0 +1,33 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.di.mock;
+
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Provider;
+
+public class MockInterface1_Decorator5 implements MockInterface1 {
+
+    @Inject
+    private Provider<MockInterface1> delegate;
+
+    @Override
+    public String getName() {
+        return "[5" + delegate.get().getName() + "5]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/023d5f18/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorDecorationTest.java
----------------------------------------------------------------------
diff --git a/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorDecorationTest.java b/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorDecorationTest.java
index 266ade2..dfe34ff 100644
--- a/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorDecorationTest.java
+++ b/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorDecorationTest.java
@@ -25,6 +25,8 @@ import org.apache.cayenne.di.mock.MockInterface1;
 import org.apache.cayenne.di.mock.MockInterface1_Decorator1;
 import org.apache.cayenne.di.mock.MockInterface1_Decorator2;
 import org.apache.cayenne.di.mock.MockInterface1_Decorator3;
+import org.apache.cayenne.di.mock.MockInterface1_Decorator4;
+import org.apache.cayenne.di.mock.MockInterface1_Decorator5;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
@@ -92,4 +94,41 @@ public class DefaultInjectorDecorationTest {
         assertEquals("<[{MyName}]>", service.getName());
     }
 
+    @Test
+    public void testSingleDecorator_Provider_ConstructorInjection() {
+
+        Module module = new Module() {
+
+            @Override
+            public void configure(Binder binder) {
+                binder.bind(MockInterface1.class).to(MockImplementation1.class);
+                binder.decorate(MockInterface1.class).before(MockInterface1_Decorator4.class);
+            }
+        };
+
+        DefaultInjector injector = new DefaultInjector(module);
+
+        MockInterface1 service = injector.getInstance(MockInterface1.class);
+        assertNotNull(service);
+        assertEquals("[4MyName4]", service.getName());
+    }
+
+    @Test
+    public void testSingleDecorator_Provider_FieldInjection() {
+
+        Module module = new Module() {
+
+            @Override
+            public void configure(Binder binder) {
+                binder.bind(MockInterface1.class).to(MockImplementation1.class);
+                binder.decorate(MockInterface1.class).before(MockInterface1_Decorator5.class);
+            }
+        };
+
+        DefaultInjector injector = new DefaultInjector(module);
+
+        MockInterface1 service = injector.getInstance(MockInterface1.class);
+        assertNotNull(service);
+        assertEquals("[5MyName5]", service.getName());
+    }
 }