You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by jm...@apache.org on 2007/01/09 16:02:46 UTC

svn commit: r494426 - in /incubator/tuscany/java/sca: kernel/core/src/main/java/org/apache/tuscany/core/component/event/ kernel/core/src/main/java/org/apache/tuscany/core/component/scope/ kernel/core/src/main/java/org/apache/tuscany/core/services/store...

Author: jmarino
Date: Tue Jan  9 07:02:43 2007
New Revision: 494426

URL: http://svn.apache.org/viewvc?view=rev&rev=494426
Log:
support for destroy notification of expired conversational resources for the in-memory and journal-based implementations of Store

Added:
    incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerDestroyOnExpirationTestContainer.java   (with props)
    incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/event/AbstractEventPublisher.java   (with props)
    incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/StoreExpirationEvent.java   (with props)
    incubator/tuscany/java/sca/kernel/spi/src/test/java/org/apache/tuscany/spi/event/
    incubator/tuscany/java/sca/kernel/spi/src/test/java/org/apache/tuscany/spi/event/AbstractEventPublisherTestCase.java   (with props)
    incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/JournalStoreExpireTestCase.java   (with props)
Removed:
    incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/LRUCache.java
    incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/LRUCacheTestCase.java
Modified:
    incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/component/event/AbstractEvent.java
    incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainer.java
    incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/services/store/memory/MemoryStore.java
    incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerMaxAgeTestCase.java
    incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerMaxIdleTimeTestCase.java
    incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/services/store/memory/MemoryStoreTestCase.java
    incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/Store.java
    incubator/tuscany/java/sca/services/persistence/store.jdbc/src/main/java/org/apache/tuscany/service/persistence/store/jdbc/JDBCStore.java
    incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/Journal.java
    incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/JournalStore.java
    incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/RecordKey.java
    incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/RecordKeyTestCase.java

Modified: incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/component/event/AbstractEvent.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/component/event/AbstractEvent.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/component/event/AbstractEvent.java (original)
+++ incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/component/event/AbstractEvent.java Tue Jan  9 07:02:43 2007
@@ -26,8 +26,7 @@
  * @version $$Rev$$ $$Date$$
  */
 public abstract class AbstractEvent implements Event {
-
-    protected transient Object source;
+    protected Object source;
 
     public AbstractEvent(Object source) {
         assert source != null : "Source id was null";

Modified: incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainer.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainer.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainer.java (original)
+++ incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainer.java Tue Jan  9 07:02:43 2007
@@ -23,6 +23,7 @@
 
 import org.apache.tuscany.spi.component.AtomicComponent;
 import org.apache.tuscany.spi.component.PersistenceException;
+import org.apache.tuscany.spi.component.SCAObject;
 import org.apache.tuscany.spi.component.ScopeContainer;
 import org.apache.tuscany.spi.component.ScopeContainerMonitor;
 import org.apache.tuscany.spi.component.TargetDestructionException;
@@ -30,8 +31,10 @@
 import org.apache.tuscany.spi.component.TargetResolutionException;
 import org.apache.tuscany.spi.component.WorkContext;
 import org.apache.tuscany.spi.event.Event;
+import org.apache.tuscany.spi.event.RuntimeEventListener;
 import org.apache.tuscany.spi.model.Scope;
 import org.apache.tuscany.spi.services.store.Store;
+import org.apache.tuscany.spi.services.store.StoreExpirationEvent;
 import org.apache.tuscany.spi.services.store.StoreReadException;
 import org.apache.tuscany.spi.services.store.StoreWriteException;
 
@@ -44,9 +47,12 @@
     private Store nonDurableStore;
     private Map<AtomicComponent, AtomicComponent> components;
 
-    public ConversationalScopeContainer(Store store, WorkContext workContext, ScopeContainerMonitor monitor) {
+    public ConversationalScopeContainer(Store store, WorkContext workContext, final ScopeContainerMonitor monitor) {
         super(workContext, monitor);
         this.nonDurableStore = store;
+        if (store != null) {
+            store.addListener(new ExpirationListener(monitor));
+        }
         components = new ConcurrentHashMap<AtomicComponent, AtomicComponent>();
     }
 
@@ -184,6 +190,31 @@
             return now + component.getMaxIdleTime();
         } else {
             return Store.DEFAULT_EXPIRATION_OFFSET;
+        }
+    }
+
+    /**
+     * Receives expiration events from the store and notifies the corresponding atomic component
+     */
+    private static class ExpirationListener implements RuntimeEventListener {
+        private final ScopeContainerMonitor monitor;
+
+        public ExpirationListener(ScopeContainerMonitor monitor) {
+            this.monitor = monitor;
+        }
+
+        public void onEvent(Event event) {
+            if (event instanceof StoreExpirationEvent) {
+                StoreExpirationEvent expiration = (StoreExpirationEvent) event;
+                SCAObject object = expiration.getOwner();
+                assert object instanceof AtomicComponent;
+                AtomicComponent owner = (AtomicComponent) object;
+                try {
+                    owner.destroy(expiration.getInstance());
+                } catch (TargetDestructionException e) {
+                    monitor.destructionError(e);
+                }
+            }
         }
     }
 }

Modified: incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/services/store/memory/MemoryStore.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/services/store/memory/MemoryStore.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/services/store/memory/MemoryStore.java (original)
+++ incubator/tuscany/java/sca/kernel/core/src/main/java/org/apache/tuscany/core/services/store/memory/MemoryStore.java Tue Jan  9 07:02:43 2007
@@ -28,12 +28,14 @@
 import org.osoa.sca.annotations.EagerInit;
 import org.osoa.sca.annotations.Init;
 import org.osoa.sca.annotations.Property;
-import org.osoa.sca.annotations.Scope;
+import org.osoa.sca.annotations.Service;
 
 import org.apache.tuscany.spi.component.SCAObject;
+import org.apache.tuscany.spi.event.AbstractEventPublisher;
 import org.apache.tuscany.spi.services.store.DuplicateRecordException;
 import org.apache.tuscany.spi.services.store.RecoveryListener;
 import org.apache.tuscany.spi.services.store.Store;
+import org.apache.tuscany.spi.services.store.StoreExpirationEvent;
 import org.apache.tuscany.spi.services.store.StoreMonitor;
 import org.apache.tuscany.spi.services.store.StoreWriteException;
 
@@ -44,9 +46,9 @@
  *
  * @version $Rev$ $Date$
  */
-@Scope("COMPOSITE")
+@Service(Store.class)
 @EagerInit
-public class MemoryStore implements Store {
+public class MemoryStore extends AbstractEventPublisher implements Store {
     private Map<SCAObject, Map<String, Record>> store;
     // TODO integrate with a core threading scheme
     private ScheduledExecutorService scheduler;
@@ -177,11 +179,16 @@
 
         public void run() {
             long now = System.currentTimeMillis();
-            for (Map<String, Record> map : store.values()) {
-                for (Map.Entry<String, Record> entry : map.entrySet()) {
+            for (Map.Entry<SCAObject, Map<String, Record>> entries : store.entrySet()) {
+                for (Map.Entry<String, Record> entry : entries.getValue().entrySet()) {
                     final long expiration = entry.getValue().expiration;
                     if (expiration != NEVER && now >= expiration) {
-                        map.remove(entry.getKey());
+                        SCAObject owner = entries.getKey();
+                        Object instance = entry.getValue().getData();
+                        // notify listeners of the expiration 
+                        StoreExpirationEvent event = new StoreExpirationEvent(this, owner, instance);
+                        publish(event);
+                        entries.getValue().remove(entry.getKey());
                     }
                 }
             }

Added: incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerDestroyOnExpirationTestContainer.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerDestroyOnExpirationTestContainer.java?view=auto&rev=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerDestroyOnExpirationTestContainer.java (added)
+++ incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerDestroyOnExpirationTestContainer.java Tue Jan  9 07:02:43 2007
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.core.component.scope;
+
+import org.apache.tuscany.spi.component.AtomicComponent;
+import org.apache.tuscany.spi.component.SCAObject;
+import org.apache.tuscany.spi.component.ScopeContainer;
+import org.apache.tuscany.spi.component.WorkContext;
+import org.apache.tuscany.spi.event.Event;
+import org.apache.tuscany.spi.event.EventFilter;
+import org.apache.tuscany.spi.event.RuntimeEventListener;
+import org.apache.tuscany.spi.services.store.RecoveryListener;
+import org.apache.tuscany.spi.services.store.Store;
+import org.apache.tuscany.spi.services.store.StoreExpirationEvent;
+import org.apache.tuscany.spi.services.store.StoreReadException;
+import org.apache.tuscany.spi.services.store.StoreWriteException;
+
+import junit.framework.TestCase;
+import org.apache.tuscany.core.component.WorkContextImpl;
+import org.easymock.EasyMock;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ConversationalScopeContainerDestroyOnExpirationTestContainer extends TestCase {
+    private ScopeContainer container;
+    private TestStore store;
+    private AtomicComponent component;
+
+    /**
+     * Verifies the scope container registers a callback listener for component instance destroy events when a
+     * conversational instance expires
+     */
+    public void testDestroyNotification() throws Exception {
+        store.getListener().onEvent(new StoreExpirationEvent(this, component, new Object()));
+        EasyMock.verify(component);
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        component = EasyMock.createMock(AtomicComponent.class);
+        component.destroy(EasyMock.isA(Object.class));
+        EasyMock.replay(component);
+        store = new TestStore();
+        WorkContext context = new WorkContextImpl();
+        container = new ConversationalScopeContainer(store, context, null);
+        container.start();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        container.stop();
+    }
+
+    private class TestStore implements Store {
+        private RuntimeEventListener listener;
+
+        public RuntimeEventListener getListener() {
+            return listener;
+        }
+
+        public void insertRecord(SCAObject owner, String id, Object object, long expiration)
+            throws StoreWriteException {
+
+        }
+
+        public void updateRecord(SCAObject owner, String id, Object object, long expiration)
+            throws StoreWriteException {
+
+        }
+
+        public Object readRecord(SCAObject owner, String id) throws StoreReadException {
+            return null;
+        }
+
+        public void removeRecord(SCAObject owner, String id) throws StoreWriteException {
+
+        }
+
+        public void removeRecords() throws StoreWriteException {
+
+        }
+
+        public void recover(RecoveryListener listener) throws StoreReadException {
+
+        }
+
+        public void publish(Event object) {
+
+        }
+
+        public void addListener(RuntimeEventListener listener) {
+            this.listener = listener;
+        }
+
+        public void addListener(EventFilter filter, RuntimeEventListener listener) {
+
+        }
+
+        public void removeListener(RuntimeEventListener listener) {
+
+        }
+    }
+
+}

Propchange: incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerDestroyOnExpirationTestContainer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerDestroyOnExpirationTestContainer.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerMaxAgeTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerMaxAgeTestCase.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerMaxAgeTestCase.java (original)
+++ incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerMaxAgeTestCase.java Tue Jan  9 07:02:43 2007
@@ -22,6 +22,7 @@
 import org.apache.tuscany.spi.component.SCAObject;
 import org.apache.tuscany.spi.component.ScopeContainer;
 import org.apache.tuscany.spi.component.WorkContext;
+import org.apache.tuscany.spi.event.RuntimeEventListener;
 import org.apache.tuscany.spi.model.Scope;
 import org.apache.tuscany.spi.services.store.Store;
 
@@ -56,6 +57,7 @@
         EasyMock.replay(component);
         store = EasyMock.createMock(Store.class);
         EasyMock.expect(store.readRecord(EasyMock.isA(SCAObject.class), EasyMock.isA(String.class))).andReturn(foo);
+        store.addListener(EasyMock.isA(RuntimeEventListener.class));
         EasyMock.replay(store);
         container = new ConversationalScopeContainer(store, context, null);
         container.start();

Modified: incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerMaxIdleTimeTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerMaxIdleTimeTestCase.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerMaxIdleTimeTestCase.java (original)
+++ incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainerMaxIdleTimeTestCase.java Tue Jan  9 07:02:43 2007
@@ -22,6 +22,7 @@
 import org.apache.tuscany.spi.component.SCAObject;
 import org.apache.tuscany.spi.component.ScopeContainer;
 import org.apache.tuscany.spi.component.WorkContext;
+import org.apache.tuscany.spi.event.RuntimeEventListener;
 import org.apache.tuscany.spi.model.Scope;
 import org.apache.tuscany.spi.services.store.Store;
 
@@ -55,6 +56,7 @@
         EasyMock.replay(component);
         store = EasyMock.createMock(Store.class);
         EasyMock.expect(store.readRecord(EasyMock.isA(SCAObject.class), EasyMock.isA(String.class))).andReturn(foo);
+        store.addListener(EasyMock.isA(RuntimeEventListener.class));
         store.updateRecord(EasyMock.isA(SCAObject.class),
             EasyMock.isA(String.class),
             EasyMock.eq(foo),

Modified: incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/services/store/memory/MemoryStoreTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/services/store/memory/MemoryStoreTestCase.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/services/store/memory/MemoryStoreTestCase.java (original)
+++ incubator/tuscany/java/sca/kernel/core/src/test/java/org/apache/tuscany/core/services/store/memory/MemoryStoreTestCase.java Tue Jan  9 07:02:43 2007
@@ -19,14 +19,19 @@
 package org.apache.tuscany.core.services.store.memory;
 
 import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.tuscany.spi.component.AtomicComponent;
+import org.apache.tuscany.spi.event.RuntimeEventListener;
 import org.apache.tuscany.spi.services.store.DuplicateRecordException;
 import org.apache.tuscany.spi.services.store.Store;
+import org.apache.tuscany.spi.services.store.StoreExpirationEvent;
 import org.apache.tuscany.spi.services.store.StoreMonitor;
 
 import junit.framework.TestCase;
 import org.easymock.EasyMock;
+import org.easymock.IAnswer;
 
 /**
  * @version $Rev$ $Date$
@@ -46,6 +51,33 @@
         Thread.sleep(100);
         assertNull(store.readRecord(component, id));
         store.destroy();
+    }
+
+    public void testNotifyOnEviction() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        RuntimeEventListener listener = EasyMock.createMock(RuntimeEventListener.class);
+        listener.onEvent(EasyMock.isA(StoreExpirationEvent.class));
+        org.easymock.classextension.EasyMock.expectLastCall().andStubAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                latch.countDown();
+                return null;
+            }
+        });
+        EasyMock.replay(listener);
+        MemoryStore store = new MemoryStore(monitor);
+        store.addListener(listener);
+        store.setReaperInterval(10);
+        store.init();
+        AtomicComponent component = EasyMock.createNiceMock(AtomicComponent.class);
+        EasyMock.replay(component);
+        String id = UUID.randomUUID().toString();
+        Object value = new Object();
+        store.insertRecord(component, id, value, 1);
+        if (!latch.await(1000, TimeUnit.MILLISECONDS)) {
+            // failed to notify listener
+            fail();
+        }
+        EasyMock.verify(listener);
     }
 
     public void testNoEviction() throws Exception {

Added: incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/event/AbstractEventPublisher.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/event/AbstractEventPublisher.java?view=auto&rev=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/event/AbstractEventPublisher.java (added)
+++ incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/event/AbstractEventPublisher.java Tue Jan  9 07:02:43 2007
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.spi.event;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.tuscany.spi.component.PrepareException;
+
+/**
+ * Base implementation of an <code>EventPublisher</code>
+ *
+ * @version $Rev$ $Date$
+ */
+public abstract class AbstractEventPublisher implements EventPublisher {
+    protected static final EventFilter TRUE_FILTER = new TrueFilter();
+    protected Map<EventFilter, List<RuntimeEventListener>> listeners;
+
+    public void addListener(RuntimeEventListener listener) {
+        addListener(TRUE_FILTER, listener);
+    }
+
+    public void removeListener(RuntimeEventListener listener) {
+        assert listener != null : "Listener cannot be null";
+        synchronized (getListeners()) {
+            for (List<RuntimeEventListener> currentList : getListeners().values()) {
+                for (RuntimeEventListener current : currentList) {
+                    if (current == listener) {
+                        currentList.remove(current);
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    public void addListener(EventFilter filter, RuntimeEventListener listener) {
+        assert listener != null : "Listener cannot be null";
+        synchronized (getListeners()) {
+            List<RuntimeEventListener> list = getListeners().get(filter);
+            if (list == null) {
+                list = new CopyOnWriteArrayList<RuntimeEventListener>();
+                listeners.put(filter, list);
+            }
+            list.add(listener);
+        }
+    }
+
+    public void publish(Event event) {
+        assert event != null : "Event object was null";
+        for (Map.Entry<EventFilter, List<RuntimeEventListener>> entry : getListeners().entrySet()) {
+            if (entry.getKey().match(event)) {
+                for (RuntimeEventListener listener : entry.getValue()) {
+                    listener.onEvent(event);
+                }
+            }
+        }
+    }
+
+    protected Map<EventFilter, List<RuntimeEventListener>> getListeners() {
+        if (listeners == null) {
+            listeners = new ConcurrentHashMap<EventFilter, List<RuntimeEventListener>>();
+        }
+        return listeners;
+    }
+
+    public void prepare() throws PrepareException {
+
+    }
+
+}

Propchange: incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/event/AbstractEventPublisher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/event/AbstractEventPublisher.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/Store.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/Store.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/Store.java (original)
+++ incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/Store.java Tue Jan  9 07:02:43 2007
@@ -19,6 +19,7 @@
 package org.apache.tuscany.spi.services.store;
 
 import org.apache.tuscany.spi.component.SCAObject;
+import org.apache.tuscany.spi.event.EventPublisher;
 
 /**
  * Implementations provide a persistent store for runtime data such as conversational state. A persistent store could be
@@ -27,7 +28,7 @@
  *
  * @version $Rev$ $Date$
  */
-public interface Store {
+public interface Store extends EventPublisher {
 
     /* Used to indicate an the default expiration offset for records for the store */
     long DEFAULT_EXPIRATION_OFFSET = -1;

Added: incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/StoreExpirationEvent.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/StoreExpirationEvent.java?view=auto&rev=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/StoreExpirationEvent.java (added)
+++ incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/StoreExpirationEvent.java Tue Jan  9 07:02:43 2007
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.spi.services.store;
+
+import org.apache.tuscany.spi.component.SCAObject;
+import org.apache.tuscany.spi.event.Event;
+
+/**
+ * Fired when a store implementation expires a resource
+ *
+ * @version $Rev$ $Date$
+ */
+public class StoreExpirationEvent implements Event {
+    private Object source;
+    private SCAObject owner;
+    private Object instance;
+
+    /**
+     * Constructor.
+     *
+     * @param source   the source of the event
+     * @param owner    the owner of the expiring object
+     * @param instance the expiring object
+     */
+    public StoreExpirationEvent(Object source, SCAObject owner, Object instance) {
+        assert source != null;
+        assert owner != null;
+        assert instance != null;
+        this.source = source;
+        this.owner = owner;
+        this.instance = instance;
+    }
+
+    public Object getSource() {
+        return source;
+    }
+
+    /**
+     * Returns the owner of the expiring object.
+     *
+     * @return the owner of the expiring object.
+     */
+    public SCAObject getOwner() {
+        return owner;
+    }
+
+    /**
+     * Returns the expiring object.
+     *
+     * @return the expiring object.
+     */
+    public Object getInstance() {
+        return instance;
+    }
+}

Propchange: incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/StoreExpirationEvent.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/tuscany/java/sca/kernel/spi/src/main/java/org/apache/tuscany/spi/services/store/StoreExpirationEvent.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: incubator/tuscany/java/sca/kernel/spi/src/test/java/org/apache/tuscany/spi/event/AbstractEventPublisherTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/kernel/spi/src/test/java/org/apache/tuscany/spi/event/AbstractEventPublisherTestCase.java?view=auto&rev=494426
==============================================================================
--- incubator/tuscany/java/sca/kernel/spi/src/test/java/org/apache/tuscany/spi/event/AbstractEventPublisherTestCase.java (added)
+++ incubator/tuscany/java/sca/kernel/spi/src/test/java/org/apache/tuscany/spi/event/AbstractEventPublisherTestCase.java Tue Jan  9 07:02:43 2007
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.spi.event;
+
+
+import junit.framework.TestCase;
+import org.easymock.EasyMock;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class AbstractEventPublisherTestCase extends TestCase {
+    EventPublisher publisher;
+
+    public void testFireListener() {
+        Event event = new TestEvent();
+        RuntimeEventListener listener = EasyMock.createMock(RuntimeEventListener.class);
+        listener.onEvent(EasyMock.same(event));
+        EasyMock.expectLastCall();
+        EasyMock.replay(listener);
+        publisher.addListener(listener);
+        publisher.publish(event);
+        EasyMock.verify(publisher);
+    }
+
+    public void testRemoveListener() {
+        Event event = new TestEvent();
+        RuntimeEventListener listener = EasyMock.createMock(RuntimeEventListener.class);
+        EasyMock.replay(listener);
+        publisher.addListener(listener);
+        publisher.removeListener(listener);
+        publisher.publish(event);
+        EasyMock.verify(publisher);
+    }
+
+    public void testFalseFilterListener() {
+        Event event = new TestEvent();
+        RuntimeEventListener listener = EasyMock.createMock(RuntimeEventListener.class);
+        EasyMock.replay(listener);
+        publisher.addListener(new FalseFilter(), listener);
+        publisher.publish(event);
+        EasyMock.verify(publisher);
+    }
+
+    public void testTrueFilterListener() {
+        Event event = new TestEvent();
+        RuntimeEventListener listener = EasyMock.createMock(RuntimeEventListener.class);
+        listener.onEvent(EasyMock.same(event));
+        EasyMock.expectLastCall();
+        EasyMock.replay(listener);
+        publisher.addListener(new TrueFilter(), listener);
+        publisher.publish(event);
+        EasyMock.verify(publisher);
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        publisher = new AbstractEventPublisher() {
+        };
+    }
+
+    private class TestEvent implements Event {
+        public Object getSource() {
+            return null;
+        }
+    }
+
+    private class FalseFilter implements EventFilter {
+
+        public boolean match(Event event) {
+            return false;
+        }
+    }
+
+
+}

Propchange: incubator/tuscany/java/sca/kernel/spi/src/test/java/org/apache/tuscany/spi/event/AbstractEventPublisherTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/tuscany/java/sca/kernel/spi/src/test/java/org/apache/tuscany/spi/event/AbstractEventPublisherTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/tuscany/java/sca/services/persistence/store.jdbc/src/main/java/org/apache/tuscany/service/persistence/store/jdbc/JDBCStore.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/services/persistence/store.jdbc/src/main/java/org/apache/tuscany/service/persistence/store/jdbc/JDBCStore.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/services/persistence/store.jdbc/src/main/java/org/apache/tuscany/service/persistence/store/jdbc/JDBCStore.java (original)
+++ incubator/tuscany/java/sca/services/persistence/store.jdbc/src/main/java/org/apache/tuscany/service/persistence/store/jdbc/JDBCStore.java Tue Jan  9 07:02:43 2007
@@ -32,9 +32,11 @@
 import org.osoa.sca.annotations.Init;
 import org.osoa.sca.annotations.Property;
 import org.osoa.sca.annotations.Resource;
+import org.osoa.sca.annotations.Service;
 
 import org.apache.tuscany.spi.annotation.Autowire;
 import org.apache.tuscany.spi.component.SCAObject;
+import org.apache.tuscany.spi.event.AbstractEventPublisher;
 import org.apache.tuscany.spi.services.store.RecoveryListener;
 import org.apache.tuscany.spi.services.store.Store;
 import org.apache.tuscany.spi.services.store.StoreMonitor;
@@ -45,11 +47,15 @@
 
 /**
  * A store implementation that uses a relational database to persist records transactionally.
+ * <p/>
+ * Note this implementation does not yet support destruction callbacks for expired. In order to support this, expired
+ * records must be rehydrated and deleted individually.
  *
  * @version $Rev$ $Date$
  */
+@Service(Store.class)
 @EagerInit
-public class JDBCStore implements Store {
+public class JDBCStore extends AbstractEventPublisher implements Store {
     private DataSource dataSource;
     private StoreMonitor monitor;
     private Converter converter;

Modified: incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/Journal.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/Journal.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/Journal.java (original)
+++ incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/Journal.java Tue Jan  9 07:02:43 2007
@@ -46,7 +46,7 @@
 
     /**
      * Writes a header record to the log. The format of the header is defined by {@link
-     * SerializationHelper#createHeader(short, int, String, java.util.UUID, long)}
+     * SerializationHelper#createHeader(short, int, String, String, long)}
      *
      * @param bytes the record as a byte array
      * @param force true if the disk write should be forced

Modified: incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/JournalStore.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/JournalStore.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/JournalStore.java (original)
+++ incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/JournalStore.java Tue Jan  9 07:02:43 2007
@@ -32,13 +32,16 @@
 import org.osoa.sca.annotations.EagerInit;
 import org.osoa.sca.annotations.Init;
 import org.osoa.sca.annotations.Property;
+import org.osoa.sca.annotations.Service;
 
 import org.apache.tuscany.spi.component.SCAObject;
+import org.apache.tuscany.spi.event.AbstractEventPublisher;
 import org.apache.tuscany.spi.services.store.RecoveryListener;
 import org.apache.tuscany.spi.services.store.Store;
 import org.apache.tuscany.spi.services.store.StoreMonitor;
 import org.apache.tuscany.spi.services.store.StoreReadException;
 import org.apache.tuscany.spi.services.store.StoreWriteException;
+import org.apache.tuscany.spi.services.store.StoreExpirationEvent;
 
 import org.apache.tuscany.api.annotation.Monitor;
 import static org.apache.tuscany.persistence.store.journal.SerializationHelper.partition;
@@ -83,8 +86,9 @@
  *
  * @version $Rev$ $Date$
  */
+@Service(Store.class)
 @EagerInit
-public class JournalStore implements Store {
+public class JournalStore extends AbstractEventPublisher implements Store {
     private static final int UNITIALIZED = -99;
 
     // the cache of active records
@@ -388,7 +392,7 @@
 
     public Object readRecord(SCAObject owner, String id) throws StoreReadException {
         RecordEntry record;
-        RecordKey key = new RecordKey(id, owner.getCanonicalName());
+        RecordKey key = new RecordKey(id, owner);
         record = cache.get(key);
         if (record == null) {
             return null;
@@ -402,7 +406,7 @@
     public void removeRecord(SCAObject owner, String id) throws StoreWriteException {
         try {
             journal.writeHeader(serializeHeader(Header.DELETE, 0, owner.getCanonicalName(), id, NEVER), true);
-            RecordKey key = new RecordKey(id, owner.getCanonicalName());
+            RecordKey key = new RecordKey(id, owner);
             // remove from the cache
             cache.remove(key);
         } catch (IOException e) {
@@ -456,7 +460,7 @@
             }
             // add last record using a forced write
             journal.writeBlock(bytes.get(bytes.size() - 1), recordId, true);
-            RecordKey key = new RecordKey(id, canonicalName);
+            RecordKey key = new RecordKey(id, owner);
             // add to the entry in the cache
             cache.put(key, new RecordEntry(serializable, operation, keys, expiration));
         } catch (IOException e) {
@@ -546,11 +550,17 @@
                         RecordEntry record = entry.getValue();
                         if (record.getExpiration() <= now) {
                             try {
-                                String ownerName = key.getOwnerName();
+                                String ownerName = key.getOwner().getCanonicalName();
                                 String id = key.getId();
                                 byte[] header =
                                     SerializationHelper.serializeHeader(Header.DELETE, 0, ownerName, id, Store.NEVER);
                                 journal.writeHeader(header, false);
+                                // notify listeners
+                                SCAObject owner = key.getOwner();
+                                Object instance = record.getObject();
+                                // notify listeners of the expiration 
+                                StoreExpirationEvent event = new StoreExpirationEvent(this, owner, instance);
+                                publish(event);
                             } catch (IOException e) {
                                 monitor.error(e);
                             } catch (StoreWriteException e) {

Modified: incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/RecordKey.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/RecordKey.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/RecordKey.java (original)
+++ incubator/tuscany/java/sca/services/persistence/store.journal/src/main/java/org/apache/tuscany/persistence/store/journal/RecordKey.java Tue Jan  9 07:02:43 2007
@@ -18,6 +18,8 @@
  */
 package org.apache.tuscany.persistence.store.journal;
 
+import org.apache.tuscany.spi.component.SCAObject;
+
 /**
  * Used by the store cache to retrieve record entries
  *
@@ -26,19 +28,19 @@
 public class RecordKey {
 
     private String id;
-    private String ownerName;
+    private SCAObject owner;
 
-    public RecordKey(String id, String ownerName) {
+    public RecordKey(String id, SCAObject owner) {
         this.id = id;
-        this.ownerName = ownerName;
+        this.owner = owner;
     }
 
     public String getId() {
         return id;
     }
 
-    public String getOwnerName() {
-        return ownerName;
+    public SCAObject getOwner() {
+        return owner;
     }
 
     public boolean equals(Object o) {
@@ -52,13 +54,14 @@
         if (id != null ? !id.equals(recordKey.id) : recordKey.id != null) {
             return false;
         }
-        return !(ownerName != null ? !ownerName.equals(recordKey.ownerName) : recordKey.ownerName != null);
+        return !(owner != null ? !owner.getCanonicalName().equals(recordKey.owner.getCanonicalName()) :
+            recordKey.owner != null);
     }
 
     public int hashCode() {
         int result;
-        result = id != null ? id.hashCode() : 0;
-        result = 29 * result + (ownerName != null ? ownerName.hashCode() : 0);
+        result = (id != null ? id.hashCode() : 0);
+        result = 31 * result + (owner != null ? owner.hashCode() : 0);
         return result;
     }
 }

Added: incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/JournalStoreExpireTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/JournalStoreExpireTestCase.java?view=auto&rev=494426
==============================================================================
--- incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/JournalStoreExpireTestCase.java (added)
+++ incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/JournalStoreExpireTestCase.java Tue Jan  9 07:02:43 2007
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.persistence.store.journal;
+
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.tuscany.spi.component.SCAObject;
+import org.apache.tuscany.spi.event.RuntimeEventListener;
+import org.apache.tuscany.spi.services.store.StoreExpirationEvent;
+import org.apache.tuscany.spi.services.store.StoreMonitor;
+
+import junit.framework.TestCase;
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.objectweb.howl.log.LogEventListener;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class JournalStoreExpireTestCase extends TestCase {
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private JournalStore store;
+    private SCAObject owner;
+
+    public void testNotifyOnExpire() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        StoreMonitor monitor = EasyMock.createMock(StoreMonitor.class);
+        Journal journal = EasyMock.createNiceMock(Journal.class);
+        journal.setLogEventListener(EasyMock.isA(LogEventListener.class));
+        EasyMock.replay(journal);
+
+        RuntimeEventListener listener = org.easymock.EasyMock.createMock(RuntimeEventListener.class);
+        listener.onEvent(org.easymock.EasyMock.isA(StoreExpirationEvent.class));
+        EasyMock.expectLastCall().andStubAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                latch.countDown();
+                return null;
+            }
+        });
+        org.easymock.EasyMock.replay(listener);
+
+        store = new JournalStore(monitor, journal) {
+        };
+        store.addListener(listener);
+        store.init();
+        final String id = UUID.randomUUID().toString();
+        store.insertRecord(owner, id, "test", 1);
+        if (!latch.await(10000, TimeUnit.MILLISECONDS)) {
+            // failed to notify listener
+            fail();
+        }
+        store.destroy();
+        EasyMock.verify(listener);
+    }
+
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        TestUtils.cleanupLog();
+        owner = EasyMock.createMock(SCAObject.class);
+        EasyMock.expect(owner.getCanonicalName()).andReturn("foo").atLeastOnce();
+        EasyMock.replay(owner);
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        TestUtils.cleanupLog();
+    }
+}

Propchange: incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/JournalStoreExpireTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/JournalStoreExpireTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/RecordKeyTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/RecordKeyTestCase.java?view=diff&rev=494426&r1=494425&r2=494426
==============================================================================
--- incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/RecordKeyTestCase.java (original)
+++ incubator/tuscany/java/sca/services/persistence/store.journal/src/test/java/org/apache/tuscany/persistence/store/journal/RecordKeyTestCase.java Tue Jan  9 07:02:43 2007
@@ -18,7 +18,10 @@
  */
 package org.apache.tuscany.persistence.store.journal;
 
+import org.apache.tuscany.spi.component.SCAObject;
+
 import junit.framework.TestCase;
+import org.easymock.EasyMock;
 
 /**
  * @version $Rev$ $Date$
@@ -27,22 +30,41 @@
 
     public void testEquals() throws Exception {
         String id = "bar";
-        RecordKey key1 = new RecordKey(id, "foo");
-        RecordKey key2 = new RecordKey(id, "foo");
+        SCAObject owner1 = EasyMock.createMock(SCAObject.class);
+        EasyMock.expect(owner1.getCanonicalName()).andReturn("foo");
+        EasyMock.replay(owner1);
+        SCAObject owner2 = EasyMock.createMock(SCAObject.class);
+        EasyMock.expect(owner2.getCanonicalName()).andReturn("foo");
+        EasyMock.replay(owner2);
+
+        RecordKey key1 = new RecordKey(id, owner1);
+        RecordKey key2 = new RecordKey(id, owner2);
         assertEquals(key1, key2);
     }
 
     public void testNotEqualsId() throws Exception {
         String id = "bar";
-        RecordKey key1 = new RecordKey(id, "foo");
-        RecordKey key2 = new RecordKey("baz", "foo");
+        SCAObject owner1 = EasyMock.createMock(SCAObject.class);
+        EasyMock.expect(owner1.getCanonicalName()).andReturn("foo");
+        EasyMock.replay(owner1);
+        SCAObject owner2 = EasyMock.createMock(SCAObject.class);
+        EasyMock.expect(owner2.getCanonicalName()).andReturn("foo");
+        EasyMock.replay(owner2);
+        RecordKey key1 = new RecordKey(id, owner1);
+        RecordKey key2 = new RecordKey("baz", owner2);
         assertFalse(key1.equals(key2));
     }
 
     public void testNotEqualsOwner() throws Exception {
         String id = "bar";
-        RecordKey key1 = new RecordKey(id, "foo");
-        RecordKey key2 = new RecordKey(id, "bar");
+        SCAObject owner1 = EasyMock.createMock(SCAObject.class);
+        EasyMock.expect(owner1.getCanonicalName()).andReturn("foo");
+        EasyMock.replay(owner1);
+        SCAObject owner2 = EasyMock.createMock(SCAObject.class);
+        EasyMock.expect(owner2.getCanonicalName()).andReturn("bar");
+        EasyMock.replay(owner2);
+        RecordKey key1 = new RecordKey(id, owner1);
+        RecordKey key2 = new RecordKey(id, owner2);
         assertFalse(key1.equals(key2));
     }
 



---------------------------------------------------------------------
To unsubscribe, e-mail: tuscany-commits-unsubscribe@ws.apache.org
For additional commands, e-mail: tuscany-commits-help@ws.apache.org