Skip to content

Commit

Permalink
EE10 Concurrency work (#1103)
Browse files Browse the repository at this point in the history
EE10  Concurrency work
  • Loading branch information
rzo1 authored Jan 30, 2024
2 parents be4545d + 4f7515d commit 3bfb14b
Show file tree
Hide file tree
Showing 77 changed files with 3,224 additions and 715 deletions.
1 change: 1 addition & 0 deletions arquillian/arquillian-tomee-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<version>2.1.1</version>
<executions>
<execution>
<id>configure-adapters</id>
Expand Down
1 change: 0 additions & 1 deletion container/openejb-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -777,4 +777,3 @@
</profile>
</profiles>
</project>

Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
import org.apache.openejb.spi.ApplicationServer;
import org.apache.openejb.spi.ContainerSystem;
import org.apache.openejb.spi.SecurityService;
import org.apache.openejb.threads.impl.ContextServiceImplFactory;
import org.apache.openejb.threads.impl.ManagedExecutorServiceImpl;
import org.apache.openejb.util.Contexts;
import org.apache.openejb.util.DaemonThreadFactory;
Expand Down Expand Up @@ -1783,7 +1784,7 @@ private void ensureWebBeansContext(final AppContext appContext) {

final Map<Class<?>, Object> services = new HashMap<>();

services.put(Executor.class, new ManagedExecutorServiceImpl(ForkJoinPool.commonPool()));
services.put(Executor.class, new ManagedExecutorServiceImpl(ForkJoinPool.commonPool(), ContextServiceImplFactory.newPropagateEverythingContextService()));
services.put(JNDIService.class, new OpenEJBJndiService());
services.put(AppContext.class, appContext);
services.put(ScannerService.class, new CdiScanner());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.openejb.cdi;

import org.apache.openejb.Injection;
import org.apache.openejb.jee.ContextService;
import org.apache.openejb.jee.DataSource;
import org.apache.openejb.jee.EjbLocalRef;
import org.apache.openejb.jee.EjbRef;
Expand Down Expand Up @@ -65,6 +66,7 @@ public class CdiBeanInfo implements JndiConsumer {
private String beanName;
private ClassLoader classLoader;
private List<Injection> injections;
private KeyedCollection<String, ContextService> contextService;

public String getBeanName() {
return beanName;
Expand Down Expand Up @@ -321,4 +323,11 @@ public String getJndiConsumerName() {
public Class<?> getBeanClass() {
return this.beanClass;
}
@Override
public Map<String, ContextService> getContextServiceMap() {
if (contextService == null) {
contextService = new KeyedCollection<String, ContextService>();
}
return this.contextService.toMap();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.apache.openejb.loader.event.ComponentAdded;
import org.apache.openejb.loader.event.ComponentRemoved;
import org.apache.openejb.observer.Observes;
import org.apache.openejb.threads.impl.ContextServiceImplFactory;
import org.apache.openejb.threads.impl.ManagedExecutorServiceImpl;
import org.apache.openejb.threads.impl.ManagedThreadFactoryImpl;
import org.apache.openejb.util.AppFinder;
Expand Down Expand Up @@ -178,7 +179,7 @@ public void execute(final Runnable command) {
.size(3)
.threadFactory(new ManagedThreadFactoryImpl(appContext.getId() + "-cdi-fireasync-"))
.prefix("CDIAsyncPool")
.build(appContext.getOptions()));
.build(appContext.getOptions()), ContextServiceImplFactory.newPropagateEverythingContextService());
delegate.compareAndSet(null, executor);
} else {
executor = alreadyUpdated;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
import jakarta.el.ELResolver;
import jakarta.el.PropertyNotFoundException;
import jakarta.el.PropertyNotWritableException;
import java.beans.FeatureDescriptor;
import java.util.Iterator;

public class WebAppElResolver extends ELResolver {
private final ELResolver parent;
Expand Down Expand Up @@ -63,12 +61,7 @@ public boolean isReadOnly(final ELContext context, final Object base, final Obje
}

@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(final ELContext context, final Object base) {
return null;
}

@Override
public Class<?> getCommonPropertyType(final ELContext context, final Object base) {
public Class<?> getCommonPropertyType(ELContext context, Object base) {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.openejb.config;

import jakarta.enterprise.concurrent.ContextServiceDefinition;
import jakarta.interceptor.AroundConstruct;
import org.apache.openejb.BeanContext;
import org.apache.openejb.OpenEJBException;
Expand Down Expand Up @@ -47,6 +48,7 @@
import org.apache.openejb.jee.ConfigProperty;
import org.apache.openejb.jee.ContainerConcurrency;
import org.apache.openejb.jee.ContainerTransaction;
import org.apache.openejb.jee.ContextService;
import org.apache.openejb.jee.DataSource;
import org.apache.openejb.jee.EjbJar;
import org.apache.openejb.jee.EjbLocalRef;
Expand Down Expand Up @@ -121,6 +123,7 @@
import org.apache.openejb.jee.TransactionType;
import org.apache.openejb.jee.WebApp;
import org.apache.openejb.jee.WebserviceDescription;
import org.apache.openejb.jee.jba.JndiName;
import org.apache.openejb.jee.oejb3.OpenejbJar;
import org.apache.openejb.loader.JarLocation;
import org.apache.openejb.loader.SystemInstance;
Expand Down Expand Up @@ -4062,6 +4065,22 @@ public void buildAnnotatedRefs(final JndiConsumer consumer, final IAnnotationFin
buildDataSourceDefinition(consumer, definition);
}

//
// @ContextServiceDefinition
//

for (final Annotated<Class<?>> annotated : annotationFinder.findMetaAnnotatedClasses(ContextServiceDefinition.List.class)) {
final ContextServiceDefinition.List defs = annotated.getAnnotation(ContextServiceDefinition.List.class);
for (final ContextServiceDefinition definition : defs.value()) {
buildContextServiceDefinition(consumer, definition);
}
}

for (final Annotated<Class<?>> annotated : annotationFinder.findMetaAnnotatedClasses(ContextServiceDefinition.class)) {
final ContextServiceDefinition definition = annotated.getAnnotation(ContextServiceDefinition.class);
buildContextServiceDefinition(consumer, definition);
}

//
// @JMSConnectionFactoryDefinition
//
Expand Down Expand Up @@ -4093,6 +4112,31 @@ public void buildAnnotatedRefs(final JndiConsumer consumer, final IAnnotationFin
}
}

private void buildContextServiceDefinition(final JndiConsumer consumer, final ContextServiceDefinition definition) {
final ContextService existing = consumer.getContextServiceMap().get(definition.name());
final ContextService contextService = (existing != null) ? existing : new ContextService();

if (contextService.getName() == null) {
final JndiName jndiName = new JndiName();
jndiName.setvalue(definition.name());
contextService.setName(jndiName);
}

if (contextService.getCleared().isEmpty()) {
contextService.getCleared().addAll(Arrays.asList(definition.cleared()));
}

if (contextService.getPropagated().isEmpty()) {
contextService.getPropagated().addAll(Arrays.asList(definition.propagated()));
}

if (contextService.getUnchanged().isEmpty()) {
contextService.getUnchanged().addAll(Arrays.asList(definition.unchanged()));
}

consumer.getContextServiceMap().put(definition.name(), contextService);
}

private void buildContext(final JndiConsumer consumer, final Member member) {
final ContextRef ref = new ContextRef();
ref.setName(member.getDeclaringClass().getName() + "/" + member.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2209,6 +2209,14 @@ private String installResource(final String beanName, final ResourceInfo resourc
}
}

final String contextId = resourceInfo.properties.getProperty("Context");
if (contextId != null && contextId.length() > 0) {
final String newResourceId = getResourceId(beanName, contextId, null, null);
if (!contextId.equals(newResourceId)) {
resourceInfo.properties.setProperty("Context", newResourceId);
}
}

configFactory.install(resourceInfo);
return resourceInfo.id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,25 +92,33 @@ private void add(final JndiConsumer jndi, final DeploymentModule module, final D
add(jndi.getResourceEnvRefMap(), new ResourceEnvRef().name("java:comp/TransactionSynchronizationRegistry").type(TransactionSynchronizationRegistry.class));

if (defaults) {
// From: https://jakarta.ee/specifications/concurrency/3.0/jakarta-concurrency-spec-3.0.pdf
// Jakarta Concurrency §3.1.4.3
add(jndi.getResourceEnvRefMap(), new ResourceEnvRef().name("java:comp/DefaultManagedExecutorService").type(ManagedExecutorService.class));

// Jakarta Concurrency §3.2.4.3
add(jndi.getResourceEnvRefMap(), new ResourceEnvRef().name("java:comp/DefaultManagedScheduledExecutorService").type(ManagedScheduledExecutorService.class));

// Jakarta Concurrency §3.4.4.3
add(jndi.getResourceEnvRefMap(), new ResourceEnvRef().name("java:comp/DefaultManagedThreadFactory").type(ManagedThreadFactory.class));

// Jakarta Concurrency §3.3.4.3
add(jndi.getResourceEnvRefMap(), new ResourceEnvRef().name("java:comp/DefaultContextService").type(ContextService.class));


try {
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
contextClassLoader.loadClass("org.apache.activemq.ActiveMQSslConnectionFactory");
final ResourceEnvRef ref = new ResourceEnvRef().name("java:comp/DefaultJMSConnectionFactory")
.type(contextClassLoader.loadClass("jakarta.jms.ConnectionFactory"));
.type(contextClassLoader.loadClass("jakarta.jms.ConnectionFactory"));
add(jndi.getResourceEnvRefMap(), ref);
} catch (final ClassNotFoundException | NoClassDefFoundError notThere) {
// no-op
}
}


// OpenEJB specific feature
add(jndi.getEnvEntryMap(), new EnvEntry().name("java:comp/ComponentName").value(jndi.getJndiConsumerName()).type(String.class));

}

private <E extends JndiReference> void add(final Map<String, E> map, final E entry) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ public ConfigurationFactory(final boolean offline, final DynamicDeployer preAuto
}

chain.add(new ConvertDataSourceDefinitions());
chain.add(new ConvertContextServiceDefinitions());
chain.add(new ConvertJMSConnectionFactoryDefinitions());
chain.add(new ConvertJMSDestinationDefinitions());
chain.add(new CleanEnvEntries());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* 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.config;

import org.apache.openejb.OpenEJBException;
import org.apache.openejb.config.sys.Resource;
import org.apache.openejb.jee.ContextService;
import org.apache.openejb.jee.JndiConsumer;
import org.apache.openejb.jee.KeyedCollection;
import org.apache.openejb.util.Join;
import org.apache.openejb.util.PropertyPlaceHolderHelper;

import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
* @version $Rev$ $Date$
*/
public class ConvertContextServiceDefinitions extends BaseConvertDefinitions {

@Override
public AppModule deploy(final AppModule appModule) throws OpenEJBException {

final List<JndiConsumer> jndiConsumers = collectConsumers(appModule);

final KeyedCollection<String, ContextService> contextServices = new KeyedCollection<>();
final KeyedCollection<String, ContextService> contextServicesFromCompManagedBeans = new KeyedCollection<>();

for (final JndiConsumer consumer : jndiConsumers) {
if (consumer == null) {
continue;
}

if (consumer instanceof CompManagedBean) {
/*
* TOMEE-2053: It may contain invalid context service definitions
* because it is never updated with content from the ejb-jar.xml
* Wait until all other consumers have been processed, to safely
* decide which context services to transfer;
*/

contextServicesFromCompManagedBeans.addAll(consumer.getContextServiceMap().values());
continue;
}
contextServices.addAll(consumer.getContextServiceMap().values());
}

final Map<String, ContextService> dataSourcesMap = contextServices.toMap();
for(ContextService contextService : contextServicesFromCompManagedBeans){
//Interested only in ContextServices that come from non-JndiConsumers
if(!dataSourcesMap.containsKey(contextService.getName().getvalue())){
contextServices.add(contextService);
}
}

for (final ContextService dataSource : contextServices) {
appModule.getResources().add(toResource(dataSource));
}
return appModule;
}


private Resource toResource(final ContextService contextService) {
final String name = cleanUpName(contextService.getName().getvalue());

final Resource def = new Resource(name, jakarta.enterprise.concurrent.ContextService.class.getName());

def.setJndi(contextService.getName().getvalue().replaceFirst("java:", ""));
def.setType(jakarta.enterprise.concurrent.ContextService.class.getName());

final Properties p = def.getProperties();
put(p, "propagated", Join.join(",", contextService.getPropagated()));
put(p, "cleared", Join.join(",", contextService.getCleared()));
put(p, "unchanged", Join.join(",", contextService.getUnchanged()));

// to force it to be bound in JndiEncBuilder
put(p, "JndiName", def.getJndi());

return def;
}

private static void put(final Properties properties, final String key, final Object value) {
if (key == null) {
return;
}
if (value == null) {
return;
}

properties.put(key, PropertyPlaceHolderHelper.value(String.valueOf(value)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ protected BaseContext(final SecurityService securityService, final UserTransacti
}

private boolean isAsyncOperation(final ThreadContext threadContext) {
if (threadContext.getCurrentOperation() == null
&& threadContext.get(CUTask.Context.class) != null) {
if (threadContext.getCurrentOperation() == null) {
return true;
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ public static ThreadContext getThreadContext() {
return threadStorage.get();
}

public static ThreadContext clear() {
final ThreadContext oldContext = threadStorage.get();
threadStorage.set(null);
return oldContext;
}


public static ThreadContext enter(final ThreadContext newContext) {
if (newContext == null) {
throw new NullPointerException("newContext is null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,8 @@ public PersistenceClassFileTransformer(final ClassTransformer classTransformer)
this.classTransformer = classTransformer;
}

public byte[] transform(final ClassLoader classLoader, final String className, final Class<?> classBeingRedefined, final ProtectionDomain protectionDomain, final byte[] classfileBuffer) throws IllegalClassFormatException {
public byte[] transform(final ClassLoader classLoader, final String className, final Class<?> classBeingRedefined,
final ProtectionDomain protectionDomain, final byte[] classfileBuffer) throws IllegalClassFormatException {
// Example code to easily debug transformation of a specific class
// if ("org/apache/openejb/test/entity/cmp/BasicCmpBean".equals(className) ||
// "org/apache/openejb/test/entity/cmp/BasicCmp2Bean_BasicCmp2Bean".equals(className)) {
Expand Down
Loading

0 comments on commit 3bfb14b

Please sign in to comment.