Commit 7fe15074 authored by Ate Douma's avatar Ate Douma

CMS7-7081: Separate and promote all hippo services modules into standalone projects

- move and rename services-eventbus under tmp1/trunk and rename it back to services-eventbus/trunk hereafter
parents
* text=auto !eol
/LICENSE -text
/NOTICE -text
src/main/java/com/google/common/eventbus/HippoAnnotationHandlerFinder.java -text
src/test/java/org/onehippo/cms7/services/eventbus/HippoAnnotationHandlerFinderTest.java -text svneol=unset#text/plain
/*.iml
/.classpath
/.project
/.settings
/target
This diff is collapsed.
Hippo CMS7 Services - eventbus
Copyright 2012-2013 Hippo B.V. (http://www.onehippo.com)
This product includes software developed by:
Hippo B.V., Amsterdam, The Netherlands (http://www.onehippo.com/);
The Apache Software Foundation (http://www.apache.org/).
NOTICE: Only our own original work is licensed under the terms of the
Apache License Version 2.0. The licenses of some libraries might impose
different redistribution or general licensing terms than those stated in the
Apache License. Users and redistributors are hereby requested to verify these
conditions and agree upon them.
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2013 Hippo B.V. (http://www.onehippo.com)
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onehippo.cms7</groupId>
<artifactId>hippo-cms7-project</artifactId>
<version>21</version>
</parent>
<name>Hippo CMS7 Services - eventbus</name>
<artifactId>hippo-services-eventbus</artifactId>
<inceptionYear>2012</inceptionYear>
<properties>
<!-- use root project name for all project modules NOTICE files, should be the same as in the root NOTICE file -->
<notice.project.name>Hippo CMS7 Services - eventbus</notice.project.name>
<hippo.services.version>1.03.00-SNAPSHOT</hippo.services.version>
<hippo.commons.version>1.02.01</hippo.commons.version>
</properties>
<scm>
<connection>scm:svn:http://svn.onehippo.org/repos/hippo/hippo-cms7/services/services-eventbus/trunk</connection>
<developerConnection>scm:svn:https://svn.onehippo.org/repos/hippo/hippo-cms7/services/services-eventbus/trunk</developerConnection>
<url>http://svn.onehippo.org/repos/hippo/hippo-cms7/services/services-eventbus/trunk</url>
</scm>
<repositories>
<repository>
<id>hippo</id>
<name>Hippo Maven 2</name>
<url>http://maven.onehippo.com/maven2/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.onehippo.cms7</groupId>
<artifactId>hippo-cms7-commons</artifactId>
<version>${hippo.commons.version}</version>
</dependency>
<dependency>
<groupId>org.onehippo.cms7</groupId>
<artifactId>hippo-services</artifactId>
<version>${hippo.services.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>pedantic</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.rat</groupId>
<artifactId>apache-rat-plugin</artifactId>
<inherited>false</inherited>
<configuration>
<excludes combine.children="append">
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
/*
* Copyright 2012-2013 Hippo B.V. (http://www.onehippo.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.eventbus;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.onehippo.cms7.services.HippoServiceRegistration;
import org.onehippo.cms7.services.eventbus.Subscribe;
/**
* Fork of the guava AnnotationHandlerFinder that is injected by reflection.
* The guava handler finding strategy api is not yet public, but uses package security.
*/
public class HippoAnnotationHandlerFinder implements HandlerFindingStrategy {
@Override
public Multimap<Class<?>, EventHandler> findAllHandlers(Object registered) {
Multimap<Class<?>, EventHandler> methodsInListener = HashMultimap.create();
Object listener;
ClassLoader classLoader;
if (registered instanceof HippoServiceRegistration) {
HippoServiceRegistration registration = (HippoServiceRegistration) registered;
listener = registration.getService();
classLoader = registration.getClassLoader();
} else {
listener = registered;
classLoader = Thread.currentThread().getContextClassLoader();
}
Class<?> clazz = listener.getClass();
// loop through all the classes' methods
for (Method method : clazz.getMethods()) {
Method annotatedMethod = doGetAnnotatedMethod(method, Subscribe.class);
if (annotatedMethod != null) {
// the method has a Subscribe annotation
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1) {
throw new IllegalArgumentException(
"Method " + method + " has @Subscribe annotation, but requires " +
parameterTypes.length + " arguments. Event handler methods " +
"must require a single argument.");
}
Class<?> eventType = parameterTypes[0];
if (acceptMethod(listener, method.getAnnotations(), eventType)) {
EventHandler handler = new HippoSynchronizedEventHandler(listener, method, classLoader);
methodsInListener.put(eventType, handler);
}
}
}
return methodsInListener;
}
protected boolean acceptMethod(Object listener, Annotation[] annotations, Class<?> parameterType) {
return true;
}
/**
* returns the annotated method with annotation clazz and null if the clazz annotation is not present
* @param m
* @param clazz the annotation to look for
* @return the {@link Method} that contains the annotation <code>clazz</code> and <code>null</code> if none found
*/
private static Method doGetAnnotatedMethod(final Method m, Class<Subscribe> clazz) {
if (m == null) {
return m;
}
Subscribe annotation = m.getAnnotation(clazz);
if(annotation != null ) {
// found Subscribe annotation
return m;
}
Class<?> superC = m.getDeclaringClass().getSuperclass();
if (superC != null && Object.class != superC) {
try {
Method method = doGetAnnotatedMethod(superC.getMethod(m.getName(), m.getParameterTypes()), clazz);
if (method != null) {
return method;
}
} catch (NoSuchMethodException ex) {
// ignore
}
}
for (Class<?> i : m.getDeclaringClass().getInterfaces()) {
try {
Method method = doGetAnnotatedMethod(i.getMethod(m.getName(), m.getParameterTypes()), clazz);
if (method != null) {
return method;
}
} catch (NoSuchMethodException ex) {
// ignore
}
}
return null;
}
}
/*
* Copyright 2012-2013 Hippo B.V. (http://www.onehippo.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.eventbus;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Event handler that sets up the contex classloader when dispatching events.
*/
public class HippoSynchronizedEventHandler extends SynchronizedEventHandler {
private final Annotation[] annotations;
private final ClassLoader classLoader;
public HippoSynchronizedEventHandler(final Object target, final Method method, ClassLoader contextClassLoader) {
super(target, method);
this.annotations = method.getAnnotations();
this.classLoader = contextClassLoader;
}
public Annotation[] getAnnotations() {
if (annotations == null) {
return new Annotation[0];
}
return annotations.clone();
}
@Override
public synchronized void handleEvent(final Object event) throws InvocationTargetException {
ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
super.handleEvent(event);
} finally {
Thread.currentThread().setContextClassLoader(currentContextClassLoader);
}
}
}
/*
* Copyright 2012-2013 Hippo B.V. (http://www.onehippo.com)
*
* 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.onehippo.cms7.services.eventbus;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.HippoAnnotationHandlerFinder;
import org.onehippo.cms7.event.HippoEvent;
import org.onehippo.cms7.services.HippoServiceException;
import org.onehippo.cms7.services.HippoServiceRegistration;
import org.onehippo.cms7.services.HippoServiceRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GuavaHippoEventBus implements HippoEventBus {
static final Logger log = LoggerFactory.getLogger(GuavaHippoEventBus.class);
final ExecutorService executor = Executors.newSingleThreadExecutor();
final AsyncEventBus eventBus = new AsyncEventBus(executor);
final List<HippoServiceRegistration> listeners = Collections.synchronizedList(new ArrayList<HippoServiceRegistration>());
private volatile int version = -1;
public GuavaHippoEventBus() {
try {
Field finderField = EventBus.class.getDeclaredField("finder");
finderField.setAccessible(true);
finderField.set(eventBus, new HippoAnnotationHandlerFinder() {
@Override
protected boolean acceptMethod(final Object listener, final Annotation[] annotations, final Class<?> parameterType) {
return GuavaHippoEventBus.this.acceptMethod(listener, annotations, parameterType);
}
});
} catch (NoSuchFieldException e) {
throw new HippoServiceException("Unable to initialize event bus", e);
} catch (IllegalAccessException e) {
throw new HippoServiceException("Unable to initialize event bus", e);
}
}
protected boolean acceptMethod(final Object listener, final Annotation[] annotations, final Class<?> parameterType) {
return true;
}
public void destroy() {
executor.shutdown();
}
@Override
public void register(final Object listener) {
eventBus.register(listener);
log.warn("HippoEventBus method #register is deprecated, use whiteboard pattern instead");
}
@Override
public void unregister(final Object listener) {
eventBus.unregister(listener);
}
public void post(final Object event) {
if (updateListenersNeeded()) {
updateListeners();
}
if (event instanceof HippoEvent) {
((HippoEvent) event).sealEvent();
}
eventBus.post(event);
}
private boolean updateListenersNeeded() {
if (version == HippoServiceRegistry.getVersion()) {
return false;
}
return true;
}
private void updateListeners() {
List<HippoServiceRegistration> registered = getServiceRegistrations();
for (HippoServiceRegistration registration : registered) {
if (!listeners.contains(registration)) {
listeners.add(registration);
eventBus.register(registration);
}
}
Iterator<HippoServiceRegistration> iterator = listeners.iterator();
while (iterator.hasNext()) {
HippoServiceRegistration registration = iterator.next();
if (!registered.contains(registration)) {
iterator.remove();
eventBus.unregister(registration);
}
}
version = HippoServiceRegistry.getVersion();
}
protected List<HippoServiceRegistration> getServiceRegistrations() {
return HippoServiceRegistry.getRegistrations(HippoEventBus.class);
}
}
/*
* Copyright 2012-2013 Hippo B.V. (http://www.onehippo.com)
*
* 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.onehippo.cms7.services.eventbus;
import org.junit.Test;
import org.onehippo.cms7.services.HippoServiceRegistry;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
public class GuavaHippoEventBusTest {
public class Listener {
boolean fired = false;
@Subscribe
public void eventFired(Object payload) {
fired = true;
synchronized (GuavaHippoEventBusTest.this) {
GuavaHippoEventBusTest.this.notify();
}
}
}
@Test
public void testEventBusWithDirectListener() throws InterruptedException {
HippoEventBus eventBus = new GuavaHippoEventBus();
Listener listener = new Listener();
eventBus.register(listener);
eventBus.post(new Object());
synchronized (this) {
wait(500);
}
assertTrue(listener.fired);
}
@Test
public void testEventBusWithWhiteboardListener() throws InterruptedException {
HippoEventBus eventBus = new GuavaHippoEventBus();
Listener listener = new Listener();
HippoServiceRegistry.registerService(listener, HippoEventBus.class);
eventBus.post(new Object());
synchronized (this) {
wait(500);
}
assertTrue(listener.fired);
listener.fired = false;
HippoServiceRegistry.unregisterService(listener, HippoEventBus.class);
eventBus.post(new Object());
synchronized (this) {
wait(500);
}
assertFalse(listener.fired);
}
}
/*
* Copyright 2012-2013 Hippo B.V. (http://www.onehippo.com)
*
* 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.onehippo.cms7.services.eventbus;
import static junit.framework.Assert.assertTrue;
import org.junit.Test;
import org.onehippo.cms7.event.HippoEvent;
import com.google.common.collect.Multimap;
import com.google.common.eventbus.HippoAnnotationHandlerFinder;
public class HippoAnnotationHandlerFinderTest {
@Test
public void testAnonymousAnnotationsFinder() {
HippoAnnotationHandlerFinder finder = new HippoAnnotationHandlerFinder();
Multimap map = finder.findAllHandlers(new Object() {
@Subscribe
public void thisIsAHandler(HippoEvent<?> event) {
// do nothing
}
});
assertTrue(map.size() == 1);
}
@Test
public void testDirectAnnotationsFinder() {
HippoAnnotationHandlerFinder finder = new HippoAnnotationHandlerFinder();
Multimap map = finder.findAllHandlers(new A());
assertTrue(map.size() == 2);
}
@Test
public void testInheritedAnnotationsFinder() {
HippoAnnotationHandlerFinder finder = new HippoAnnotationHandlerFinder();
Multimap map = finder.findAllHandlers(new B());
assertTrue(map.size() == 2);
}
@Test
public void testInheritedAnnotationsWithOverrdeWithoutAnnotationFinder() {
HippoAnnotationHandlerFinder finder = new HippoAnnotationHandlerFinder();
Multimap map = finder.findAllHandlers(new C());
// overrding a method and then not including the annotation should take the annotation
// from the overriden class
assertTrue(map.size() == 2);
}
@Test
public void testInterfaceAnnonymousAnnotationsFinder() {
HippoAnnotationHandlerFinder finder = new HippoAnnotationHandlerFinder();
Multimap map = finder.findAllHandlers(new I() {
@Override
public void thisIsAHandler(HippoEvent<?> event) {
// do nothing
}
});
assertTrue(map.size() == 1);
}
@Test
public void testInterfaceAnnonymousAnnotationWithExtraSubscribeMethodFinder() {
HippoAnnotationHandlerFinder finder = new HippoAnnotationHandlerFinder();
Multimap map = finder.findAllHandlers(new I() {
@Override
public void thisIsAHandler(HippoEvent<?> event) {
// do nothing
}
@Subscribe
public void testExtra(HippoEvent<?> event) {
//
}
});
// added an extra Subscribe method
assertTrue(map.size() == 2);
}
@Test
public void testInterfaceImplAnnotationsFinder() {
HippoAnnotationHandlerFinder finder = new HippoAnnotationHandlerFinder();
Multimap map = finder.findAllHandlers(new Impl() {
});
assertTrue(map.size() == 1);
}
@Test
public void testInterfaceSubImplWithExtraInterfaceAnnotationsFinder() {
HippoAnnotationHandlerFinder finder = new HippoAnnotationHandlerFinder();
Multimap map = finder.findAllHandlers(new SubImpl() {
});
// we have now 2 Subscribe annotations through two different interfaces
assertTrue(map.size() == 2);
}
public class SubImpl extends Impl implements I2 {
@Override
public void thisIsAHandler(HippoEvent<?> event) {
// nothing
}
@Override
public void thisIsASecondHandler(HippoEvent<?> event) {
// nothing
}
}
public class Impl implements I {
@Override
public void thisIsAHandler(HippoEvent<?> event) {
// nothing
}
}
public interface I {
@Subscribe
public void thisIsAHandler(HippoEvent<?> event);
}
public interface I2 {
@Subscribe
public void thisIsASecondHandler(HippoEvent<?> event);
}
public class A extends B {
}
public class C extends B {
@Override
public void thisIsAHandler(HippoEvent<?> event) {
}
}
public class B {
@Subscribe
public void thisIsAHandler(HippoEvent<?> event) {
// do nothing
}
@Subscribe
public void thisIsASecondHandler(HippoEvent<?> event) {
// do nothing
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment