From 2a22d6cf8dc6302a94f4121983d979d8f55da6ca Mon Sep 17 00:00:00 2001 From: erik Date: Thu, 15 May 2008 10:17:54 +0000 Subject: [PATCH] ORMappingConfig is now provided by the datasource component. ExternalDatasourceComponent reads config from property file. Next step is that it requires config from a separate Properties object which is provided by either a property component, or a DatabaseComponent (e.g. Derby). --- .../system/spring/SpringComponent.java | 16 +- .../spring/component/HibernateComponent.java | 33 +- .../spring/component/ORMappingConfig.java | 61 +++ .../system/spring/SpringComponentTest.java | 346 +++++++++++------- .../system/spring/SubSpringComponent.java | 45 +++ .../system/spring/SubSpringComponent2.java | 45 +++ 6 files changed, 402 insertions(+), 144 deletions(-) create mode 100644 system/spring/src/main/java/org/wamblee/system/spring/component/ORMappingConfig.java create mode 100644 system/spring/src/test/java/org/wamblee/system/spring/SubSpringComponent.java create mode 100644 system/spring/src/test/java/org/wamblee/system/spring/SubSpringComponent2.java diff --git a/system/spring/src/main/java/org/wamblee/system/spring/SpringComponent.java b/system/spring/src/main/java/org/wamblee/system/spring/SpringComponent.java index d0abbcd1..83a5133b 100644 --- a/system/spring/src/main/java/org/wamblee/system/spring/SpringComponent.java +++ b/system/spring/src/main/java/org/wamblee/system/spring/SpringComponent.java @@ -169,12 +169,16 @@ public class SpringComponent extends AbstractComponent { // Register required services in a parent context for (RequiredInterface required: getRequiredInterfaces()) { String beanName = _required.get(required); - ConstructorArgumentValues cargs = new ConstructorArgumentValues(); - cargs.addGenericArgumentValue(required.getName()); - BeanDefinition definition = new RootBeanDefinition( - RequiredServiceBean.class, cargs, - new MutablePropertyValues()); - aParentContext.registerBeanDefinition(beanName, definition); + if ( beanName != null && beanName.length() > 0) { + ConstructorArgumentValues cargs = new ConstructorArgumentValues(); + cargs.addGenericArgumentValue(required.getName()); + BeanDefinition definition = new RootBeanDefinition( + RequiredServiceBean.class, cargs, + new MutablePropertyValues()); + aParentContext.registerBeanDefinition(beanName, definition); + } else { + // The required interface is not required by the spring config but by the sub-class directly. + } } } diff --git a/system/spring/src/main/java/org/wamblee/system/spring/component/HibernateComponent.java b/system/spring/src/main/java/org/wamblee/system/spring/component/HibernateComponent.java index 364b250f..56fda2f0 100644 --- a/system/spring/src/main/java/org/wamblee/system/spring/component/HibernateComponent.java +++ b/system/spring/src/main/java/org/wamblee/system/spring/component/HibernateComponent.java @@ -23,6 +23,7 @@ import java.util.Properties; import javax.sql.DataSource; import org.hibernate.SessionFactory; +import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.MySQLInnoDBDialect; import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.transaction.PlatformTransactionManager; @@ -31,12 +32,18 @@ import org.wamblee.system.core.DefaultProvidedInterface; import org.wamblee.system.core.DefaultRequiredInterface; import org.wamblee.system.core.ProvidedInterface; import org.wamblee.system.core.RequiredInterface; +import org.wamblee.system.core.Scope; import org.wamblee.system.spring.SpringComponent; +import org.wamblee.system.spring.component.ORMappingConfig.DatabaseType; public class HibernateComponent extends SpringComponent { + private static final String HIBERNATE_DIALECT_PROP = "hibernate.dialect"; + private static final String HIBERNATE_SCHEMAUPDATE_PROP = "hibernate.schemaupdate"; private static final String HIBERNATE_PROPS_KEY = "hibernateProperties"; private static final String HIBERNATE_SPRING_CONFIG = "spring/org.wamblee.system.spring.component.hibernate.xml"; + + private final RequiredInterface CONFIG = new DefaultRequiredInterface("config", ORMappingConfig.class); public HibernateComponent(String aName) throws IOException { super(aName, new String[] { HIBERNATE_SPRING_CONFIG}, @@ -45,8 +52,30 @@ public class HibernateComponent extends SpringComponent { Properties props = new Properties(); addProperties(HIBERNATE_PROPS_KEY, props); - props.put("hibernate.dialect", MySQLInnoDBDialect.class.getName()); - setProperty("hibernate.schemaupdate", "true"); + addRequiredInterface(CONFIG); + } + + @Override + protected Scope doStart(Scope aExternalScope) { + + ORMappingConfig config = aExternalScope.getInterfaceImplementation(CONFIG.getProvider(), ORMappingConfig.class); + setProperty(HIBERNATE_SCHEMAUPDATE_PROP, "" + config.isSchemaUpdate()); + + DatabaseType db = config.getType(); + String dialect = db.handleCases(new DatabaseType.Switch() { + @Override + public String handleMySqlInnoDb() { + return MySQLInnoDBDialect.class.getName(); + } + @Override + public String handleDerby() { + return DerbyDialect.class.getName(); + } + }); + getHibernateProperties().put(HIBERNATE_DIALECT_PROP, MySQLInnoDBDialect.class.getName()); + + + return super.doStart(aExternalScope); } private Properties getHibernateProperties() { diff --git a/system/spring/src/main/java/org/wamblee/system/spring/component/ORMappingConfig.java b/system/spring/src/main/java/org/wamblee/system/spring/component/ORMappingConfig.java new file mode 100644 index 00000000..cf34da38 --- /dev/null +++ b/system/spring/src/main/java/org/wamblee/system/spring/component/ORMappingConfig.java @@ -0,0 +1,61 @@ +/* + * Copyright 2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.wamblee.system.spring.component; + +public class ORMappingConfig { + + public enum DatabaseType { + MYSQL_INNO_DB, DERBY; + + public static interface Switch { + T handleMySqlInnoDb(); + + T handleDerby(); + } + + public T handleCases(Switch aSwitch) { + + switch (this) { + case MYSQL_INNO_DB: { + return aSwitch.handleMySqlInnoDb(); + } + case DERBY: { + return aSwitch.handleDerby(); + } + default: { + throw new RuntimeException("Unhandled case " + this); + } + } + } + }; + + private boolean _schemaUpdate; + private DatabaseType _type; + + public ORMappingConfig(boolean aSchemaUpdate, DatabaseType aType) { + _schemaUpdate = aSchemaUpdate; + _type = aType; + } + + public boolean isSchemaUpdate() { + return _schemaUpdate; + } + + public DatabaseType getType() { + return _type; + } + +} diff --git a/system/spring/src/test/java/org/wamblee/system/spring/SpringComponentTest.java b/system/spring/src/test/java/org/wamblee/system/spring/SpringComponentTest.java index 3e63c7ea..10e2ca8e 100644 --- a/system/spring/src/test/java/org/wamblee/system/spring/SpringComponentTest.java +++ b/system/spring/src/test/java/org/wamblee/system/spring/SpringComponentTest.java @@ -34,79 +34,84 @@ import org.wamblee.test.EventTracker; public class SpringComponentTest extends TestCase { - private static final String HELLO_SERVICE_SPRING_XML = "test.org.wamblee.system.spring.xml"; - private static final String HELLO_SERVICE_SPRING_WITH_REQS_XML = "test.org.wamblee.system.springWithRequirements.xml"; - private static final String HELLO_SERVICE_SPRING_WITH_PROPERTIES_XML = "test.org.wamblee.system.springWithProperties.xml"; - private static final String HELLO_SERVICE_SPRING_WITH_PROPERTIES_XML2 = "test.org.wamblee.system.springWithProperties2.xml"; - - private static final String PROPERTY_FILE = "test.org.wamblee.system.spring.properties"; - - public static EventTracker EVENT_TRACKER; - - private Scope _externalScope; - - @Override - protected void setUp() throws Exception { - super.setUp(); - EVENT_TRACKER = new EventTracker(); - _externalScope = new DefaultScope(new ProvidedInterface[0]); - } - - public void testBlackboxSystem() { - SpringComponent system = new SpringComponent("system", - new String[] { HELLO_SERVICE_SPRING_XML }, - new HashMap(), - new HashMap()); - - Scope runtime = system.start(_externalScope); - assertEquals(0, _externalScope.getProvidedInterfaces().length); - - system.stop(runtime); - } - - public void testOneProvidedService() { - Map provided = new HashMap(); - provided.put("helloService", new DefaultProvidedInterface("hello", - HelloService.class)); - - SpringComponent system = new SpringComponent("system", - new String[] { HELLO_SERVICE_SPRING_XML }, provided, - new HashMap()); - Scope runtime = system.start(_externalScope); - ProvidedInterface[] services = runtime.getProvidedInterfaces(); - - assertEquals(1, services.length); - Object service = runtime.getInterfaceImplementation(services[0], Object.class); - assertTrue(service instanceof HelloService); - - // BUG; Provided services should be made available in the external scope. - Object service2 = _externalScope.getInterfaceImplementation(provided.get("helloService"), Object.class); - assertSame(service, service2); - - assertEquals("Hello world!", ((HelloService) service).say()); - system.stop(runtime); - } - - public void testWithProperties() throws IOException { - Map provided = new HashMap(); - provided.put("helloService", new DefaultProvidedInterface("hello", - HelloService.class)); - SpringComponent system = new SpringComponent("system", - new String[] { HELLO_SERVICE_SPRING_WITH_PROPERTIES_XML }, - provided, new HashMap()); - Properties props = new Properties(); - props.load(new ClassPathResource(PROPERTY_FILE).getInputStream()); - system.addProperties(props); - - Scope scope = system.start(_externalScope); - // BUG: Hello service was constructed multiple times. Once with the unprocessed property - // and another time with the processed property. - assertEquals(1, EVENT_TRACKER.getEventCount()); - ProvidedInterface[] services = scope.getProvidedInterfaces(); - assertEquals("Property Value", scope.getInterfaceImplementation(services[0], HelloService.class).say()); - } - - public void testWithPropertiesAsBean() throws IOException { + private static final String HELLO_SERVICE_SPRING_XML = "test.org.wamblee.system.spring.xml"; + private static final String HELLO_SERVICE_SPRING_WITH_REQS_XML = "test.org.wamblee.system.springWithRequirements.xml"; + private static final String HELLO_SERVICE_SPRING_WITH_PROPERTIES_XML = "test.org.wamblee.system.springWithProperties.xml"; + private static final String HELLO_SERVICE_SPRING_WITH_PROPERTIES_XML2 = "test.org.wamblee.system.springWithProperties2.xml"; + + private static final String PROPERTY_FILE = "test.org.wamblee.system.spring.properties"; + + public static EventTracker EVENT_TRACKER; + + private Scope _externalScope; + + @Override + protected void setUp() throws Exception { + super.setUp(); + EVENT_TRACKER = new EventTracker(); + _externalScope = new DefaultScope(new ProvidedInterface[0]); + } + + public void testBlackboxSystem() { + SpringComponent system = new SpringComponent("system", + new String[] { HELLO_SERVICE_SPRING_XML }, + new HashMap(), + new HashMap()); + + Scope runtime = system.start(_externalScope); + assertEquals(0, _externalScope.getProvidedInterfaces().length); + + system.stop(runtime); + } + + public void testOneProvidedService() { + Map provided = new HashMap(); + provided.put("helloService", new DefaultProvidedInterface("hello", + HelloService.class)); + + SpringComponent system = new SpringComponent("system", + new String[] { HELLO_SERVICE_SPRING_XML }, provided, + new HashMap()); + Scope runtime = system.start(_externalScope); + ProvidedInterface[] services = runtime.getProvidedInterfaces(); + + assertEquals(1, services.length); + Object service = runtime.getInterfaceImplementation(services[0], + Object.class); + assertTrue(service instanceof HelloService); + + // BUG; Provided services should be made available in the external + // scope. + Object service2 = _externalScope.getInterfaceImplementation(provided + .get("helloService"), Object.class); + assertSame(service, service2); + + assertEquals("Hello world!", ((HelloService) service).say()); + system.stop(runtime); + } + + public void testWithProperties() throws IOException { + Map provided = new HashMap(); + provided.put("helloService", new DefaultProvidedInterface("hello", + HelloService.class)); + SpringComponent system = new SpringComponent("system", + new String[] { HELLO_SERVICE_SPRING_WITH_PROPERTIES_XML }, + provided, new HashMap()); + Properties props = new Properties(); + props.load(new ClassPathResource(PROPERTY_FILE).getInputStream()); + system.addProperties(props); + + Scope scope = system.start(_externalScope); + // BUG: Hello service was constructed multiple times. Once with the + // unprocessed property + // and another time with the processed property. + assertEquals(1, EVENT_TRACKER.getEventCount()); + ProvidedInterface[] services = scope.getProvidedInterfaces(); + assertEquals("Property Value", scope.getInterfaceImplementation( + services[0], HelloService.class).say()); + } + + public void testWithPropertiesAsBean() throws IOException { Map provided = new HashMap(); provided.put("helloService", new DefaultProvidedInterface("hello", HelloService2.class)); @@ -118,72 +123,141 @@ public class SpringComponentTest extends TestCase { system.addProperties("properties", props); Scope scope = system.start(_externalScope); - + ProvidedInterface[] services = scope.getProvidedInterfaces(); - - Properties props2 = scope.getInterfaceImplementation(services[0], HelloService2.class).getProperties(); + + Properties props2 = scope.getInterfaceImplementation(services[0], + HelloService2.class).getProperties(); assertEquals(props, props2); } - public void testWithMissingRequirement() { - try { - SpringComponent system = new SpringComponent("system", - new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, - new HashMap(), - new HashMap()); - system.start(_externalScope); - } catch (SystemAssemblyException e) { - // e.printStackTrace(); - return; - } - fail(); - } - - public void testWithRequirement() { - Map required = new HashMap(); - required.put(new DefaultRequiredInterface("hello", HelloService.class), - "helloService"); - SpringComponent system = new SpringComponent("system", - new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, - new HashMap(), required); - - HelloService helloObject = new HelloService("ladida"); - ProvidedInterface helloService = new DefaultProvidedInterface("hello", - HelloService.class); - Scope scope = new DefaultScope(new ProvidedInterface[]{ helloService }); - scope.publishInterface(helloService, helloObject); - system.getRequiredInterfaces()[0].setProvider(helloService); - - Scope runtime = system.start(scope); - system.stop(runtime); - } - - public void testWithRequirementAndProvidedService() { - Map required = new HashMap(); - required.put(new DefaultRequiredInterface("hello", HelloService.class), - "helloService"); - Map provided = new HashMap(); - provided.put("blaService", new DefaultProvidedInterface("bla", - BlaService.class)); - - SpringComponent system = new SpringComponent("system", - new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, provided, - required); - - HelloService helloObject = new HelloService("ladida"); - ProvidedInterface helloService = new DefaultProvidedInterface("hello", - HelloService.class); - Scope scope = new DefaultScope(new ProvidedInterface[] { helloService }); - scope.publishInterface(helloService, helloObject); - system.getRequiredInterfaces()[0].setProvider(helloService); - Scope runtime = system.start(scope); - ProvidedInterface started = runtime.getProvidedInterfaces()[0]; - - Object impl = runtime.getInterfaceImplementation(started, BlaService.class); - assertNotNull(impl); - assertTrue(impl instanceof BlaService); - assertEquals("ladida", ((BlaService)impl).execute()); - system.stop(runtime); - } + public void testWithMissingRequirement() { + try { + SpringComponent system = new SpringComponent("system", + new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, + new HashMap(), + new HashMap()); + system.start(_externalScope); + } catch (SystemAssemblyException e) { + // e.printStackTrace(); + return; + } + fail(); + } + + public void testWithRequirement() { + Map required = new HashMap(); + required.put(new DefaultRequiredInterface("hello", HelloService.class), + "helloService"); + SpringComponent system = new SpringComponent("system", + new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, + new HashMap(), required); + + HelloService helloObject = new HelloService("ladida"); + ProvidedInterface helloService = new DefaultProvidedInterface("hello", + HelloService.class); + Scope scope = new DefaultScope(new ProvidedInterface[] { helloService }); + scope.publishInterface(helloService, helloObject); + system.getRequiredInterfaces()[0].setProvider(helloService); + + Scope runtime = system.start(scope); + system.stop(runtime); + } + + public void testWithRequirementAndProvidedService() { + Map required = new HashMap(); + required.put(new DefaultRequiredInterface("hello", HelloService.class), + "helloService"); + Map provided = new HashMap(); + provided.put("blaService", new DefaultProvidedInterface("bla", + BlaService.class)); + + SpringComponent system = new SpringComponent("system", + new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, provided, + required); + + HelloService helloObject = new HelloService("ladida"); + ProvidedInterface helloService = new DefaultProvidedInterface("hello", + HelloService.class); + Scope scope = new DefaultScope(new ProvidedInterface[] { helloService }); + scope.publishInterface(helloService, helloObject); + system.getRequiredInterfaces()[0].setProvider(helloService); + Scope runtime = system.start(scope); + ProvidedInterface started = runtime.getProvidedInterfaces()[0]; + + Object impl = runtime.getInterfaceImplementation(started, + BlaService.class); + assertNotNull(impl); + assertTrue(impl instanceof BlaService); + assertEquals("ladida", ((BlaService) impl).execute()); + system.stop(runtime); + } + + /** + * Tests a scenario where a subclass of SpringComponent adds a new provided + * interface where the interface is provided by the subclass itself and not + * by the spring configs inside. + */ + public void testWithProvidedFromSubClassNotFromConfig() { + Map provided = new HashMap(); + provided.put("helloService", new DefaultProvidedInterface("hello", + HelloService.class)); + + SubSpringComponent system = new SubSpringComponent("system", + new String[] { HELLO_SERVICE_SPRING_XML }, provided, + new HashMap()); + + Scope runtime = system.start(_externalScope); + ProvidedInterface[] services = runtime.getProvidedInterfaces(); + + assertEquals(2, services.length); + Object service = runtime.getInterfaceImplementation(services[0], + Object.class); + assertTrue(service instanceof HelloService); + + // BUG; Provided services should be made available in the external + // scope. + Object service2 = _externalScope.getInterfaceImplementation(provided + .get("helloService"), Object.class); + assertSame(service, service2); + + Object floatsvc = _externalScope.getInterfaceImplementation(system + .getProvidedInterfaces()[1], Object.class); + assertTrue(floatsvc instanceof Float); + assertTrue((((Float) floatsvc).floatValue() - 100.345f) < 0.00001); + + assertEquals("Hello world!", ((HelloService) service).say()); + system.stop(runtime); + } + + /** + * Tests the spring component with an additional requirement from the subclass + * which is not required by the spring config files inside. + */ + public void testWithRequirementFromSubClass() { + Map required = new HashMap(); + required.put(new DefaultRequiredInterface("hello", HelloService.class), + "helloService"); + SpringComponent system = new SubSpringComponent2("system", + new String[] { HELLO_SERVICE_SPRING_WITH_REQS_XML }, + new HashMap(), required); + + HelloService helloObject = new HelloService("ladida"); + ProvidedInterface helloService = new DefaultProvidedInterface("hello", + HelloService.class); + + ProvidedInterface floatService = new DefaultProvidedInterface("float", Float.class); + + Scope scope = new DefaultScope(new ProvidedInterface[] { helloService }); + scope.publishInterface(helloService, helloObject); + scope.publishInterface(floatService, 100.234f); + system.getRequiredInterfaces()[0].setProvider(helloService); + system.getRequiredInterfaces()[1].setProvider(floatService); + + Scope runtime = system.start(scope); + system.stop(runtime); + + assertEquals(100.234f, ((Float)runtime.get("floatValue")).floatValue(), 0.0001f); + } } diff --git a/system/spring/src/test/java/org/wamblee/system/spring/SubSpringComponent.java b/system/spring/src/test/java/org/wamblee/system/spring/SubSpringComponent.java new file mode 100644 index 00000000..16279e0c --- /dev/null +++ b/system/spring/src/test/java/org/wamblee/system/spring/SubSpringComponent.java @@ -0,0 +1,45 @@ +/* + * Copyright 2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.wamblee.system.spring; + +import java.util.Map; + +import net.sf.cglib.transform.impl.AddStaticInitTransformer; + +import org.wamblee.system.core.DefaultProvidedInterface; +import org.wamblee.system.core.ProvidedInterface; +import org.wamblee.system.core.RequiredInterface; +import org.wamblee.system.core.Scope; + +public class SubSpringComponent extends SpringComponent { + + private static ProvidedInterface PROVIDED = new DefaultProvidedInterface("provided", Float.class); + + public SubSpringComponent(String aName, String[] aConfigFiles, + Map aProvided, + Map aRequired) { + super(aName, aConfigFiles, aProvided, aRequired); + addProvidedInterface(PROVIDED); + } + + @Override + protected Scope doStart(Scope aExternalScope) { + + Scope scope = super.doStart(aExternalScope); + addInterface(PROVIDED, 100.345f, aExternalScope); + return scope; + } +} diff --git a/system/spring/src/test/java/org/wamblee/system/spring/SubSpringComponent2.java b/system/spring/src/test/java/org/wamblee/system/spring/SubSpringComponent2.java new file mode 100644 index 00000000..7b67cc42 --- /dev/null +++ b/system/spring/src/test/java/org/wamblee/system/spring/SubSpringComponent2.java @@ -0,0 +1,45 @@ +/* + * Copyright 2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.wamblee.system.spring; + +import java.util.Map; + +import org.wamblee.system.core.DefaultRequiredInterface; +import org.wamblee.system.core.ProvidedInterface; +import org.wamblee.system.core.RequiredInterface; +import org.wamblee.system.core.Scope; + +public class SubSpringComponent2 extends SpringComponent { + + private static RequiredInterface REQUIRED = new DefaultRequiredInterface("required", Float.class); + + public SubSpringComponent2(String aName, String[] aConfigFiles, + Map aProvided, + Map aRequired) { + super(aName, aConfigFiles, aProvided, aRequired); + addRequiredInterface(REQUIRED); + } + + @Override + protected Scope doStart(Scope aExternalScope) { + + Scope scope = super.doStart(aExternalScope); + + float value = aExternalScope.getInterfaceImplementation(REQUIRED.getProvider(), Float.class); + scope.put("floatValue", value); + return scope; + } +} -- 2.31.1