Author: rmannibucau
Date: Wed Aug 15 22:29:07 2012
New Revision: 1373659
URL: http://svn.apache.org/viewvc?rev=1373659&view=rev
Log:
TOMEE-376 features config for cxf endpoints
Added:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/ListConfigurator.java
openejb/trunk/openejb/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/FeatureTest.java
openejb/trunk/openejb/server/openejb-cxf/src/test/java/org/apache/openejb/server/cxf/FeatureTest.java
Modified:
openejb/trunk/openejb/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/CxfEndpoint.java
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/CxfService.java
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/ejb/EjbEndpoint.java
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/pojo/PojoEndpoint.java
Added:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/ListConfigurator.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/ListConfigurator.java?rev=1373659&view=auto
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/ListConfigurator.java
(added)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/ListConfigurator.java
Wed Aug 15 22:29:07 2012
@@ -0,0 +1,72 @@
+/*
+ * 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.openejb.util;
+
+import org.apache.openejb.OpenEJBRuntimeException;
+import org.apache.xbean.recipe.ObjectRecipe;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public final class ListConfigurator {
+ private ListConfigurator() {
+ // no-op
+ }
+
+ public static <T> List<T> getList(final Properties properties, final
String key, final ClassLoader classloader, final Class<T> filter) {
+ if (properties == null) {
+ return null;
+ }
+
+ final String features = properties.getProperty(key);
+ if (features == null) {
+ return null;
+ }
+
+ final List<T> list = new ArrayList<T>();
+ final String[] split = features.trim().split(",");
+ for (String feature : split) {
+ if (feature == null || feature.trim().isEmpty()) {
+ continue;
+ }
+
+ final String prefix = key + "." + feature + ".";
+ final ObjectRecipe recipe = new ObjectRecipe(feature);
+ for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+ final String current = entry.getKey().toString();
+ if (current.startsWith(prefix)) {
+ final String property = current.substring(prefix.length());
+ recipe.setProperty(property, entry.getValue());
+ }
+ }
+
+ final Object instance = recipe.create(classloader);
+ if (!filter.isInstance(instance)) {
+ throw new OpenEJBRuntimeException(feature + " is not an
abstract feature");
+ }
+ list.add(filter.cast(instance));
+ }
+
+ if (list.isEmpty()) {
+ return null;
+ }
+ return list;
+ }
+}
+
Modified:
openejb/trunk/openejb/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java?rev=1373659&r1=1373658&r2=1373659&view=diff
==============================================================================
---
openejb/trunk/openejb/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
(original)
+++
openejb/trunk/openejb/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
Wed Aug 15 22:29:07 2012
@@ -16,18 +16,8 @@
*/
package org.apache.openejb.server.cxf.rs;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.naming.Context;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.ws.rs.core.Application;
-import javax.xml.bind.Marshaller;
import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.feature.AbstractFeature;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.lifecycle.ResourceProvider;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
@@ -37,7 +27,6 @@ import org.apache.cxf.service.invoker.In
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.apache.cxf.transport.http.HTTPTransportFactory;
import org.apache.openejb.BeanContext;
-import org.apache.openejb.BeanType;
import org.apache.openejb.Injection;
import org.apache.openejb.loader.Options;
import org.apache.openejb.loader.SystemInstance;
@@ -45,12 +34,25 @@ import org.apache.openejb.server.httpd.H
import org.apache.openejb.server.httpd.HttpRequestImpl;
import org.apache.openejb.server.httpd.HttpResponse;
import org.apache.openejb.server.rest.RsHttpListener;
+import org.apache.openejb.util.ListConfigurator;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.ObjectRecipeHelper;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.xbean.recipe.ObjectRecipe;
+import javax.naming.Context;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.ws.rs.core.Application;
+import javax.xml.bind.Marshaller;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* System property:
* <ul>
@@ -70,6 +72,9 @@ public class CxfRsHttpListener implement
public static final String DEFAULT_CXF_JAXRS_PROVIDERS_KEY = "default";
public static final String OPENEJB_CXF_PROPERTIES =
"openejb.cxf.rs.jaxb.properties";
+ public static final String OPENEJB_JAXRS_READ_PROPERTIES =
"openejb.jaxrs.read-properties";
+ public static final String OPENEJB_JAXRS_CXF_FEATURES =
"openejb.jaxrs.cxf.features";
+
private static final List<Object> PROVIDERS =
createConfiguredProviderList("", CxfRsHttpListener.class.getClassLoader());
private static final Map<String, Object> cxfProperties =
toMap(SystemInstance.get().getProperty(OPENEJB_CXF_PROPERTIES));
@@ -77,6 +82,16 @@ public class CxfRsHttpListener implement
private AbstractHTTPDestination destination;
private Server server;
+ private static List<AbstractFeature> GLOBAL_FEATURES = new
ArrayList<AbstractFeature>();
+ static {
+ final List<AbstractFeature> features = ListConfigurator.getList(
+ SystemInstance.get().getProperties(),
OPENEJB_JAXRS_CXF_FEATURES,
+ CxfRsHttpListener.class.getClassLoader(),
AbstractFeature.class);
+ if (features != null) {
+ GLOBAL_FEATURES.addAll(features);
+ }
+ }
+
public CxfRsHttpListener(HTTPTransportFactory httpTransportFactory) {
transportFactory = httpTransportFactory;
}
@@ -144,6 +159,19 @@ public class CxfRsHttpListener implement
factory.getProperties().putAll(cxfProperties);
}
+ if
(SystemInstance.get().getOptions().get(OPENEJB_JAXRS_READ_PROPERTIES, false)) {
+ List<AbstractFeature> features = ListConfigurator.getList(
+ SystemInstance.get().getProperties(), clazz.getName() +
"." + OPENEJB_JAXRS_CXF_FEATURES,
+ clazz.getClassLoader(), AbstractFeature.class);
+ if (features == null) {
+ features = new ArrayList<AbstractFeature>();
+ }
+ features.addAll(GLOBAL_FEATURES);
+ if (!features.isEmpty()) {
+ factory.setFeatures(features);
+ }
+ }
+
if (rp != null) {
factory.setResourceProvider(rp);
}
Added:
openejb/trunk/openejb/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/FeatureTest.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/FeatureTest.java?rev=1373659&view=auto
==============================================================================
---
openejb/trunk/openejb/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/FeatureTest.java
(added)
+++
openejb/trunk/openejb/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/FeatureTest.java
Wed Aug 15 22:29:07 2012
@@ -0,0 +1,50 @@
+package org.apache.openejb.server.cxf.rs;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.feature.AbstractFeature;
+import org.apache.openejb.OpenEjbContainer;
+import org.apache.openejb.jee.StatelessBean;
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.junit.Configuration;
+import org.apache.openejb.junit.Module;
+import org.apache.openejb.server.cxf.rs.beans.MySecondRestClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(ApplicationComposer.class)
+public class FeatureTest {
+ @Configuration
+ public Properties config() {
+ return new Properties() {{
+ setProperty(OpenEjbContainer.OPENEJB_EMBEDDED_REMOTABLE, "true");
+ setProperty(CxfRsHttpListener.OPENEJB_JAXRS_READ_PROPERTIES,
"true");
+ setProperty(MySecondRestClass.class.getName() + "." +
CxfRsHttpListener.OPENEJB_JAXRS_CXF_FEATURES, MyFeature.class.getName());
+ }};
+ }
+
+ @Module
+ public StatelessBean app() {
+ final StatelessBean bean = (StatelessBean) new
StatelessBean(MySecondRestClass.class).localBean();
+ bean.setRestService(true);
+ return bean;
+ }
+
+ @Test
+ public void run() {
+ assertTrue(MyFeature.ok);
+ }
+
+ public static class MyFeature extends AbstractFeature {
+ public static boolean ok = false;
+
+ @Override
+ public void initialize(Server server, Bus bus) {
+ ok = true;
+ }
+ }
+}
Modified:
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/CxfEndpoint.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/CxfEndpoint.java?rev=1373659&r1=1373658&r2=1373659&view=diff
==============================================================================
---
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/CxfEndpoint.java
(original)
+++
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/CxfEndpoint.java
Wed Aug 15 22:29:07 2012
@@ -20,16 +20,17 @@ package org.apache.openejb.server.cxf;
import org.apache.cxf.Bus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.endpoint.ServerImpl;
+import org.apache.cxf.feature.AbstractFeature;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.jaxws.handler.PortInfoImpl;
import org.apache.cxf.jaxws.support.JaxWsEndpointImpl;
import org.apache.cxf.jaxws.support.JaxWsImplementorInfo;
import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
import org.apache.cxf.service.Service;
-import org.apache.cxf.service.model.BindingInfo;
import org.apache.cxf.transport.http.HTTPTransportFactory;
import org.apache.openejb.core.webservices.HandlerResolverImpl;
import org.apache.openejb.core.webservices.PortData;
+import org.apache.openejb.util.ListConfigurator;
import javax.naming.Context;
import javax.xml.transform.Source;
@@ -39,6 +40,7 @@ import javax.xml.ws.http.HTTPBinding;
import javax.xml.ws.soap.SOAPBinding;
import java.util.List;
import java.util.Map;
+import java.util.Properties;
import java.util.concurrent.Executor;
public abstract class CxfEndpoint {
@@ -149,12 +151,8 @@ public abstract class CxfEndpoint {
svrFactory.setStart(false);
svrFactory.setServiceBean(implementor);
svrFactory.setDestinationFactory(httpTransportFactory);
-
- final Map<String, Object> properties = getEndpointProperties();
- if (properties != null) {
- svrFactory.setProperties(properties);
- }
-
+ svrFactory.setProperties(getEndpointProperties());
+
svrFactory.setFeatures(ListConfigurator.getList(getFeaturesProperties(),
getFeaturePropertyKey(), getImplementorClass().getClassLoader(),
AbstractFeature.class));
if (HTTPBinding.HTTP_BINDING.equals(implInfo.getBindingType()))
{
svrFactory.setTransportId("http://cxf.apache.org/bindings/xformat");
@@ -174,6 +172,10 @@ public abstract class CxfEndpoint {
server.start();
}
+ protected abstract Properties getFeaturesProperties();
+
+ protected abstract String getFeaturePropertyKey();
+
protected Map<String,Object> getEndpointProperties() {
return null;
}
Modified:
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/CxfService.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/CxfService.java?rev=1373659&r1=1373658&r2=1373659&view=diff
==============================================================================
---
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/CxfService.java
(original)
+++
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/CxfService.java
Wed Aug 15 22:29:07 2012
@@ -18,6 +18,8 @@
package org.apache.openejb.server.cxf;
import org.apache.cxf.Bus;
+import org.apache.cxf.bus.extension.ExtensionManagerBus;
+import org.apache.cxf.feature.AbstractFeature;
import org.apache.openejb.BeanContext;
import org.apache.openejb.core.webservices.PortData;
import org.apache.openejb.server.cxf.client.SaajInterceptor;
@@ -26,13 +28,18 @@ import org.apache.openejb.server.cxf.poj
import org.apache.openejb.server.cxf.transport.util.CxfUtil;
import org.apache.openejb.server.httpd.HttpListener;
import org.apache.openejb.server.webservices.WsService;
+import org.apache.openejb.util.ListConfigurator;
import javax.naming.Context;
import java.net.URL;
+import java.util.List;
import java.util.Map;
+import java.util.Properties;
import java.util.TreeMap;
public class CxfService extends WsService {
+ public static final String OPENEJB_JAXWS_CXF_FEATURES =
"openejb.jaxws.cxf.features";
+
private final Map<String, CxfWsContainer> wsContainers = new
TreeMap<String, CxfWsContainer>();
public CxfService() {
@@ -43,6 +50,21 @@ public class CxfService extends WsServic
return "cxf";
}
+ public void init(final Properties props) throws java.lang.Exception {
+ super.init(props);
+
+ // set bus features
+ final Bus bus = CxfUtil.getBus();
+ if (bus instanceof ExtensionManagerBus) { // always true normally
+ final List<AbstractFeature> features = ListConfigurator.getList(
+ new Properties(props), OPENEJB_JAXWS_CXF_FEATURES,
+ CxfUtil.class.getClassLoader(), AbstractFeature.class);
+ if (features != null) {
+ ((ExtensionManagerBus) bus).setFeatures(features);
+ }
+ }
+ }
+
protected HttpListener createEjbWsContainer(URL moduleBaseUrl, PortData
port, BeanContext beanContext) {
Bus bus = CxfUtil.getBus();
Modified:
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/ejb/EjbEndpoint.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/ejb/EjbEndpoint.java?rev=1373659&r1=1373658&r2=1373659&view=diff
==============================================================================
---
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/ejb/EjbEndpoint.java
(original)
+++
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/ejb/EjbEndpoint.java
Wed Aug 15 22:29:07 2012
@@ -32,6 +32,7 @@ import org.apache.openejb.core.webservic
import org.apache.openejb.core.webservices.PortData;
import org.apache.openejb.server.cxf.ConfigureCxfSecurity;
import org.apache.openejb.server.cxf.CxfEndpoint;
+import org.apache.openejb.server.cxf.CxfService;
import org.apache.openejb.server.cxf.CxfServiceConfiguration;
import org.apache.openejb.server.cxf.JaxWsImplementorInfoImpl;
@@ -39,6 +40,7 @@ import javax.xml.ws.WebServiceException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Properties;
/**
* A web service endpoint which invokes an EJB container.
@@ -76,6 +78,16 @@ public class EjbEndpoint extends CxfEndp
return map;
}
+ @Override
+ protected Properties getFeaturesProperties() {
+ return port.getProperties();
+ }
+
+ @Override
+ protected String getFeaturePropertyKey() {
+ return CxfService.OPENEJB_JAXWS_CXF_FEATURES;
+ }
+
protected void init() {
// configure handlers
try {
Modified:
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/pojo/PojoEndpoint.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/pojo/PojoEndpoint.java?rev=1373659&r1=1373658&r2=1373659&view=diff
==============================================================================
---
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/pojo/PojoEndpoint.java
(original)
+++
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/pojo/PojoEndpoint.java
Wed Aug 15 22:29:07 2012
@@ -31,6 +31,7 @@ import org.apache.openejb.core.webservic
import org.apache.openejb.core.webservices.PortData;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.server.cxf.CxfEndpoint;
+import org.apache.openejb.server.cxf.CxfService;
import org.apache.openejb.server.cxf.CxfServiceConfiguration;
import org.apache.openejb.server.cxf.JaxWsImplementorInfoImpl;
@@ -39,6 +40,7 @@ import javax.xml.ws.WebServiceException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Properties;
import static org.apache.openejb.InjectionProcessor.unwrap;
@@ -90,6 +92,14 @@ public class PojoEndpoint extends CxfEnd
}
@Override
+ protected Properties getFeaturesProperties() {
+ if
(SystemInstance.get().getOptions().get(OPENEJB_JAXWS_READ_POJO_PROPERTIES,
false)) {
+ return null;
+ }
+ return SystemInstance.get().getProperties();
+ }
+
+ @Override
protected Map<String, Object> getEndpointProperties() {
if
(SystemInstance.get().getOptions().get(OPENEJB_JAXWS_READ_POJO_PROPERTIES,
false)) {
final String prefix = OPENEJB_JAXWS_POJO_CONFIG_PREFIX +
getImplementorClass().getName() + ".";
@@ -126,4 +136,9 @@ public class PojoEndpoint extends CxfEnd
// shutdown server
super.stop();
}
+
+ @Override
+ protected String getFeaturePropertyKey() {
+ return getImplementorClass().getName() + "." +
CxfService.OPENEJB_JAXWS_CXF_FEATURES;
+ }
}
Added:
openejb/trunk/openejb/server/openejb-cxf/src/test/java/org/apache/openejb/server/cxf/FeatureTest.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-cxf/src/test/java/org/apache/openejb/server/cxf/FeatureTest.java?rev=1373659&view=auto
==============================================================================
---
openejb/trunk/openejb/server/openejb-cxf/src/test/java/org/apache/openejb/server/cxf/FeatureTest.java
(added)
+++
openejb/trunk/openejb/server/openejb-cxf/src/test/java/org/apache/openejb/server/cxf/FeatureTest.java
Wed Aug 15 22:29:07 2012
@@ -0,0 +1,61 @@
+package org.apache.openejb.server.cxf;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.feature.AbstractFeature;
+import org.apache.openejb.OpenEjbContainer;
+import org.apache.openejb.config.EjbModule;
+import org.apache.openejb.jee.EjbJar;
+import org.apache.openejb.jee.SingletonBean;
+import org.apache.openejb.jee.oejb3.EjbDeployment;
+import org.apache.openejb.jee.oejb3.OpenejbJar;
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.junit.Configuration;
+import org.apache.openejb.junit.Module;
+import org.apache.openejb.server.cxf.fault.AuthenticatorServiceBean;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(ApplicationComposer.class)
+public class FeatureTest {
+ @Configuration
+ public Properties config() {
+ return new Properties() {{
+ setProperty(OpenEjbContainer.OPENEJB_EMBEDDED_REMOTABLE, "true");
+ }};
+ }
+
+ @Module
+ public EjbModule app() {
+ final EjbJar jar = new EjbJar();
+ jar.addEnterpriseBean(new
SingletonBean(AuthenticatorServiceBean.class).localBean());
+
+ final OpenejbJar openejbJar = new OpenejbJar();
+ openejbJar.addEjbDeployment(new
EjbDeployment(jar.getEnterpriseBeans()[0]));
+ openejbJar.getEjbDeployment().iterator().next().getProperties()
+ .setProperty(CxfService.OPENEJB_JAXWS_CXF_FEATURES,
MyFeature.class.getName());
+
+ final EjbModule module = new EjbModule(jar);
+ module.setOpenejbJar(openejbJar);
+
+ return module;
+ }
+
+ @Test
+ public void run() {
+ assertTrue(MyFeature.ok);
+ }
+
+ public static class MyFeature extends AbstractFeature {
+ public static boolean ok = false;
+
+ @Override
+ public void initialize(Server server, Bus bus) {
+ ok = true;
+ }
+ }
+}