[java-shib-attribute] 04/05: JSATTR-41 Look to make the ScriptedDataConnector Cached
Rod Widdowson
rdw at steadingsoftware.com
Mon Jan 20 11:45:47 UTC 2025
This is an automated email from the git hooks/post-receive script.
rdw pushed a commit to branch main
in repository java-shib-attribute.
View the commit online:
http://git.shibboleth.net/view/?p=java-shib-attribute.git;a=commit;h=d9db4fc06d77045a6445166615a570cc31b2b4f5
commit d9db4fc06d77045a6445166615a570cc31b2b4f5
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Sat Jan 18 16:21:53 2025 +0000
JSATTR-41 Look to make the ScriptedDataConnector Cached
https://shibboleth.atlassian.net/browse/JSATTR-41
Add tests for the caching bit.
---
.../dc/scripted/impl/ScriptedDataConnector.java | 1 -
.../dc/impl/ScriptedDataConnectorTest.java | 94 ----------
.../scripted/impl/ScriptedDataConnectorTest.java | 191 +++++++++++++++++++++
.../idp/attribute/resolver/impl/dc/cache.js | 1 +
.../dc/impl/ScriptedDataConnectorParser.java | 4 +
5 files changed, 196 insertions(+), 95 deletions(-)
diff --git a/shib-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/scripted/impl/ScriptedDataConnector.java b/shib-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/scripted/impl/ScriptedDataConnector.java
index 88f8b2386..ee03c4fa6 100644
--- a/shib-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/scripted/impl/ScriptedDataConnector.java
+++ b/shib-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/scripted/impl/ScriptedDataConnector.java
@@ -80,7 +80,6 @@ public class ScriptedDataConnector extends AbstractSearchDataConnector<ScriptedS
contextExtenders = CollectionSupport.emptyList();
setValidator(new NullValidator());
setMappingStrategy(new ScriptedMappingStrategy());
- setExecutableSearchBuilder(new ScriptedSearchBuilder());
}
/**
diff --git a/shib-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/ScriptedDataConnectorTest.java b/shib-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/ScriptedDataConnectorTest.java
deleted file mode 100644
index 47110a925..000000000
--- a/shib-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/ScriptedDataConnectorTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.idp.attribute.resolver.dc.impl;
-
-import static org.testng.Assert.assertEquals;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-import javax.script.ScriptException;
-
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.testng.annotations.Test;
-
-import net.shibboleth.idp.attribute.IdPAttribute;
-import net.shibboleth.idp.attribute.IdPAttributeValue;
-import net.shibboleth.idp.attribute.StringAttributeValue;
-import net.shibboleth.idp.attribute.resolver.ResolutionException;
-import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
-import net.shibboleth.idp.attribute.resolver.context.AttributeResolverWorkContext;
-import net.shibboleth.idp.attribute.resolver.dc.scripted.impl.ScriptedDataConnector;
-import net.shibboleth.shared.collection.CollectionSupport;
-import net.shibboleth.shared.component.ComponentInitializationException;
-import net.shibboleth.shared.scripting.EvaluableScript;
-
-/**
- * Tests for {@link ScriptedDataConnector}
- *
- */
- at SuppressWarnings("javadoc")
-public class ScriptedDataConnectorTest {
-
- @Nonnull private EvaluableScript getScript(String fileName) throws IOException, ComponentInitializationException {
- final String name = "/net/shibboleth/idp/attribute/resolver/impl/dc/" + fileName;
- final EvaluableScript es = new EvaluableScript();
- es.setEngineName("javascript");
- final InputStream is = getClass().getResourceAsStream(name);
- assert is != null;
- es.setScript(is);
- es.initialize();
- return es;
- }
-
- @Test(expectedExceptions=ResolutionException.class)
- public void error() throws ComponentInitializationException, ScriptException, IOException, ResolutionException {
- final ScriptedDataConnector connector = new ScriptedDataConnector();
- connector.setId("Scripted");
- connector.setScript(getScript("error.js"));
-
- connector.initialize();
-
- final AttributeResolutionContext context = new ProfileRequestContext().ensureSubcontext(AttributeResolutionContext.class);
- context.ensureSubcontext(AttributeResolverWorkContext.class);
-
- connector.resolve(context);
- }
-
- @Test public void custom() throws ComponentInitializationException, ResolutionException, ScriptException, IOException {
-
- final ScriptedDataConnector connector = new ScriptedDataConnector();
- connector.setId("Scripted");
-
- final IdPAttribute attribute = new IdPAttribute("attr");
- attribute.setValues(CollectionSupport.singletonList((IdPAttributeValue)new StringAttributeValue("bar")));
- connector.setCustomObject(attribute);
-
- connector.setScript(getScript("custom.js"));
-
- connector.initialize();
-
- final AttributeResolutionContext context = new ProfileRequestContext().ensureSubcontext(AttributeResolutionContext.class);
- context.ensureSubcontext(AttributeResolverWorkContext.class);
- final Map<String, IdPAttribute> result = connector.resolve(context);
- assert result != null;
-
- assertEquals(result.size(), 1);
- assertEquals(result.get(attribute.getId()),attribute);
- }
-
-}
\ No newline at end of file
diff --git a/shib-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/scripted/impl/ScriptedDataConnectorTest.java b/shib-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/scripted/impl/ScriptedDataConnectorTest.java
new file mode 100644
index 000000000..b031f00c0
--- /dev/null
+++ b/shib-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/scripted/impl/ScriptedDataConnectorTest.java
@@ -0,0 +1,191 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.attribute.resolver.dc.scripted.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.script.ScriptException;
+
+import org.opensaml.messaging.context.BaseContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.StringAttributeValue;
+import net.shibboleth.idp.attribute.resolver.ResolutionException;
+import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
+import net.shibboleth.idp.attribute.resolver.context.AttributeResolverWorkContext;
+import net.shibboleth.idp.attribute.resolver.dc.impl.TestCache;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.scripting.EvaluableScript;
+import net.shibboleth.shared.testing.VelocityEngine;
+
+/**
+ * Tests for {@link ScriptedDataConnector}.
+ */
+ at SuppressWarnings("javadoc")
+public class ScriptedDataConnectorTest {
+
+ @Nonnull private EvaluableScript getScript(String fileName) throws IOException, ComponentInitializationException {
+ final String name = "/net/shibboleth/idp/attribute/resolver/impl/dc/" + fileName;
+ final EvaluableScript es = new EvaluableScript();
+ es.setEngineName("javascript");
+ final InputStream is = getClass().getResourceAsStream(name);
+ assert is != null;
+ es.setScript(is);
+ es.initialize();
+ return es;
+ }
+
+ @Test(expectedExceptions=ResolutionException.class)
+ public void error() throws ComponentInitializationException, ScriptException, IOException, ResolutionException {
+ final ScriptedDataConnector connector = new ScriptedDataConnector();
+ connector.setId("Scripted");
+ connector.setScript(getScript("error.js"));
+ connector.setExecutableSearchBuilder(new ScriptedSearchBuilder());
+ connector.initialize();
+
+ final AttributeResolutionContext context = new ProfileRequestContext().ensureSubcontext(AttributeResolutionContext.class);
+ context.ensureSubcontext(AttributeResolverWorkContext.class);
+
+ connector.resolve(context);
+ }
+
+ @Test public void custom() throws ComponentInitializationException, ResolutionException, ScriptException, IOException {
+
+ final ScriptedDataConnector connector = new ScriptedDataConnector();
+ connector.setId("Scripted");
+
+ final IdPAttribute attribute = new IdPAttribute("attr");
+ attribute.setValues(CollectionSupport.singletonList((IdPAttributeValue)new StringAttributeValue("bar")));
+ connector.setCustomObject(attribute);
+
+ connector.setScript(getScript("custom.js"));
+ connector.setExecutableSearchBuilder(new ScriptedSearchBuilder());
+ connector.initialize();
+
+ final AttributeResolutionContext context = new ProfileRequestContext().ensureSubcontext(AttributeResolutionContext.class);
+ context.ensureSubcontext(AttributeResolverWorkContext.class);
+ final Map<String, IdPAttribute> result = connector.resolve(context);
+ assert result != null;
+
+ assertEquals(result.size(), 1);
+ assertEquals(result.get(attribute.getId()),attribute);
+ }
+
+ private int callCount; // used for cache hit/miss
+
+ @Test public void cache() throws ComponentInitializationException, ResolutionException, ScriptException, IOException {
+
+ final ScriptedDataConnector connector = new ScriptedDataConnector();
+ connector.setId("Scripted");
+
+ final IdPAttribute attribute = new IdPAttribute("attr");
+ attribute.setValues(CollectionSupport.singletonList((IdPAttributeValue)new StringAttributeValue("bar")));
+
+ Function<Object, IdPAttribute> fn = new Function<Object, IdPAttribute>() {
+ @Override
+ public IdPAttribute apply(Object t) {
+ ScriptedDataConnectorTest.this.callCount++;
+ return attribute;
+ }
+ };
+
+ connector.setCustomObject(fn);
+
+ final TestCache cache = new TestCache();
+ connector.setResultsCache(cache);
+ connector.setScript(getScript("cache.js"));
+ final ScriptedSearchBuilder builder = new ScriptedSearchBuilder();
+ builder.setVelocityEngine(VelocityEngine.newVelocityEngine());
+
+ builder.setCacheKeyTemplateText("${resolutionContext.getSubcontext(\"" + MyCacheKeyContextContext.class.getName() + "\")}");
+ builder.initialize();
+
+ connector.setExecutableSearchBuilder(builder);
+ connector.initialize();
+
+ AttributeResolutionContext context = new ProfileRequestContext().ensureSubcontext(AttributeResolutionContext.class);
+ context.setResolvedIdPAttributes(CollectionSupport.singleton(attribute));
+ context.ensureSubcontext(AttributeResolverWorkContext.class);
+ context.addSubcontext(new MyCacheKeyContextContext("1"));
+ callCount = 0;
+ assertTrue(cache.size() == 0);
+ Map<String, IdPAttribute> result = connector.resolve(context);
+ assert result != null;
+ assertEquals(result.size(), 1);
+ assertEquals(result.get(attribute.getId()),attribute);
+
+ assertTrue(cache.size() == 1);
+ assertEquals(cache.iterator().next(), result);
+
+ assertEquals(callCount, 1);
+
+ //
+ // And go again checking for a cache hit
+ //
+ context = new ProfileRequestContext().ensureSubcontext(AttributeResolutionContext.class);
+ context.ensureSubcontext(AttributeResolverWorkContext.class);
+ context.addSubcontext(new MyCacheKeyContextContext("1"));
+ callCount = 0;
+
+ assertTrue(cache.size() == 1);
+ result = connector.resolve(context);
+ assert result != null;
+ assertEquals(result.size(), 1);
+ assertEquals(result.get(attribute.getId()),attribute);
+
+ assertTrue(cache.size() == 1);
+ assertEquals(cache.iterator().next(), result);
+
+ assertEquals(callCount, 0);
+
+ //
+ // And again - cache miss
+ //
+ context = new ProfileRequestContext().ensureSubcontext(AttributeResolutionContext.class);
+ context.ensureSubcontext(AttributeResolverWorkContext.class);
+ context.addSubcontext(new MyCacheKeyContextContext("2"));
+ callCount = 0;
+ assertTrue(cache.size() == 1);
+ result = connector.resolve(context);
+ assert result != null;
+ assertEquals(result.size(), 1);
+ assertEquals(result.get(attribute.getId()),attribute);
+
+ assertTrue(cache.size() == 2);
+ assertEquals(callCount, 1);
+ }
+
+ /** Silly little class whose only reason is to inject a cacheKey.*/
+ private class MyCacheKeyContextContext extends BaseContext {
+ private final String key;
+ public MyCacheKeyContextContext(String parm) {
+ key = parm;
+ }
+ public String toString() {
+ return key;
+ }
+ }
+}
diff --git a/shib-attribute-resolver-impl/src/test/resources/net/shibboleth/idp/attribute/resolver/impl/dc/cache.js b/shib-attribute-resolver-impl/src/test/resources/net/shibboleth/idp/attribute/resolver/impl/dc/cache.js
new file mode 100644
index 000000000..a2affa0b5
--- /dev/null
+++ b/shib-attribute-resolver-impl/src/test/resources/net/shibboleth/idp/attribute/resolver/impl/dc/cache.js
@@ -0,0 +1 @@
+connectorResults.add(custom.apply(1));
diff --git a/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ScriptedDataConnectorParser.java b/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ScriptedDataConnectorParser.java
index a62c225a1..52c4c9524 100644
--- a/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ScriptedDataConnectorParser.java
+++ b/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ScriptedDataConnectorParser.java
@@ -27,6 +27,7 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
import net.shibboleth.idp.attribute.resolver.dc.scripted.impl.ScriptedDataConnector;
+import net.shibboleth.idp.attribute.resolver.dc.scripted.impl.ScriptedSearchBuilder;
import net.shibboleth.idp.attribute.resolver.spring.dc.AbstractDataConnectorParser;
import net.shibboleth.idp.attribute.resolver.spring.impl.AttributeResolverNamespaceHandler;
import net.shibboleth.shared.primitive.LoggerFactory;
@@ -109,6 +110,9 @@ public class ScriptedDataConnectorParser extends AbstractDataConnectorParser {
}
builder.addPropertyValue("script", scriptBuilder.getBeanDefinition());
+ final BeanDefinitionBuilder searchBuilder =
+ BeanDefinitionBuilder.genericBeanDefinition(ScriptedSearchBuilder.class);
+ builder.addPropertyValue("executableSearchBuilder", searchBuilder.getBeanDefinition());
}
// Checkstyle: CyclomaticComplexity ON
}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list