Repository: tomee Updated Branches: refs/heads/master 066da5ed0 -> e386526f1
TOMEE-1846 adding Template API Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/a5d08be1 Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/a5d08be1 Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/a5d08be1 Branch: refs/heads/master Commit: a5d08be10d9ea4b20a9179494fbc9ced140e5439 Parents: 066da5e Author: Romain manni-Bucau <rmannibu...@gmail.com> Authored: Fri Jun 17 12:24:19 2016 +0200 Committer: Romain manni-Bucau <rmannibu...@gmail.com> Committed: Fri Jun 17 12:24:19 2016 +0200 ---------------------------------------------------------------------- .../apache/openejb/api/resource/Template.java | 29 ++++ .../openejb/config/ConfigurationFactory.java | 132 ++++++++++++------- .../java/org/apache/openejb/config/Service.java | 2 + .../openejb/config/sys/AbstractService.java | 10 ++ .../apache/openejb/config/sys/StackHandler.java | 1 + .../apache/openejb/resource/TemplateTest.java | 63 +++++++++ 6 files changed, 189 insertions(+), 48 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/a5d08be1/container/openejb-api/src/main/java/org/apache/openejb/api/resource/Template.java ---------------------------------------------------------------------- diff --git a/container/openejb-api/src/main/java/org/apache/openejb/api/resource/Template.java b/container/openejb-api/src/main/java/org/apache/openejb/api/resource/Template.java new file mode 100644 index 0000000..bb56f28 --- /dev/null +++ b/container/openejb-api/src/main/java/org/apache/openejb/api/resource/Template.java @@ -0,0 +1,29 @@ +/* + * 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.api.resource; + +/** + * Called to setup a service/resource. + * + * It is called at the very beginning of resource configuration (ie before provider are resolved) + * so the resource can be fully configured. + * + * @param <T> Service or AbstractService or Resource. + */ +public interface Template<T> { + void configure(T resource); +} http://git-wip-us.apache.org/repos/asf/tomee/blob/a5d08be1/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java b/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java index 99a91b9..e9fd1d1 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java @@ -22,6 +22,7 @@ import org.apache.openejb.OpenEJBException; import org.apache.openejb.Vendor; import org.apache.openejb.api.Proxy; import org.apache.openejb.api.resource.PropertiesResourceProvider; +import org.apache.openejb.api.resource.Template; import org.apache.openejb.assembler.classic.AppInfo; import org.apache.openejb.assembler.classic.Assembler; import org.apache.openejb.assembler.classic.BmpEntityContainerInfo; @@ -790,6 +791,7 @@ public class ConfigurationFactory implements OpenEjbConfigurationFactory { service.setConstructor(map.remove("constructor")); service.setFactoryName(map.remove("factory-name")); service.setPropertiesProvider(map.remove("properties-provider")); + service.setTemplate(map.remove("template")); final String cp = map.remove("classpath"); if (null != cp) { @@ -1156,30 +1158,23 @@ public class ConfigurationFactory implements OpenEjbConfigurationFactory { } } - final String providerType = getProviderType(service); - - final ServiceProvider provider = resolveServiceProvider(service, infoType); - - if (provider == null) { - final List<ServiceProvider> providers = ServiceUtils.getServiceProvidersByServiceType(providerType); - final StringBuilder sb = new StringBuilder(); - final List<String> types = new ArrayList<String>(); - for (final ServiceProvider p : providers) { - for (final String type : p.getTypes()) { - if (types.contains(type)) { - continue; - } - types.add(type); - sb.append(System.getProperty("line.separator")); - sb.append(" <").append(p.getService()); - sb.append(" id=\"").append(service.getId()).append('"'); - sb.append(" type=\"").append(type).append("\"/>"); - } + { + String template = service.getTemplate(); + if (template == null) { + template = SystemInstance.get().getProperty(Template.class.getName()); + } + if (template != null) { + template = unaliasPropertiesProvider(template); + + // don't trim them, user wants to handle it himself, let him do it + final ObjectRecipe recipe = newObjectRecipe(template); + recipe.setProperty("serviceId", service.getId()); + // note: we can also use reflection if needed to limit the dependency + Template.class.cast(recipe.create()).configure(service); } - final String noProviderMessage = messages.format("configureService.noProviderForService", providerType, service.getId(), service.getType(), service.getProvider(), sb.toString()); - throw new NoSuchProviderException(noProviderMessage); } + final ServiceProvider provider = getServiceProvider(service, infoType); if (service.getId() == null) { service.setId(provider.getId()); } @@ -1225,39 +1220,33 @@ public class ConfigurationFactory implements OpenEjbConfigurationFactory { props.putAll(provider.getProperties()); } - props.putAll(serviceProperties); - props.putAll(overrides); - - // force user properties last - String propertiesProvider = service.getPropertiesProvider(); - if (propertiesProvider == null) { - propertiesProvider = SystemInstance.get().getProperty(PropertiesResourceProvider.class.getName()); + if (serviceProperties != null) { + props.putAll(serviceProperties); } - if (propertiesProvider != null) { - propertiesProvider = unaliasPropertiesProvider(propertiesProvider); - - // don't trim them, user wants to handle it himself, let him do it - final ObjectRecipe recipe = new ObjectRecipe(propertiesProvider); - recipe.allow(Option.CASE_INSENSITIVE_PROPERTIES); - recipe.allow(Option.PRIVATE_PROPERTIES); - recipe.allow(Option.FIELD_INJECTION); - recipe.allow(Option.NAMED_PARAMETERS); - recipe.allow(Option.IGNORE_MISSING_PROPERTIES); - recipe.setFactoryMethod("provides"); - recipe.setProperty("serviceId", service.getId()); - recipe.setProperties(props); - recipe.setProperty("properties", props); // let user get all config - final Properties p = Properties.class.cast(recipe.create()); + props.putAll(overrides); - props.putAll(p); + {// force user properties last + String propertiesProvider = service.getPropertiesProvider(); + if (propertiesProvider == null) { + propertiesProvider = SystemInstance.get().getProperty(PropertiesResourceProvider.class.getName()); + } + if (propertiesProvider != null) { + propertiesProvider = unaliasPropertiesProvider(propertiesProvider); + + // don't trim them, user wants to handle it himself, let him do it + final ObjectRecipe recipe = newObjectRecipe(propertiesProvider); + recipe.setFactoryMethod("provides"); + recipe.setProperty("serviceId", service.getId()); + recipe.setProperties(props); + recipe.setProperty("properties", props); // let user get all config + final Properties p = Properties.class.cast(recipe.create()); + + props.putAll(p); + } } props.remove(IGNORE_DEFAULT_VALUES_PROP); - if (providerType != null && !provider.getService().equals(providerType)) { - throw new OpenEJBException(messages.format("configureService.wrongProviderType", service.getId(), providerType)); - } - final T info; try { info = infoType.newInstance(); @@ -1305,6 +1294,49 @@ public class ConfigurationFactory implements OpenEjbConfigurationFactory { } } + private <T extends ServiceInfo> ServiceProvider getServiceProvider( + final org.apache.openejb.config.Service service, + final Class<? extends T> infoType) throws OpenEJBException { + final String providerType = getProviderType(service); + + final ServiceProvider provider = resolveServiceProvider(service, infoType); + + if (provider == null) { + final List<ServiceProvider> providers = ServiceUtils.getServiceProvidersByServiceType(providerType); + final StringBuilder sb = new StringBuilder(); + final List<String> types = new ArrayList<String>(); + for (final ServiceProvider p : providers) { + for (final String type : p.getTypes()) { + if (types.contains(type)) { + continue; + } + types.add(type); + sb.append(System.getProperty("line.separator")); + sb.append(" <").append(p.getService()); + sb.append(" id=\"").append(service.getId()).append('"'); + sb.append(" type=\"").append(type).append("\"/>"); + } + } + final String noProviderMessage = messages.format("configureService.noProviderForService", providerType, service.getId(), service.getType(), service.getProvider(), sb.toString()); + throw new NoSuchProviderException(noProviderMessage); + } + + if (!provider.getService().equals(providerType)) { + throw new OpenEJBException(messages.format("configureService.wrongProviderType", service.getId(), providerType)); + } + return provider; + } + + private ObjectRecipe newObjectRecipe(final String template) { + final ObjectRecipe recipe = new ObjectRecipe(template); + recipe.allow(Option.CASE_INSENSITIVE_PROPERTIES); + recipe.allow(Option.PRIVATE_PROPERTIES); + recipe.allow(Option.FIELD_INJECTION); + recipe.allow(Option.NAMED_PARAMETERS); + recipe.allow(Option.IGNORE_MISSING_PROPERTIES); + return recipe; + } + private static String unaliasPropertiesProvider(final String propertiesProvider) { switch (propertiesProvider.toLowerCase(Locale.ENGLISH)) { case "heroku": @@ -1318,6 +1350,10 @@ public class ConfigurationFactory implements OpenEjbConfigurationFactory { } } + private static String unaliasTemplate(final String value) { + return value; + } + /** * Takes a raw unparsed string expected to be in jvm classpath syntax * and parses it, producing a collection of URIs representing the absolute http://git-wip-us.apache.org/repos/asf/tomee/blob/a5d08be1/container/openejb-core/src/main/java/org/apache/openejb/config/Service.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/Service.java b/container/openejb-core/src/main/java/org/apache/openejb/config/Service.java index 7ca596d..58d9792 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/config/Service.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/config/Service.java @@ -67,4 +67,6 @@ public interface Service { String getClasspath(); String getPropertiesProvider(); + + String getTemplate(); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tomee/blob/a5d08be1/container/openejb-core/src/main/java/org/apache/openejb/config/sys/AbstractService.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/sys/AbstractService.java b/container/openejb-core/src/main/java/org/apache/openejb/config/sys/AbstractService.java index 6181df5..5771632 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/config/sys/AbstractService.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/config/sys/AbstractService.java @@ -83,6 +83,8 @@ public abstract class AbstractService implements Service { @XmlAttribute(name = "properties-provider") private String propertiesProvider; + @XmlAttribute(name = "template") + private String template; protected AbstractService(final String id) { this(id, null, null); @@ -227,6 +229,14 @@ public abstract class AbstractService implements Service { this.classpath = classpath; } + public String getTemplate() { + return template; + } + + public void setTemplate(final String template) { + this.template = template; + } + @Override public boolean equals(final Object o) { if (this == o) { http://git-wip-us.apache.org/repos/asf/tomee/blob/a5d08be1/container/openejb-core/src/main/java/org/apache/openejb/config/sys/StackHandler.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/sys/StackHandler.java b/container/openejb-core/src/main/java/org/apache/openejb/config/sys/StackHandler.java index 965c2b5..9f14676 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/config/sys/StackHandler.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/config/sys/StackHandler.java @@ -224,6 +224,7 @@ public class StackHandler extends DefaultHandler { service.setJndi(attributes.getValue("jndi")); service.setPostConstruct(attributes.getValue("post-construct")); service.setPreDestroy(attributes.getValue("pre-destroy")); + service.setTemplate(attributes.getValue("template")); service.setPropertiesProvider(attributes.getValue("property-provider")); if (service.getPropertiesProvider() == null) { service.setPropertiesProvider(attributes.getValue("properties-provider")); http://git-wip-us.apache.org/repos/asf/tomee/blob/a5d08be1/container/openejb-core/src/test/java/org/apache/openejb/resource/TemplateTest.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/test/java/org/apache/openejb/resource/TemplateTest.java b/container/openejb-core/src/test/java/org/apache/openejb/resource/TemplateTest.java new file mode 100644 index 0000000..9ad1eff --- /dev/null +++ b/container/openejb-core/src/test/java/org/apache/openejb/resource/TemplateTest.java @@ -0,0 +1,63 @@ +/* + * 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.resource; + +import org.apache.openejb.api.resource.Template; +import org.apache.openejb.config.sys.AbstractService; +import org.apache.openejb.junit.ApplicationComposer; +import org.apache.openejb.testing.Classes; +import org.apache.openejb.testing.Configuration; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.annotation.Resource; +import java.util.Properties; + +import static org.junit.Assert.assertEquals; + +@Classes +@RunWith(ApplicationComposer.class) +public class TemplateTest { + @Resource(name = "r1") + private MyResource r1; + + @Test + public void validAliases() { + assertEquals("r1", r1.value); + } + + @Configuration + public Properties config() { + final Properties p = new Properties(); + p.put("r1", "new://Resource?template=org.apache.openejb.resource.TemplateTest$MyTemplate"); + return p; + } + + public static class MyResource { + private String value; + } + + public static class MyTemplate implements Template<AbstractService> { + private String serviceId; + + @Override + public void configure(final AbstractService resource) { + resource.setClassName(MyResource.class.getName()); + resource.getProperties().put("value", serviceId); + } + } +}