From: Erik Brakkee Date: Wed, 14 May 2008 11:37:04 +0000 (+0000) Subject: HibernateUserAdministrationTest now based on the component mechanism. X-Git-Tag: wamblee-utils-0.7~736 X-Git-Url: http://wamblee.org/gitweb/?a=commitdiff_plain;h=001d69a3cfa9c4d949963d222c05a3134b594ddb;p=utils HibernateUserAdministrationTest now based on the component mechanism. Fixed various problems in the component mechanism itself. --- diff --git a/system/general/src/main/java/org/wamblee/system/core/Component.java b/system/general/src/main/java/org/wamblee/system/core/Component.java index 48293d45..37a9c84d 100644 --- a/system/general/src/main/java/org/wamblee/system/core/Component.java +++ b/system/general/src/main/java/org/wamblee/system/core/Component.java @@ -73,8 +73,7 @@ public interface Component { * Initialises the subsystem by starting all the services that * it described as provided. * @param aScope Scope with external interface implementations that are available. The component - * implementation can either oublish itself in this scope or it can decide to - * create a new scope with the scope passed in as a parent. + * must publish its runtime and its provided interfaces in this scope. * @return Gets an object representing the runtime of the component. */ Type start(Scope aScope); diff --git a/system/general/src/main/java/org/wamblee/system/core/Container.java b/system/general/src/main/java/org/wamblee/system/core/Container.java index a0130f7c..1c19be34 100644 --- a/system/general/src/main/java/org/wamblee/system/core/Container.java +++ b/system/general/src/main/java/org/wamblee/system/core/Container.java @@ -195,28 +195,13 @@ public class Container extends AbstractComponent { // provided interfaces of the container. // The code below assumes an exact match. if (!(provided.contains(service))) { - throw new SystemAssemblyException(getName() + ": Service '" + throw new SystemAssemblyException(getQualifiedName() + ": Service '" + service + "' is not provided by any of its components"); } } } - /** - * Starts the container. After the container is started, the container - * becomes sealed meaning that no further components, required or provided - * interfaces may be added. - * - * @return Scope. - */ - public Scope start() { - checkSealed(); - validate(); - Scope scope = super.start(new DefaultScope(new ProvidedInterface[0])); - seal(); - return scope; - } - /** * Seal the container, meaning that no further components or interfaces may * be added. @@ -233,17 +218,30 @@ public class Container extends AbstractComponent { public boolean isSealed() { return _sealed; } + + /** + * Utility method to start with an empty external scope. This is useful for + * top-level containers which are not part of another container. + * @return Scope. + */ + public Scope start() { + Scope scope = new DefaultScope(getProvidedInterfaces()); + return super.start(scope); + } @Override protected Scope doStart(Scope aExternalScope) { - return doStartOptionalDryRun(aExternalScope, false); + checkSealed(); + validate(); + Scope scope = new DefaultScope(getProvidedInterfaces(), aExternalScope); + doStartOptionalDryRun(scope, false); + seal(); + return scope; } - private Scope doStartOptionalDryRun(Scope aExternalScope, boolean aDryRun) { + private void doStartOptionalDryRun(Scope aScope, boolean aDryRun) { LOG.info("Starting '" + getQualifiedName() + "'"); - Scope scope = new DefaultScope(getProvidedInterfaces(), aExternalScope); - List> allProvided = new ArrayList>(); addProvidersOfRequiredInterfaces(allProvided); @@ -256,8 +254,8 @@ public class Container extends AbstractComponent { // Start the service. if (!aDryRun) { - Object runtime = component.start(scope); - scope.addRuntime(component, runtime); + Object runtime = component.start(aScope); + aScope.addRuntime(component, runtime); started.add(component); } @@ -272,11 +270,10 @@ public class Container extends AbstractComponent { } catch (RuntimeException e) { LOG.error(getQualifiedName() + ": could not start '" + component.getQualifiedName() + "'", e); - stopAlreadyStartedComponents(started, scope); + stopAlreadyStartedComponents(started, aScope); throw e; } } - return scope; } private void addProvidersOfRequiredInterfaces( diff --git a/system/general/src/main/java/org/wamblee/system/core/DefaultProvidedInterface.java b/system/general/src/main/java/org/wamblee/system/core/DefaultProvidedInterface.java index 3eb33ddc..10b8f618 100644 --- a/system/general/src/main/java/org/wamblee/system/core/DefaultProvidedInterface.java +++ b/system/general/src/main/java/org/wamblee/system/core/DefaultProvidedInterface.java @@ -15,7 +15,11 @@ */ package org.wamblee.system.core; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; + /** * Default implementation of a service descriptor. @@ -77,4 +81,32 @@ public class DefaultProvidedInterface implements ProvidedInterface { } return buf.toString(); } + + @Override + public boolean equals(Object aObj) { + if ( !(aObj instanceof DefaultProvidedInterface)) { + return false; + } + DefaultProvidedInterface provided = (DefaultProvidedInterface)aObj; + return getEqualsRepresentation().equals(provided.getEqualsRepresentation()); + } + + @Override + public int hashCode() { + return getEqualsRepresentation().hashCode(); + } + + + private String getEqualsRepresentation() { + List result = new ArrayList(); + for (Class cls: _interfaces) { + result.add(cls.getName()); + } + Collections.sort(result); + String value = ""; + for (String str: result) { + value += ":" + str; + } + return value; + } } diff --git a/system/general/src/main/java/org/wamblee/system/core/DefaultScope.java b/system/general/src/main/java/org/wamblee/system/core/DefaultScope.java index 5a09f942..51949ca1 100644 --- a/system/general/src/main/java/org/wamblee/system/core/DefaultScope.java +++ b/system/general/src/main/java/org/wamblee/system/core/DefaultScope.java @@ -21,11 +21,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.UUID; public class DefaultScope implements Scope { private List _parents; - private int _count; private Map _properties; private Map _runtimes; private Map _provided; @@ -42,7 +42,6 @@ public class DefaultScope implements Scope { public DefaultScope(ProvidedInterface[] aExternallyProvided, List aParent) { _parents = new ArrayList(aParent); - _count = 0; _properties = new HashMap(); _runtimes = new HashMap(); _provided = new HashMap(); @@ -82,7 +81,7 @@ public class DefaultScope implements Scope { @Override synchronized public void publishInterface(ProvidedInterface aInterface, Object aImplementation) { - String id = "" + _count++; + String id = UUID.randomUUID().toString(); _provided.put(id, new ProvidedInterfaceImplementation(aInterface, aImplementation)); aInterface.setUniqueId(id); diff --git a/system/general/src/test/java/org/wamblee/system/core/ContainerTest.java b/system/general/src/test/java/org/wamblee/system/core/ContainerTest.java index 4c451337..2104e3a9 100644 --- a/system/general/src/test/java/org/wamblee/system/core/ContainerTest.java +++ b/system/general/src/test/java/org/wamblee/system/core/ContainerTest.java @@ -504,4 +504,22 @@ public class ContainerTest extends TestCase { assertEquals(env1.getString(), app.getString()); assertFalse(env2.getString().equals(app.getString())); } + + public void testProvidedInDifferentScopes() { + // Scoping problem occurred. Externally and internally provided components clashed + // because unique id generation in the scope was wrong. + + StringComponent str = new StringComponent("string"); + Application app = new Application("app"); + Container container = new Container("top").addComponent(str).addComponent(app); + container.addRequiredInterface(new DefaultRequiredInterface("integer", Integer.class)); + + ProvidedInterface provided = new DefaultProvidedInterface("hallo", Integer.class); + container.getRequiredInterfaces()[0] + .setProvider(provided); + + Scope external = new DefaultScope(new ProvidedInterface[0]); + external.publishInterface(provided, 100); + Scope scope = container.start(external); + } } diff --git a/system/general/src/test/java/org/wamblee/system/core/DefaultScopeTest.java b/system/general/src/test/java/org/wamblee/system/core/DefaultScopeTest.java new file mode 100644 index 00000000..8458c326 --- /dev/null +++ b/system/general/src/test/java/org/wamblee/system/core/DefaultScopeTest.java @@ -0,0 +1,51 @@ +/* + * 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.core; + +import junit.framework.TestCase; + +public class DefaultScopeTest extends TestCase { + + public void testLookup() { + ProvidedInterface provider = new DefaultProvidedInterface("x", Integer.class); + Scope scope = new DefaultScope(new ProvidedInterface[0]); + + assertNull(provider.getUniqueId()); + scope.publishInterface(provider, 100); + assertNotNull(provider.getUniqueId()); + } + + public void testNestedLookup() { + ProvidedInterface provider1 = new DefaultProvidedInterface("x", Integer.class); + Scope parent = new DefaultScope(new ProvidedInterface[0]); + + parent.publishInterface(provider1, 100); + + ProvidedInterface provider2 = new DefaultProvidedInterface("y", String.class); + Scope child = new DefaultScope(new ProvidedInterface[0], parent); + + child.publishInterface(provider2, "hallo"); + + assertNotNull(provider1.getUniqueId()); + assertNotNull(provider2.getUniqueId()); + + assertFalse(provider1.getUniqueId().equals(provider2.getUniqueId())); + + assertEquals(100, child.getInterfaceImplementation(provider1, Integer.class).intValue()); + assertEquals("hallo", child.getInterfaceImplementation(provider2, String.class)); + } + +} diff --git a/system/general/src/test/java/org/wamblee/system/core/IntegerComponent.java b/system/general/src/test/java/org/wamblee/system/core/IntegerComponent.java new file mode 100644 index 00000000..0af4ae3d --- /dev/null +++ b/system/general/src/test/java/org/wamblee/system/core/IntegerComponent.java @@ -0,0 +1,82 @@ +/* + * Copyright 2007 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.core; + +import javax.sql.DataSource; + +import org.wamblee.system.core.AbstractComponent; +import org.wamblee.system.core.DefaultProvidedInterface; +import org.wamblee.system.core.ProvidedInterface; +import org.wamblee.system.core.RequiredInterface; +import org.wamblee.test.EventTracker; + +public class IntegerComponent extends AbstractComponent { + + private static final ProvidedInterface[] provided(String aPrefix) { + return new ProvidedInterface[] { + new DefaultProvidedInterface(aPrefix + "integer", Integer.class) }; + } + + private EventTracker _tracker; + private double _random; + + public IntegerComponent() { + this("environment"); + } + + public IntegerComponent(String aName) { + this(aName, ""); + } + + public IntegerComponent(String aName, String aPrefix) { + super(aName, provided(aPrefix), new RequiredInterface[0]); + _random = Math.random(); + } + + + + public IntegerComponent(EventTracker aTracker) { + this(); + _tracker = aTracker; + } + + public Integer getInteger() { + return 2; + } + + @Override + protected Object doStart(Scope aScope) { + addInterface(getProvidedInterfaces()[1], getInteger(), aScope); + track("start." + getName()); + return _random; + } + + @Override + protected void doStop(Object aRuntime) { + track("stop." + getName()); + if (_random != (Double) aRuntime) { + throw new IllegalArgumentException("Wrong runtime: expected " + + _random + " but got " + aRuntime); + } + } + + private void track(String aString) { + if (_tracker == null) { + return; + } + _tracker.eventOccurred(aString); + } +} diff --git a/system/general/src/test/java/org/wamblee/system/core/StringComponent.java b/system/general/src/test/java/org/wamblee/system/core/StringComponent.java new file mode 100644 index 00000000..990adaf0 --- /dev/null +++ b/system/general/src/test/java/org/wamblee/system/core/StringComponent.java @@ -0,0 +1,86 @@ +/* + * Copyright 2007 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.core; + +import javax.sql.DataSource; + +import org.wamblee.system.core.AbstractComponent; +import org.wamblee.system.core.DefaultProvidedInterface; +import org.wamblee.system.core.ProvidedInterface; +import org.wamblee.system.core.RequiredInterface; +import org.wamblee.test.EventTracker; + +public class StringComponent extends AbstractComponent { + + private static final ProvidedInterface[] provided(String aPrefix) { + return new ProvidedInterface[] { + new DefaultProvidedInterface(aPrefix + "datasource", String.class) }; + } + + private EventTracker _tracker; + private double _random; + + public StringComponent() { + this("environment"); + } + + public StringComponent(String aName) { + this(aName, ""); + } + + public StringComponent(String aName, String aPrefix) { + super(aName, provided(aPrefix), new RequiredInterface[0]); + _random = Math.random(); + } + + + + public StringComponent(EventTracker aTracker) { + this(); + _tracker = aTracker; + } + + public Integer getInteger() { + return 2; + } + + public String getString() { + return getName() + ".hello"; + } + + @Override + protected Object doStart(Scope aScope) { + addInterface(getProvidedInterfaces()[0], getString(), aScope); + track("start." + getName()); + return _random; + } + + @Override + protected void doStop(Object aRuntime) { + track("stop." + getName()); + if (_random != (Double) aRuntime) { + throw new IllegalArgumentException("Wrong runtime: expected " + + _random + " but got " + aRuntime); + } + } + + private void track(String aString) { + if (_tracker == null) { + return; + } + _tracker.eventOccurred(aString); + } +}