/* * Copyright (c) 2002-2012 Alibaba Group Holding Limited. * All rights reserved. * * 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 com.alibaba.citrus.service.pull.impl; import static com.alibaba.citrus.test.TestUtil.*; import static com.alibaba.citrus.util.BasicConstant.*; import static com.alibaba.citrus.util.CollectionUtil.*; import static java.util.Collections.*; import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import com.alibaba.citrus.service.pull.PullContext; import com.alibaba.citrus.service.pull.PullException; import com.alibaba.citrus.service.pull.PullService; import com.alibaba.citrus.service.pull.RuntimeToolSetFactory; import com.alibaba.citrus.service.pull.ToolFactory; import com.alibaba.citrus.service.pull.ToolNameAware; import com.alibaba.citrus.service.pull.ToolSetFactory; import com.alibaba.citrus.service.pull.impl.PullServiceImpl.ToolName; import com.alibaba.citrus.service.pull.impl.PullServiceImpl.ToolSetInfo; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; public class PullServiceTests extends AbstractPullServiceTests { private PullContext context; private String[] staticToolNames; private String[] allNames; private String[] allValues; private String[] allNamesWithParent; private String[] allValuesWithParent; // service instance vars private Map<String, ToolFactory> tools; private Map<String, ToolSetInfo<ToolSetFactory>> toolsInSet; private Map<String, RuntimeToolSetFactory> toolsRuntime; private Map<String, Object> prePulledTools; private Set<ToolName> toolNames; // context instance vars private Map<String, Object> context_pulledTools; private Map<String, RuntimeToolSetFactory> context_toolsRuntime; private Map<String, ToolSetInfo<RuntimeToolSetFactory>> context_toolsInRuntimeSet; private Set<ToolName> context_toolNames; @Before public void init() { populateService(); initService(); } private void populateService() { Map<String, Object> factories = createHashMap(); // -------------- // singleton // -------------- // - ToolFactory factories.put("singleton.1", newToolFactory(true, "singleton.1")); factories.put("singleton.2", newToolFactory(true, null)); // - ToolSetFactory factories.put("singletons.1", newToolSetFactory(true, false, "singletons.1", "a", "1", "b", "2")); factories.put("singletons.2", newToolSetFactory(true, false, null, "c", "3", "d", null)); // - ToolSetFactory & ToolFactory factories.put("singletons.3", newToolSetFactory(true, true, "singletons.3", "e", "5", "f", "6")); factories.put("singletons.4", newToolSetFactory(true, true, null, "g", "7", "h", null)); // -------------- // non-singleton // -------------- // - ToolFactory factories.put("prototype.1", newToolFactory(false, "prototype.1")); factories.put("prototype.2", newToolFactory(false, null)); // - ToolSetFactory factories.put("prototypes.1", newToolSetFactory(false, false, "prototypes.1", "i", "9", "j", "10")); factories.put("prototypes.2", newToolSetFactory(false, false, null, "k", "11", "l", null)); // - ToolSetFactory & ToolFactory factories.put("prototypes.3", newToolSetFactory(false, true, "prototypes.3", "m", "13", "n", "14")); factories.put("prototypes.4", newToolSetFactory(false, true, null, "o", "15", "p", null)); // - RuntimeToolSetFactory factories.put("runtime.1", newRuntimeToolSetFactory(false, false, "runtime.1", "q", "17", "r", "18")); factories.put("runtime.2", newRuntimeToolSetFactory(false, false, null, "s", "19", "t", null)); // - RuntimeToolSetFactory & ToolFactory factories.put("runtime.3", newRuntimeToolSetFactory(false, true, "runtime.3", "u", "21", "v", "22")); factories.put("runtime.4", newRuntimeToolSetFactory(false, true, null, "w", "23", "x", null)); service.setToolFactories(factories); staticToolNames = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "prototype.1", "prototype.2", "prototypes.3", "prototypes.4", "runtime.3", "runtime.4", "singleton.1", "singleton.2", "singletons.3", "singletons.4" }; // all names and values including runtime tools allNames = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "prototype.1", "prototype.2", "prototypes.3", "prototypes.4", "q", "r", "runtime.3", "runtime.4", "s", "singleton.1", "singleton.2", "singletons.3", "singletons.4", "t", "u", "v", "w", "x" }; allValues = new String[] { "1", "2", "3", null, "5", "6", "7", null, "9", "10", "11", null, "13", "14", "15", null, "prototype.1", null, "prototypes.3", null, "17", "18", "runtime.3", null, "19", "singleton.1", null, "singletons.3", null, null, "21", "22", "23", null }; } @SuppressWarnings("unchecked") private void initService() { try { service.afterPropertiesSet(); } catch (Exception e) { throw new RuntimeException(e); } // service assertNull(getFieldValue(service, "toolFactories", Map.class)); tools = sort(getFieldValue(service, "tools", Map.class)); toolsInSet = sort(getFieldValue(service, "toolsInSet", Map.class)); toolsRuntime = sort(getFieldValue(service, "toolsRuntime", Map.class)); prePulledTools = sort(getFieldValue(service, "prePulledTools", Map.class)); toolNames = createHashSet(getFieldValue(service, "toolNames", Set.class)); assertNotNull(tools); assertNotNull(toolsInSet); assertNotNull(toolsRuntime); assertNotNull(prePulledTools); assertNotNull(toolNames); // context context = service.getContext(); assertNotNull(context); context_pulledTools = getFieldValue(context, "pulledTools", Map.class); context_toolsRuntime = getFieldValue(context, "toolsRuntime", Map.class); context_toolsInRuntimeSet = getFieldValue(context, "toolsInRuntimeSet", Map.class); context_toolNames = getFieldValue(context, "toolNames", Set.class); assertNotNull(context_pulledTools); assertNotNull(context_toolsRuntime); assertNotNull(context_toolsInRuntimeSet); assertNotNull(context_toolNames); } private <T> Map<String, T> sort(Map<String, T> map) { Map<String, T> sortedMap = createTreeMap(); sortedMap.putAll(map); return sortedMap; } private void initServiceWithParent() { PullService parent = service; service = new PullServiceImpl(); Map<String, Object> factories = createHashMap(); factories.put("singleton.3", newToolFactory(true, "singleton.3")); factories.put("singletons.5", newToolSetFactory(true, true, "singletons.5", "z1", "11")); factories.put("prototype.3", newToolFactory(false, "prototype.3")); factories.put("prototypes.5", newToolSetFactory(false, true, "prototypes.5", "z2", "22")); factories.put("runtime.5", newRuntimeToolSetFactory(false, true, "runtime.5", "z3", "33")); service.setToolFactories(factories); service.setParent(parent); initService(); // all names and values including runtime tools and parent's tools allNamesWithParent = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "prototype.1", "prototype.2", "prototype.3", "prototypes.3", "prototypes.4", "prototypes.5", "q", "r", "runtime.3", "runtime.4", "runtime.5", "s", "singleton.1", "singleton.2", "singleton.3", "singletons.3", "singletons.4", "singletons.5", "t", "u", "v", "w", "x", "z1", "z2", "z3" }; allValuesWithParent = new String[] { "1", "2", "3", null, "5", "6", "7", null, "9", "10", "11", null, "13", "14", "15", null, "prototype.1", null, "prototype.3", "prototypes.3", null, "prototypes.5", "17", "18", "runtime.3", null, "runtime.5", "19", "singleton.1", null, "singleton.3", "singletons.3", null, "singletons.5", null, "21", "22", "23", null, "11", "22", "33" }; } @Test public void service_initParent() throws Exception { PullServiceImpl parent = new PullServiceImpl(); PullServiceImpl sub; // no parent sub = new PullServiceImpl(); sub.setApplicationContext(getApplicationContext("pullService", parent, false)); sub.setBeanName("pullService"); sub.afterPropertiesSet(); assertNull(getFieldValue(sub, "parent", PullService.class)); // with parent, beanName == pullService sub = new PullServiceImpl(); sub.setApplicationContext(getApplicationContext("pullService", parent, true)); sub.setBeanName("pullService"); sub.afterPropertiesSet(); assertSame(parent, getFieldValue(sub, "parent", PullService.class)); // with parent, beanName == otherName sub = new PullServiceImpl(); sub.setApplicationContext(getApplicationContext("pullService", parent, true)); sub.setBeanName("otherName"); sub.afterPropertiesSet(); assertSame(parent, getFieldValue(sub, "parent", PullService.class)); // with parent, beanName == otherName sub = new PullServiceImpl(); sub.setApplicationContext(getApplicationContext("otherName", parent, true)); sub.setBeanName("otherName"); sub.afterPropertiesSet(); assertSame(parent, getFieldValue(sub, "parent", PullService.class)); // with parent, beanName == otherName2 sub = new PullServiceImpl(); sub.setApplicationContext(getApplicationContext("otherName", parent, true)); sub.setBeanName("otherName2"); sub.afterPropertiesSet(); assertNull(getFieldValue(sub, "parent", PullService.class)); } private ApplicationContext getApplicationContext(String beanName, PullService parent, boolean withParent) { ApplicationContext parentContext = createMock(ApplicationContext.class); ApplicationContext thisContext = createMock(ApplicationContext.class); if (withParent) { expect(thisContext.getParent()).andReturn(parentContext).anyTimes(); } else { expect(thisContext.getParent()).andReturn(null).anyTimes(); } expect(parentContext.containsBean(beanName)).andReturn(true).anyTimes(); expect(parentContext.containsBean(org.easymock.EasyMock.<String>anyObject())).andReturn(false).anyTimes(); expect(parentContext.getBean(beanName)).andReturn(parent).anyTimes(); replay(parentContext, thisContext); return thisContext; } @Test public void service_init_noFactories() throws Exception { service = new PullServiceImpl(); initService(); assertTrue(tools.isEmpty()); assertTrue(toolsInSet.isEmpty()); assertTrue(toolsRuntime.isEmpty()); assertTrue(prePulledTools.isEmpty()); assertTrue(toolNames.isEmpty()); } @Test public void service_init_emptyName() throws Exception { service = new PullServiceImpl(); try { Map<String, Object> factories = createHashMap(); factories.put(null, newToolFactory(true, "111")); service.setToolFactories(factories); service.afterPropertiesSet(); fail(); } catch (IllegalArgumentException e) { assertThat(e, exception("tool name")); } try { Map<String, Object> factories = createHashMap(); factories.put(" ", newToolFactory(true, "111")); service.setToolFactories(factories); service.afterPropertiesSet(); fail(); } catch (IllegalArgumentException e) { assertThat(e, exception("tool name")); } } @Test public void service_init_unknwonFactory() throws Exception { service = new PullServiceImpl(); try { Map<String, Object> factories = createHashMap(); factories.put("unknwon", "not a factory"); service.setToolFactories(factories); service.afterPropertiesSet(); fail(); } catch (IllegalArgumentException e) { assertThat(e, exception("unknown pull tool factory type: java.lang.String")); } } @Test public void service_init_prePulling_preQueueing() throws Exception { List<Object> values; // toolNames - all tools and tools in set assertArrayEquals(staticToolNames, toStringArray(toolNames)); // prePulledTools - pre-pulled singletons assertArrayEquals(new Object[] { "a", "b", "c", "d", "e", "f", "g", "h", "singleton.1", "singleton.2", "singletons.3", "singletons.4" }, prePulledTools.keySet().toArray()); assertArrayEquals(new Object[] { "1", "2", "3", NULL_PLACEHOLDER, "5", "6", "7", NULL_PLACEHOLDER, "singleton.1", NULL_PLACEHOLDER, "singletons.3", NULL_PLACEHOLDER }, prePulledTools.values().toArray()); // tools - non-singleton tools only assertArrayEquals(new Object[] { "prototype.1", "prototype.2", "prototypes.3", "prototypes.4", "runtime.3", "runtime.4" }, tools.keySet().toArray()); values = createArrayList(); for (ToolFactory factory : tools.values()) { values.add(factory.createTool()); } assertArrayEquals(new Object[] { "prototype.1", null, "prototypes.3", null, "runtime.3", null }, values.toArray()); // toolsInSet - non-singleton tools in set only assertArrayEquals(new Object[] { "i", "j", "k", "l", "m", "n", "o", "p" }, toolsInSet.keySet().toArray()); values = createArrayList(); for (String nameInSet : toolsInSet.keySet()) { values.add(toolsInSet.get(nameInSet).getFactory().createTool(nameInSet)); } assertArrayEquals(new Object[] { "9", "10", "11", null, "13", "14", "15", null }, values.toArray()); // toolsRuntime - runtime tool sets only assertArrayEquals(new Object[] { "runtime.1", "runtime.2", "runtime.3", "runtime.4" }, toolsRuntime.keySet() .toArray()); assertEquals(toolNames.size(), tools.size() + toolsInSet.size() + prePulledTools.size()); } @Test public void service_init_ToolNameAware() throws Exception { service = new PullServiceImpl(); ToolNameAwareToolFactory f1 = createMock(ToolNameAwareToolFactory.class); ToolNameAwareToolSetFactory f2 = createMock(ToolNameAwareToolSetFactory.class); ToolNameAwareRuntimeToolSetFactory f3 = createMock(ToolNameAwareRuntimeToolSetFactory.class); f1.setToolName("f1"); f2.setToolName("f2"); f3.setToolName("f3"); expect(f1.isSingleton()).andReturn(false); expect(f2.isSingleton()).andReturn(false); expect(f2.getToolNames()).andReturn(null); replay(f1, f2, f3); Map<String, Object> factories = createHashMap(); factories.put("f1", f1); factories.put("f2", f2); factories.put("f3", f3); service.setToolFactories(factories); service.afterPropertiesSet(); verify(f1, f2, f3); } @Test public void service_getContext() { // 在web环境中,context被cache,否则不cache assertNotSame(service.getContext(), service.getContext()); setRequestAttrs(); assertSame(service.getContext(), service.getContext()); } @Test public void service_getTools() { assertGetTools(service.getTools()); // 在非web环境中,context不被cache assertNotSame(service.getTools(), service.getTools()); // 在web环境中,context被cache setRequestAttrs(); assertSame(service.getTools(), service.getTools()); // unmodifiable try { service.getTools().clear(); fail(); } catch (UnsupportedOperationException e) { } } @Test public void service_getTools_withParent() { initServiceWithParent(); Map<String, Object> tools = sort(service.getTools()); assertArrayEquals(allNamesWithParent, tools.keySet().toArray()); assertArrayEquals(allValuesWithParent, tools.values().toArray()); // 在非web环境中,context不被cache assertNotSame(service.getTools(), service.getTools()); // 在web环境中,context被cache setRequestAttrs(); assertSame(service.getTools(), service.getTools()); // unmodifiable try { service.getTools().clear(); fail(); } catch (UnsupportedOperationException e) { } } @Test public void service_toString() { // inited with tools String str = ""; str += "PullTools [\n"; str += " [ 1/26] /prototype.1\n"; str += " [ 2/26] /prototype.2\n"; str += " [ 3/26] /prototypes.1/i\n"; str += " [ 4/26] /prototypes.1/j\n"; str += " [ 5/26] /prototypes.2/k\n"; str += " [ 6/26] /prototypes.2/l\n"; str += " [ 7/26] /prototypes.3\n"; str += " [ 8/26] /prototypes.3/m\n"; str += " [ 9/26] /prototypes.3/n\n"; str += " [10/26] /prototypes.4\n"; str += " [11/26] /prototypes.4/o\n"; str += " [12/26] /prototypes.4/p\n"; str += " [13/26] /runtime.3\n"; str += " [14/26] /runtime.4\n"; str += " [15/26] /singleton.1\n"; str += " [16/26] /singleton.2\n"; str += " [17/26] /singletons.1/a\n"; str += " [18/26] /singletons.1/b\n"; str += " [19/26] /singletons.2/c\n"; str += " [20/26] /singletons.2/d\n"; str += " [21/26] /singletons.3\n"; str += " [22/26] /singletons.3/e\n"; str += " [23/26] /singletons.3/f\n"; str += " [24/26] /singletons.4\n"; str += " [25/26] /singletons.4/g\n"; str += " [26/26] /singletons.4/h\n"; str += "]"; assertEquals(str, service.toString()); // not inited service = new PullServiceImpl(); assertEquals("PullTools[uninitialized]", service.toString()); // inited empty initService(); assertEquals("PullTools[]", service.toString()); } @Test public void service_toString_withParent() { initServiceWithParent(); String str = ""; str += "PullTools [\n"; str += " [1/7] /prototype.3\n"; str += " [2/7] /prototypes.5\n"; str += " [3/7] /prototypes.5/z2\n"; str += " [4/7] /runtime.5\n"; str += " [5/7] /singleton.3\n"; str += " [6/7] /singletons.5\n"; str += " [7/7] /singletons.5/z1\n"; str += "]\n"; str += "Parent PullTools [\n"; str += " [ 1/26] /prototype.1\n"; str += " [ 2/26] /prototype.2\n"; str += " [ 3/26] /prototypes.1/i\n"; str += " [ 4/26] /prototypes.1/j\n"; str += " [ 5/26] /prototypes.2/k\n"; str += " [ 6/26] /prototypes.2/l\n"; str += " [ 7/26] /prototypes.3\n"; str += " [ 8/26] /prototypes.3/m\n"; str += " [ 9/26] /prototypes.3/n\n"; str += " [10/26] /prototypes.4\n"; str += " [11/26] /prototypes.4/o\n"; str += " [12/26] /prototypes.4/p\n"; str += " [13/26] /runtime.3\n"; str += " [14/26] /runtime.4\n"; str += " [15/26] /singleton.1\n"; str += " [16/26] /singleton.2\n"; str += " [17/26] /singletons.1/a\n"; str += " [18/26] /singletons.1/b\n"; str += " [19/26] /singletons.2/c\n"; str += " [20/26] /singletons.2/d\n"; str += " [21/26] /singletons.3\n"; str += " [22/26] /singletons.3/e\n"; str += " [23/26] /singletons.3/f\n"; str += " [24/26] /singletons.4\n"; str += " [25/26] /singletons.4/g\n"; str += " [26/26] /singletons.4/h\n"; str += "]"; assertEquals(str, service.toString()); } @Test public void context_getToolNames() { assertArrayEquals(allNames, context.getToolNames().toArray()); // cached assertSame(context.getToolNames(), context.getToolNames()); // unmodifiable try { context.getToolNames().clear(); fail(); } catch (UnsupportedOperationException e) { } } @Test public void context_getToolNames_withParent() { initServiceWithParent(); assertArrayEquals(allNamesWithParent, context.getToolNames().toArray()); // cached assertSame(context.getToolNames(), context.getToolNames()); // unmodifiable try { context.getToolNames().clear(); fail(); } catch (UnsupportedOperationException e) { } } @Test public void context_getTools() { assertGetTools(context.getTools()); // cached assertSame(context.getTools(), context.getTools()); // unmodifiable try { context.getTools().clear(); fail(); } catch (UnsupportedOperationException e) { } } @Test public void context_getTools_withParent() { initServiceWithParent(); Map<String, Object> tools = createTreeMap(); tools.putAll(context.getTools()); assertArrayEquals(allNamesWithParent, tools.keySet().toArray()); assertArrayEquals(allValuesWithParent, tools.values().toArray()); // cached assertSame(context.getTools(), context.getTools()); // unmodifiable try { context.getTools().clear(); fail(); } catch (UnsupportedOperationException e) { } } @Test public void context_pull() { assertContext(/* pulledTools */0, /* toolsRuntime */4, /* toolsInRuntimeSet */0, /* toolNames */26); // tool, singleton assertEquals("singleton.1", context.pull("singleton.1")); assertEquals(null, context.pull("singleton.2")); assertContext(/* pulledTools */0, /* toolsRuntime */4, /* toolsInRuntimeSet */0, /* toolNames */26); // tool-set, singleton assertEquals("singletons.3", context.pull("singletons.3")); assertEquals(null, context.pull("singletons.4")); assertContext(/* pulledTools */0, /* toolsRuntime */4, /* toolsInRuntimeSet */0, /* toolNames */26); assertEquals("1", context.pull("a")); assertEquals("2", context.pull("b")); assertEquals("3", context.pull("c")); assertEquals(null, context.pull("d")); assertEquals("5", context.pull("e")); assertEquals("6", context.pull("f")); assertEquals("7", context.pull("g")); assertEquals(null, context.pull("h")); assertContext(/* pulledTools */0, /* toolsRuntime */4, /* toolsInRuntimeSet */0, /* toolNames */26); // tool, non-singleton assertEquals("prototype.1", context.pull("prototype.1")); assertEquals(null, context.pull("prototype.2")); assertContext(/* pulledTools */2, /* toolsRuntime */4, /* toolsInRuntimeSet */0, /* toolNames */26); // tool-set, non-singleton assertEquals("prototypes.3", context.pull("prototypes.3")); assertEquals(null, context.pull("prototypes.4")); assertContext(/* pulledTools */4, /* toolsRuntime */4, /* toolsInRuntimeSet */0, /* toolNames */26); assertEquals("9", context.pull("i")); assertEquals("10", context.pull("j")); assertEquals("11", context.pull("k")); assertEquals(null, context.pull("l")); assertEquals("13", context.pull("m")); assertEquals("14", context.pull("n")); assertEquals("15", context.pull("o")); assertEquals(null, context.pull("p")); assertContext(/* pulledTools */12, /* toolsRuntime */4, /* toolsInRuntimeSet */0, /* toolNames */26); // tool-set, runtime assertEquals("runtime.3", context.pull("runtime.3")); assertEquals(null, context.pull("runtime.4")); assertContext(/* pulledTools */14, /* toolsRuntime */4, /* toolsInRuntimeSet */0, /* toolNames */26); assertEquals("17", context.pull("q")); assertContext(/* pulledTools */15, /* toolsRuntime */3, /* toolsInRuntimeSet */2, /* toolNames */28); assertEquals("18", context.pull("r")); assertContext(/* pulledTools */16, /* toolsRuntime */3, /* toolsInRuntimeSet */2, /* toolNames */28); assertEquals("19", context.pull("s")); assertContext(/* pulledTools */17, /* toolsRuntime */2, /* toolsInRuntimeSet */4, /* toolNames */30); assertEquals(null, context.pull("t")); assertContext(/* pulledTools */18, /* toolsRuntime */2, /* toolsInRuntimeSet */4, /* toolNames */30); assertEquals("21", context.pull("u")); assertContext(/* pulledTools */19, /* toolsRuntime */1, /* toolsInRuntimeSet */6, /* toolNames */32); assertEquals("22", context.pull("v")); assertContext(/* pulledTools */20, /* toolsRuntime */1, /* toolsInRuntimeSet */6, /* toolNames */32); assertEquals("23", context.pull("w")); assertContext(/* pulledTools */21, /* toolsRuntime */0, /* toolsInRuntimeSet */8, /* toolNames */34); assertEquals(null, context.pull("x")); assertContext(/* pulledTools */22, /* toolsRuntime */0, /* toolsInRuntimeSet */8, /* toolNames */34); } @Test public void context_pull_empty() { assertEquals(null, context.pull(null)); assertEquals(null, context.pull(" ")); assertContext(/* pulledTools */0, /* toolsRuntime */4, /* toolsInRuntimeSet */0, /* toolNames */26); } @Test public void context_pull_notExist() { assertEquals(null, context.pull("notexist")); assertContext(/* pulledTools */0, /* toolsRuntime */0, /* toolsInRuntimeSet */8, /* toolNames */34); } @Test public void context_pull_exceptions() throws Exception { // singleton try { createPullService("mysingleton", new ExceptionToolFactory(true, "my error")); fail(); } catch (PullException e) { assertThat(e, exception(IllegalArgumentException.class, "Could not create tool: \"mysingleton\"", "my error")); } try { createPullService("mysingletonSet", new ExceptionToolSetFactory(true, "my error")); fail(); } catch (PullException e) { assertThat( e, exception(IllegalArgumentException.class, "Could not create tool: \"mysingletonSet.subname\"", "my error")); } // non-singleton createPullService("myprototype", new ExceptionToolFactory(false, "my error")); try { service.getTools(); fail(); } catch (PullException e) { assertThat(e, exception(IllegalArgumentException.class, "Could not create tool: \"myprototype\"", "my error")); } createPullService("myprototypeSet", new ExceptionToolSetFactory(false, "my error")); try { service.getTools(); fail(); } catch (PullException e) { assertThat( e, exception(IllegalArgumentException.class, "Could not create tool: \"myprototypeSet.subname\"", "my error")); } // runtime createPullService("myruntime", new ExceptionRuntimeToolSetFactory(false, "my error", false)); try { service.getTools(); fail(); } catch (PullException e) { assertThat( e, exception(IllegalArgumentException.class, "Could not create tool: \"myruntime.subname\"", "my error")); } // runtime - failure on createTool() createPullService("myruntime", new ExceptionRuntimeToolSetFactory(false, "my error", true)); try { service.getTools(); fail(); } catch (PullException e) { assertThat( e, exception(IllegalArgumentException.class, "Could not create runtime tool-set: \"myruntime\"", "my error")); } } private void createPullService(String name, Object factory) throws Exception { service = new PullServiceImpl(); Map<String, Object> factories = createHashMap(); factories.put(name, factory); service.setToolFactories(factories); service.afterPropertiesSet(); } @Test public void context_pull_withParent() { setRequestAttrs(); // 确保每次取得同一个context,以便于测试 // init parent context Map<String, Object> parent_pulledTools; Map<String, RuntimeToolSetFactory> parent_toolsRuntime; Map<String, ToolSetInfo<RuntimeToolSetFactory>> parent_toolsInRuntimeSet; Set<ToolName> parent_toolNames; populateService(); initService(); parent_pulledTools = context_pulledTools; parent_toolsRuntime = context_toolsRuntime; parent_toolsInRuntimeSet = context_toolsInRuntimeSet; parent_toolNames = context_toolNames; // init this context Map<String, Object> this_pulledTools; Map<String, RuntimeToolSetFactory> this_toolsRuntime; Map<String, ToolSetInfo<RuntimeToolSetFactory>> this_toolsInRuntimeSet; Set<ToolName> this_toolNames; initServiceWithParent(); this_pulledTools = context_pulledTools; this_toolsRuntime = context_toolsRuntime; this_toolsInRuntimeSet = context_toolsInRuntimeSet; this_toolNames = context_toolNames; assertContext(/* pulledTools */0, /* toolsRuntime */1, /* toolsInRuntimeSet */0, /* toolNames */7); // restore parent context and test it context_pulledTools = parent_pulledTools; context_toolsRuntime = parent_toolsRuntime; context_toolsInRuntimeSet = parent_toolsInRuntimeSet; context_toolNames = parent_toolNames; context_pull(); // restore this context and test it context_pulledTools = this_pulledTools; context_toolsRuntime = this_toolsRuntime; context_toolsInRuntimeSet = this_toolsInRuntimeSet; context_toolNames = this_toolNames; assertContext(/* pulledTools */0, /* toolsRuntime */0, /* toolsInRuntimeSet */1, /* toolNames */8); assertEquals("singleton.3", context.pull("singleton.3")); assertEquals("singletons.5", context.pull("singletons.5")); assertEquals("prototype.3", context.pull("prototype.3")); assertEquals("prototypes.5", context.pull("prototypes.5")); assertEquals("runtime.5", context.pull("runtime.5")); assertEquals("11", context.pull("z1")); assertEquals("22", context.pull("z2")); assertEquals("33", context.pull("z3")); assertContext(/* pulledTools */5, /* toolsRuntime */0, /* toolsInRuntimeSet */1, /* toolNames */8); } private void assertGetTools(Map<String, Object> tools) { tools = createTreeMap(); tools.putAll(context.getTools()); assertArrayEquals(allNames, tools.keySet().toArray()); assertArrayEquals(allValues, tools.values().toArray()); } private void assertContext(int pulledTools, int toolsRuntime, int toolsInRuntimeSet, int toolNames) { assertEquals(pulledTools, context_pulledTools.size()); assertEquals(toolsRuntime, context_toolsRuntime.size()); assertEquals(toolsInRuntimeSet, context_toolsInRuntimeSet.size()); assertEquals(toolNames, context_toolNames.size()); } @Test public void context_toString() { String str; // has not pulled all str = ""; str += "PullContext {\n"; str += " prePulledTools = {\n"; str += " [ 1/12] a = 1\n"; str += " [ 2/12] b = 2\n"; str += " [ 3/12] c = 3\n"; str += " [ 4/12] d = null\n"; str += " [ 5/12] e = 5\n"; str += " [ 6/12] f = 6\n"; str += " [ 7/12] g = 7\n"; str += " [ 8/12] h = null\n"; str += " [ 9/12] singleton.1 = singleton.1\n"; str += " [10/12] singleton.2 = null\n"; str += " [11/12] singletons.3 = singletons.3\n"; str += " [12/12] singletons.4 = null\n"; str += " }\n"; str += " pulledTools = {}\n"; str += "}"; assertEquals(str, context.toString()); // pulled all context.getTools(); str = ""; str += "PullContext {\n"; str += " prePulledTools = {\n"; str += " [ 1/12] a = 1\n"; str += " [ 2/12] b = 2\n"; str += " [ 3/12] c = 3\n"; str += " [ 4/12] d = null\n"; str += " [ 5/12] e = 5\n"; str += " [ 6/12] f = 6\n"; str += " [ 7/12] g = 7\n"; str += " [ 8/12] h = null\n"; str += " [ 9/12] singleton.1 = singleton.1\n"; str += " [10/12] singleton.2 = null\n"; str += " [11/12] singletons.3 = singletons.3\n"; str += " [12/12] singletons.4 = null\n"; str += " }\n"; str += " pulledTools = {\n"; str += " [ 1/22] i = 9\n"; str += " [ 2/22] j = 10\n"; str += " [ 3/22] k = 11\n"; str += " [ 4/22] l = null\n"; str += " [ 5/22] m = 13\n"; str += " [ 6/22] n = 14\n"; str += " [ 7/22] o = 15\n"; str += " [ 8/22] p = null\n"; str += " [ 9/22] prototype.1 = prototype.1\n"; str += " [10/22] prototype.2 = null\n"; str += " [11/22] prototypes.3 = prototypes.3\n"; str += " [12/22] prototypes.4 = null\n"; str += " [13/22] q = 17\n"; str += " [14/22] r = 18\n"; str += " [15/22] runtime.3 = runtime.3\n"; str += " [16/22] runtime.4 = null\n"; str += " [17/22] s = 19\n"; str += " [18/22] t = null\n"; str += " [19/22] u = 21\n"; str += " [20/22] v = 22\n"; str += " [21/22] w = 23\n"; str += " [22/22] x = null\n"; str += " }\n"; str += "}"; assertEquals(str, context.toString()); } @Test public void context_toString_withParent() { initServiceWithParent(); String str; // has not pulled all str = ""; str += "PullContext {\n"; str += " prePulledTools = {\n"; str += " [1/3] singleton.3 = singleton.3\n"; str += " [2/3] singletons.5 = singletons.5\n"; str += " [3/3] z1 = 11\n"; str += " }\n"; str += " pulledTools = {}\n"; str += "}\n"; str += "Parent PullContext {\n"; str += " prePulledTools = {\n"; str += " [ 1/12] a = 1\n"; str += " [ 2/12] b = 2\n"; str += " [ 3/12] c = 3\n"; str += " [ 4/12] d = null\n"; str += " [ 5/12] e = 5\n"; str += " [ 6/12] f = 6\n"; str += " [ 7/12] g = 7\n"; str += " [ 8/12] h = null\n"; str += " [ 9/12] singleton.1 = singleton.1\n"; str += " [10/12] singleton.2 = null\n"; str += " [11/12] singletons.3 = singletons.3\n"; str += " [12/12] singletons.4 = null\n"; str += " }\n"; str += " pulledTools = {}\n"; str += "}"; assertEquals(str, context.toString()); // pulled all context.getTools(); str = ""; str += "PullContext {\n"; str += " prePulledTools = {\n"; str += " [1/3] singleton.3 = singleton.3\n"; str += " [2/3] singletons.5 = singletons.5\n"; str += " [3/3] z1 = 11\n"; str += " }\n"; str += " pulledTools = {\n"; str += " [1/5] prototype.3 = prototype.3\n"; str += " [2/5] prototypes.5 = prototypes.5\n"; str += " [3/5] runtime.5 = runtime.5\n"; str += " [4/5] z2 = 22\n"; str += " [5/5] z3 = 33\n"; str += " }\n"; str += "}\n"; str += "Parent PullContext {\n"; str += " prePulledTools = {\n"; str += " [ 1/12] a = 1\n"; str += " [ 2/12] b = 2\n"; str += " [ 3/12] c = 3\n"; str += " [ 4/12] d = null\n"; str += " [ 5/12] e = 5\n"; str += " [ 6/12] f = 6\n"; str += " [ 7/12] g = 7\n"; str += " [ 8/12] h = null\n"; str += " [ 9/12] singleton.1 = singleton.1\n"; str += " [10/12] singleton.2 = null\n"; str += " [11/12] singletons.3 = singletons.3\n"; str += " [12/12] singletons.4 = null\n"; str += " }\n"; str += " pulledTools = {\n"; str += " [ 1/22] i = 9\n"; str += " [ 2/22] j = 10\n"; str += " [ 3/22] k = 11\n"; str += " [ 4/22] l = null\n"; str += " [ 5/22] m = 13\n"; str += " [ 6/22] n = 14\n"; str += " [ 7/22] o = 15\n"; str += " [ 8/22] p = null\n"; str += " [ 9/22] prototype.1 = prototype.1\n"; str += " [10/22] prototype.2 = null\n"; str += " [11/22] prototypes.3 = prototypes.3\n"; str += " [12/22] prototypes.4 = null\n"; str += " [13/22] q = 17\n"; str += " [14/22] r = 18\n"; str += " [15/22] runtime.3 = runtime.3\n"; str += " [16/22] runtime.4 = null\n"; str += " [17/22] s = 19\n"; str += " [18/22] t = null\n"; str += " [19/22] u = 21\n"; str += " [20/22] v = 22\n"; str += " [21/22] w = 23\n"; str += " [22/22] x = null\n"; str += " }\n"; str += "}"; assertEquals(str, context.toString()); } @Test public void context_sharing() throws Exception { setRequestAttrs(); // init parent PullServiceImpl parent = new PullServiceImpl(); Map<String, Object> factories = createHashMap(); factories.put("parentSingleton", new MyToolFactory(true)); factories.put("parentPrototype", new MyToolFactory(false)); factories.put("parentRuntime", new MyRuntimeToolSetFactory("parentRuntime")); parent.setToolFactories(factories); parent.afterPropertiesSet(); // init sub1 PullServiceImpl sub1 = new PullServiceImpl(); factories = createHashMap(); factories.put("subSingleton", new MyToolFactory(true)); factories.put("subPrototype", new MyToolFactory(false)); factories.put("subRuntime", new MyRuntimeToolSetFactory("subRuntime")); sub1.setParent(parent); sub1.setToolFactories(factories); sub1.afterPropertiesSet(); // init sub2 PullServiceImpl sub2 = new PullServiceImpl(); factories = createHashMap(); factories.put("subSingleton", new MyToolFactory(true)); factories.put("subPrototype", new MyToolFactory(false)); factories.put("subRuntime", new MyRuntimeToolSetFactory("subRuntime")); sub2.setParent(parent); sub2.setToolFactories(factories); sub2.afterPropertiesSet(); // parentObject is shared among subs assertSameAndNotNull(sub1.getContext().pull("parentSingleton"), sub2.getContext().pull("parentSingleton")); assertSameAndNotNull(sub1.getContext().pull("parentPrototype"), sub2.getContext().pull("parentPrototype")); assertSameAndNotNull(sub1.getContext().pull("parentRuntime"), sub2.getContext().pull("parentRuntime")); assertNotSameAndNotNull(sub1.getContext().pull("subSingleton"), sub2.getContext().pull("subSingleton")); assertNotSameAndNotNull(sub1.getContext().pull("subPrototype"), sub2.getContext().pull("subPrototype")); assertNotSameAndNotNull(sub1.getContext().pull("subRuntime"), sub2.getContext().pull("subRuntime")); } private void assertSameAndNotNull(Object o1, Object o2) { assertNotNull(o1); assertNotNull(o2); assertSame(o1, o2); } private void assertNotSameAndNotNull(Object o1, Object o2) { assertNotNull(o1); assertNotNull(o2); assertNotSame(o1, o2); } private String[] toStringArray(Collection<ToolName> c) { String[] result = new String[c.size()]; int i = 0; for (ToolName o : c) { result[i++] = o == null ? null : o.getName(); } Arrays.sort(result); return result; } private static class MyToolFactory implements ToolFactory { private boolean singleton; public MyToolFactory(boolean singleton) { this.singleton = singleton; } public boolean isSingleton() { return singleton; } public Object createTool() { return new Object(); } } private static class MyRuntimeToolSetFactory implements RuntimeToolSetFactory { private List<String> keys; public MyRuntimeToolSetFactory(String name) { this.keys = singletonList(name); } public Object createToolSet() throws Exception { return null; } public Iterable<String> getToolNames(Object toolSet) { return keys; } public Object createTool(Object toolSet, String name) throws Exception { return new Object(); } } private static class ExceptionBaseFactory { private boolean singleton; private String msg; private boolean failOnCreatingToolSet; public ExceptionBaseFactory(boolean singleton, String msg) { this(singleton, msg, true); } public ExceptionBaseFactory(boolean singleton, String msg, boolean failOnCreatingToolSet) { this.singleton = singleton; this.msg = msg; this.failOnCreatingToolSet = failOnCreatingToolSet; } public boolean isSingleton() { return singleton; } public Object createTool() throws Exception { throw new IllegalArgumentException(msg); } public Iterable<String> getToolNames() { return singletonList("subname"); } public Object createTool(String name) throws Exception { throw new IllegalArgumentException(msg); } public Object createToolSet() throws Exception { if (failOnCreatingToolSet) { throw new IllegalArgumentException(msg); } return null; } public Iterable<String> getToolNames(Object tool) { return singletonList("subname"); } public Object createTool(Object tool, String name) throws Exception { throw new IllegalArgumentException(msg); } } private static class ExceptionToolFactory extends ExceptionBaseFactory implements ToolFactory { public ExceptionToolFactory(boolean singleton, String msg) { super(singleton, msg); } } private static class ExceptionToolSetFactory extends ExceptionBaseFactory implements ToolSetFactory { public ExceptionToolSetFactory(boolean singleton, String msg) { super(singleton, msg); } } private static class ExceptionRuntimeToolSetFactory extends ExceptionBaseFactory implements RuntimeToolSetFactory { public ExceptionRuntimeToolSetFactory(boolean singleton, String msg, boolean failOnCreatingTool) { super(singleton, msg, failOnCreatingTool); } } private static interface ToolNameAwareToolFactory extends ToolFactory, ToolNameAware { } private static interface ToolNameAwareToolSetFactory extends ToolSetFactory, ToolNameAware { } private static interface ToolNameAwareRuntimeToolSetFactory extends RuntimeToolSetFactory, ToolNameAware { } }