Author: btellier Date: Sat Nov 28 12:54:59 2015 New Revision: 1716954 URL: http://svn.apache.org/viewvc?rev=1716954&view=rev Log: MAILBOX-211 Should be based on more generic components
Added: james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListener.java james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DelegatingMailboxListener.java james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxListenerRegistry.java james/project/trunk/mailbox/store/src/test/java/org/apache/james/mailbox/store/event/ james/project/trunk/mailbox/store/src/test/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListenerTest.java Removed: james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/AbstractDelegatingMailboxListener.java james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/HashMapDelegatingMailboxListener.java Modified: james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java Modified: james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java URL: http://svn.apache.org/viewvc/james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java?rev=1716954&r1=1716953&r2=1716954&view=diff ============================================================================== --- james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java (original) +++ james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java Sat Nov 28 12:54:59 2015 @@ -55,8 +55,8 @@ import org.apache.james.mailbox.model.Me import org.apache.james.mailbox.model.SimpleMailboxACL; import org.apache.james.mailbox.quota.QuotaManager; import org.apache.james.mailbox.quota.QuotaRootResolver; -import org.apache.james.mailbox.store.event.AbstractDelegatingMailboxListener; -import org.apache.james.mailbox.store.event.HashMapDelegatingMailboxListener; +import org.apache.james.mailbox.store.event.DelegatingMailboxListener; +import org.apache.james.mailbox.store.event.DefaultDelegatingMailboxListener; import org.apache.james.mailbox.store.event.MailboxEventDispatcher; import org.apache.james.mailbox.store.mail.MailboxMapper; import org.apache.james.mailbox.store.mail.model.MailboxId; @@ -88,7 +88,7 @@ public class StoreMailboxManager<Id exte public static final int DEFAULT_FETCH_BATCH_SIZE = 200; private MailboxEventDispatcher<Id> dispatcher; - private AbstractDelegatingMailboxListener delegatingListener = null; + private DelegatingMailboxListener delegatingListener = null; private final MailboxSessionMapperFactory<Id> mailboxSessionMapperFactory; private final Authenticator authenticator; @@ -193,13 +193,13 @@ public class StoreMailboxManager<Id exte } /** - * Return the {@link AbstractDelegatingMailboxListener} which is used by this {@link MailboxManager} + * Return the {@link DelegatingMailboxListener} which is used by this {@link MailboxManager} * * @return delegatingListener */ - public AbstractDelegatingMailboxListener getDelegationListener() { + public DelegatingMailboxListener getDelegationListener() { if (delegatingListener == null) { - delegatingListener = new HashMapDelegatingMailboxListener(); + delegatingListener = new DefaultDelegatingMailboxListener(); } return delegatingListener; } @@ -253,12 +253,12 @@ public class StoreMailboxManager<Id exte } /** - * Set the {@link AbstractDelegatingMailboxListener} to use with this {@link MailboxManager} instance. If none is set here a {@link HashMapDelegatingMailboxListener} instance will + * Set the {@link DelegatingMailboxListener} to use with this {@link MailboxManager} instance. If none is set here a {@link DefaultDelegatingMailboxListener} instance will * be created lazy * * @param delegatingListener */ - public void setDelegatingMailboxListener(AbstractDelegatingMailboxListener delegatingListener) { + public void setDelegatingMailboxListener(DelegatingMailboxListener delegatingListener) { this.delegatingListener = delegatingListener; dispatcher = new MailboxEventDispatcher<Id>(getDelegationListener()); } Added: james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListener.java URL: http://svn.apache.org/viewvc/james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListener.java?rev=1716954&view=auto ============================================================================== --- james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListener.java (added) +++ james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListener.java Sat Nov 28 12:54:59 2015 @@ -0,0 +1,103 @@ +/**************************************************************** + * 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.james.mailbox.store.event; + +import java.util.Collection; + +import org.apache.james.mailbox.MailboxListener; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.MailboxPath; + +/** + * Receive a {@link org.apache.james.mailbox.MailboxListener.Event} and delegate it to an other + * {@link MailboxListener} depending on the registered name + * + * This is a mono instance Thread safe implementation for DelegatingMailboxListener + */ +public class DefaultDelegatingMailboxListener implements DelegatingMailboxListener { + + private MailboxListenerRegistry registry; + + @Override + public ListenerType getType() { + return ListenerType.EACH_NODE; + } + + public DefaultDelegatingMailboxListener() { + this.registry = new MailboxListenerRegistry(); + } + + @Override + public void addListener(MailboxPath path, MailboxListener listener, MailboxSession session) throws MailboxException { + if (listener.getType() != ListenerType.MAILBOX) { + throw new MailboxException(listener.getClass().getCanonicalName() + " registred on specific MAILBOX operation while its listener type was " + listener.getType()); + } + registry.addListener(path, listener); + } + + @Override + public void addGlobalListener(MailboxListener listener, MailboxSession session) throws MailboxException { + if (listener.getType() != ListenerType.EACH_NODE && listener.getType() != ListenerType.ONCE) { + throw new MailboxException(listener.getClass().getCanonicalName() + " registered on global event dispatching while its listener type was " + listener.getType()); + } + registry.addGlobalListener(listener); + } + + @Override + public void removeListener(MailboxPath mailboxPath, MailboxListener listener, MailboxSession session) throws MailboxException { + registry.removeListener(mailboxPath, listener); + } + + @Override + public void removeGlobalListener(MailboxListener listener, MailboxSession session) throws MailboxException { + registry.removeGlobalListener(listener); + } + + @Override + public void event(Event event) { + Collection<MailboxListener> listenerSnapshot = registry.getLocalMailboxListeners(event.getMailboxPath()); + if (event instanceof MailboxDeletion) { + registry.deleteRegistryFor(event.getMailboxPath()); + } else if (event instanceof MailboxRenamed) { + MailboxRenamed renamed = (MailboxRenamed) event; + registry.handleRename(renamed.getMailboxPath(), renamed.getNewPath()); + } + deliverEventToMailboxListeners(event, listenerSnapshot); + deliverEventToGlobalListeners(event); + } + + protected void deliverEventToMailboxListeners(Event event, Collection<MailboxListener> listenerSnapshot) { + for (MailboxListener listener : listenerSnapshot) { + deliverEvent(event, listener); + } + } + + protected void deliverEventToGlobalListeners(Event event) { + for (MailboxListener mailboxListener : registry.getGlobalListeners()) { + deliverEvent(event, mailboxListener); + } + } + + private void deliverEvent(Event event, MailboxListener listener) { + listener.event(event); + } + +} Added: james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DelegatingMailboxListener.java URL: http://svn.apache.org/viewvc/james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DelegatingMailboxListener.java?rev=1716954&view=auto ============================================================================== --- james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DelegatingMailboxListener.java (added) +++ james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DelegatingMailboxListener.java Sat Nov 28 12:54:59 2015 @@ -0,0 +1,27 @@ +/**************************************************************** + * 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.james.mailbox.store.event; + +import org.apache.james.mailbox.MailboxListener; +import org.apache.james.mailbox.MailboxListenerSupport; + +public interface DelegatingMailboxListener extends MailboxListenerSupport, MailboxListener{ + +} Added: james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxListenerRegistry.java URL: http://svn.apache.org/viewvc/james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxListenerRegistry.java?rev=1716954&view=auto ============================================================================== --- james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxListenerRegistry.java (added) +++ james/project/trunk/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxListenerRegistry.java Sat Nov 28 12:54:59 2015 @@ -0,0 +1,77 @@ +/**************************************************************** + * 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.james.mailbox.store.event; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import org.apache.james.mailbox.MailboxListener; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.MailboxPath; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class MailboxListenerRegistry { + + private Multimap<MailboxPath, MailboxListener> listeners; + private ConcurrentLinkedQueue<MailboxListener> globalListeners; + + public MailboxListenerRegistry() { + this.globalListeners = new ConcurrentLinkedQueue<MailboxListener>(); + this.listeners = Multimaps.synchronizedMultimap(HashMultimap.<MailboxPath, MailboxListener>create()); + } + + public void addListener(MailboxPath path, MailboxListener listener) throws MailboxException { + listeners.put(path, listener); + } + + public void addGlobalListener(MailboxListener listener) throws MailboxException { + globalListeners.add(listener); + } + + public void removeListener(MailboxPath mailboxPath, MailboxListener listener) throws MailboxException { + listeners.remove(mailboxPath, listener); + } + + public void removeGlobalListener(MailboxListener listener) throws MailboxException { + globalListeners.remove(listener); + } + + public List<MailboxListener> getLocalMailboxListeners(MailboxPath path) { + return ImmutableList.copyOf(listeners.get(path)); + } + + public List<MailboxListener> getGlobalListeners() { + return ImmutableList.copyOf(globalListeners); + } + + public void deleteRegistryFor(MailboxPath path) { + listeners.removeAll(path); + } + + public void handleRename(MailboxPath oldName, MailboxPath newName) { + listeners.putAll(newName, listeners.removeAll(oldName)); + } + +} Added: james/project/trunk/mailbox/store/src/test/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListenerTest.java URL: http://svn.apache.org/viewvc/james/project/trunk/mailbox/store/src/test/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListenerTest.java?rev=1716954&view=auto ============================================================================== --- james/project/trunk/mailbox/store/src/test/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListenerTest.java (added) +++ james/project/trunk/mailbox/store/src/test/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListenerTest.java Sat Nov 28 12:54:59 2015 @@ -0,0 +1,182 @@ +/**************************************************************** + * 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.james.mailbox.store.event; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.james.mailbox.MailboxListener; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.util.EventCollector; +import org.junit.Before; +import org.junit.Test; + +public class DefaultDelegatingMailboxListenerTest { + + private static final MailboxPath MAILBOX_PATH = new MailboxPath("namespace", "user", "name"); + private static final MailboxPath OTHER_MAILBOX_PATH = new MailboxPath("namespace", "other", "name"); + + private DefaultDelegatingMailboxListener defaultDelegatingMailboxListener; + private EventCollector mailboxEventCollector; + private EventCollector eachNodeEventCollector; + private EventCollector onceEventCollector; + + @Before + public void setUp() throws Exception { + mailboxEventCollector = new EventCollector(MailboxListener.ListenerType.MAILBOX); + eachNodeEventCollector = new EventCollector(MailboxListener.ListenerType.EACH_NODE); + onceEventCollector = new EventCollector(MailboxListener.ListenerType.ONCE); + defaultDelegatingMailboxListener = new DefaultDelegatingMailboxListener(); + defaultDelegatingMailboxListener.addListener(MAILBOX_PATH, mailboxEventCollector, null); + defaultDelegatingMailboxListener.addGlobalListener(onceEventCollector, null); + defaultDelegatingMailboxListener.addGlobalListener(eachNodeEventCollector, null); + } + + @Test(expected = MailboxException.class) + public void addListenerShouldThrowOnEACH_NODEListenerType() throws Exception { + MailboxListener mailboxListener = new EventCollector(MailboxListener.ListenerType.EACH_NODE); + defaultDelegatingMailboxListener.addListener(MAILBOX_PATH, mailboxListener, null); + } + + @Test(expected = MailboxException.class) + public void addListenerShouldThrowOnONCEListenerType() throws Exception { + MailboxListener mailboxListener = new EventCollector(MailboxListener.ListenerType.ONCE); + defaultDelegatingMailboxListener.addListener(MAILBOX_PATH, mailboxListener, null); + } + + @Test(expected = MailboxException.class) + public void addGlobalListenerShouldThrowOnMAILBOXListenerType() throws Exception { + MailboxListener mailboxListener = new EventCollector(MailboxListener.ListenerType.MAILBOX); + defaultDelegatingMailboxListener.addGlobalListener(mailboxListener, null); + } + + @Test + public void eventShouldWork() throws Exception { + MailboxListener.Event event = new MailboxListener.Event(null, MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(event); + assertThat(mailboxEventCollector.getEvents()).containsExactly(event); + assertThat(eachNodeEventCollector.getEvents()).containsExactly(event); + assertThat(onceEventCollector.getEvents()).containsExactly(event); + } + + @Test + public void eventShouldOnlyTriggerMAILBOXListenerRelatedToTheEvent() throws Exception { + MailboxListener.Event event = new MailboxListener.Event(null, OTHER_MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(event); + assertThat(mailboxEventCollector.getEvents()).isEmpty(); + assertThat(eachNodeEventCollector.getEvents()).containsExactly(event); + assertThat(onceEventCollector.getEvents()).containsExactly(event); + } + + @Test + public void mailboxRenamedEventShouldUnregisterMAILBOXFromTheirPreviousPath() throws Exception { + MailboxListener.MailboxRenamed event = new MailboxListener.MailboxRenamed(null, MAILBOX_PATH) { + @Override + public MailboxPath getNewPath() { + return OTHER_MAILBOX_PATH; + } + }; + defaultDelegatingMailboxListener.event(event); + MailboxListener.Event secondEvent = new MailboxListener.Event(null, MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(secondEvent); + assertThat(mailboxEventCollector.getEvents()).containsExactly(event); + assertThat(eachNodeEventCollector.getEvents()).containsOnly(event, secondEvent); + assertThat(onceEventCollector.getEvents()).containsExactly(event, secondEvent); + } + + @Test + public void mailboxRenamedEventShouldRegisterMAILBOXToTheirNewPath() throws Exception { + MailboxListener.MailboxRenamed event = new MailboxListener.MailboxRenamed(null, MAILBOX_PATH) { + @Override + public MailboxPath getNewPath() { + return OTHER_MAILBOX_PATH; + } + }; + defaultDelegatingMailboxListener.event(event); + MailboxListener.Event secondEvent = new MailboxListener.Event(null, OTHER_MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(secondEvent); + assertThat(mailboxEventCollector.getEvents()).containsOnly(event, secondEvent); + assertThat(eachNodeEventCollector.getEvents()).containsOnly(event, secondEvent); + assertThat(onceEventCollector.getEvents()).containsExactly(event, secondEvent); + } + + @Test + public void mailboxDeletionShouldUnregisterMAILBOXListeners() throws Exception { + MailboxListener.MailboxDeletion event = new MailboxListener.MailboxDeletion(null, MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(event); + MailboxListener.Event secondEvent = new MailboxListener.Event(null, MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(secondEvent); + assertThat(mailboxEventCollector.getEvents()).containsExactly(event); + assertThat(eachNodeEventCollector.getEvents()).containsOnly(event, secondEvent); + assertThat(onceEventCollector.getEvents()).containsExactly(event, secondEvent); + } + + @Test + public void mailboxDeletionShouldNotRegisterMAILBOXListenerToOtherPaths() throws Exception { + MailboxListener.MailboxDeletion event = new MailboxListener.MailboxDeletion(null, MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(event); + MailboxListener.Event secondEvent = new MailboxListener.Event(null, OTHER_MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(secondEvent); + assertThat(mailboxEventCollector.getEvents()).containsExactly(event); + assertThat(eachNodeEventCollector.getEvents()).containsOnly(event, secondEvent); + assertThat(onceEventCollector.getEvents()).containsExactly(event, secondEvent); + } + + @Test + public void removeListenerShouldWork() throws Exception { + defaultDelegatingMailboxListener.removeListener(MAILBOX_PATH, mailboxEventCollector, null); + MailboxListener.Event event = new MailboxListener.Event(null, MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(event); + assertThat(mailboxEventCollector.getEvents()).isEmpty(); + assertThat(eachNodeEventCollector.getEvents()).containsExactly(event); + assertThat(onceEventCollector.getEvents()).containsExactly(event); + } + + @Test + public void removeListenerShouldNotRemoveAListenerFromADifferentPath() throws Exception { + defaultDelegatingMailboxListener.removeListener(OTHER_MAILBOX_PATH, mailboxEventCollector, null); + MailboxListener.Event event = new MailboxListener.Event(null, MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(event); + assertThat(mailboxEventCollector.getEvents()).containsExactly(event); + assertThat(eachNodeEventCollector.getEvents()).containsExactly(event); + assertThat(onceEventCollector.getEvents()).containsExactly(event); + } + + @Test + public void removeGlobalListenerShouldWorkForONCE() throws Exception { + defaultDelegatingMailboxListener.removeGlobalListener(eachNodeEventCollector, null); + MailboxListener.Event event = new MailboxListener.Event(null, MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(event); + assertThat(mailboxEventCollector.getEvents()).containsExactly(event); + assertThat(eachNodeEventCollector.getEvents()).isEmpty(); + assertThat(onceEventCollector.getEvents()).containsExactly(event); + } + + @Test + public void removeGlobalListenerShouldWorkForEACH_NODE() throws Exception { + defaultDelegatingMailboxListener.removeGlobalListener(onceEventCollector, null); + MailboxListener.Event event = new MailboxListener.Event(null, MAILBOX_PATH) {}; + defaultDelegatingMailboxListener.event(event); + assertThat(mailboxEventCollector.getEvents()).containsExactly(event); + assertThat(eachNodeEventCollector.getEvents()).containsExactly(event); + assertThat(onceEventCollector.getEvents()).isEmpty(); + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org