You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2019/12/12 16:20:35 UTC
[isis] 01/02: ISIS-2177: remove home-brew request-scope handling
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 9200522da7445f3542edbac3efac63b3c5328e2d
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Dec 12 17:16:19 2019 +0100
ISIS-2177: remove home-brew request-scope handling
---
.../ServiceInjectorTestUsingCodegenPlugin.java | 157 ----------
.../ServiceInstantiatorTestUsingCodegenPlugin.java | 218 --------------
.../persistence/PersistenceSession5.java | 59 ++--
.../isis/runtime/services/ServiceInstantiator.java | 331 ---------------------
.../isis/runtime/scoping/RequestScopedService.java | 79 -----
5 files changed, 24 insertions(+), 820 deletions(-)
diff --git a/core/detached-tests/src/test/java/org/apache/isis/runtime/services/ServiceInjectorTestUsingCodegenPlugin.java b/core/detached-tests/src/test/java/org/apache/isis/runtime/services/ServiceInjectorTestUsingCodegenPlugin.java
deleted file mode 100644
index fa82903..0000000
--- a/core/detached-tests/src/test/java/org/apache/isis/runtime/services/ServiceInjectorTestUsingCodegenPlugin.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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.isis.runtime.services;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
-import javax.enterprise.context.RequestScoped;
-
-import org.apache.isis.runtime.scoping.RequestScopedService;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.apache.isis.applib.services.inject.ServiceInjector;
-import org.apache.isis.applib.services.registry.ServiceRegistry;
-import org.apache.isis.metamodel.MetaModelContext_forTesting;
-import org.apache.isis.unittestsupport.jmocking.JUnitRuleMockery2;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-public class ServiceInjectorTestUsingCodegenPlugin {
-
- @Rule
- public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(JUnitRuleMockery2.Mode.INTERFACES_AND_CLASSES);
-
- private ServiceInstantiator serviceInstantiator;
- private ServiceRegistry serviceRegistry;
- private ServiceInjector serviceInjector;
-
- private MetaModelContext_forTesting metaModelContext;
-
-
- @Before
- public void setUp() throws Exception {
-
- serviceInstantiator = new ServiceInstantiator();
-
- metaModelContext = MetaModelContext_forTesting.builder()
- .singleton(serviceInstantiator.createInstance(SingletonCalculator.class))
- .singleton(serviceInstantiator.createInstance(AccumulatingCalculator.class))
- .build();
-
- serviceRegistry = metaModelContext.getServiceRegistry();
- serviceInjector = metaModelContext.getServiceInjector();
- }
-
- @Test
- public void singleton() {
- SingletonCalculator calculator = serviceRegistry.lookupService(SingletonCalculator.class).get();
- assertThat(calculator.add(3), is(3));
- calculator = serviceRegistry.lookupService(SingletonCalculator.class).get();
- assertThat(calculator.add(4), is(7));
- }
-
- @Test
- public void requestScoped_instantiate() {
- final AccumulatingCalculator calculator = serviceRegistry.lookupService(AccumulatingCalculator.class).get();
- assertThat(calculator instanceof RequestScopedService, is(true));
- }
-
- @Test
- public void requestScoped_justOneThread() {
- final AccumulatingCalculator calculator = serviceRegistry.lookupService(AccumulatingCalculator.class).get();
-
- try {
- ((RequestScopedService)calculator).__isis_startRequest(serviceInjector);
- assertThat(calculator.add(3), is(3));
- assertThat(calculator.add(4), is(7));
- assertThat(calculator.getTotal(), is(7));
- } finally {
- ((RequestScopedService)calculator).__isis_endRequest();
- }
- }
-
- @Test
- public void requestScoped_multipleThreads() throws InterruptedException, ExecutionException {
-
- final AccumulatingCalculator calculator = serviceRegistry.lookupService(AccumulatingCalculator.class).get();
- final ExecutorService executor = Executors.newFixedThreadPool(10);
-
- // setup 32 tasks
- final List<Callable<Integer>> tasks = IntStream.range(0, 1000)
- .<Callable<Integer>>mapToObj(index->()->{
-
- // within each task setup a new calculator instance that adds the numbers from 1 .. 100 = 5050
- ((RequestScopedService)calculator).__isis_startRequest(serviceInjector);
- for(int i=1; i<=100; i++) {
- calculator.add(i);
- }
- try {
- return calculator.getTotal();
- } finally {
- ((RequestScopedService)calculator).__isis_endRequest();
- }
- })
- .collect(Collectors.toList());
-
-
- final List<Future<Integer>> results = executor.invokeAll(tasks);
- executor.shutdown();
- executor.awaitTermination(5, TimeUnit.SECONDS);
-
- // we expect that each of the 32 calculators have calculated the sum correctly
- for(Future<Integer> future: results) {
- assertThat(future.get(), is(5050));
- }
- }
-
- public static class SingletonCalculator {
- private int total;
- public int add(int x) {
- total += x;
- return getTotal();
- }
- public int getTotal() {
- return total;
- }
- }
-
- @RequestScoped
- public static class AccumulatingCalculator {
- private int total;
- public int add(int x) {
- total += x;
- return getTotal();
- }
- public int getTotal() {
- return total;
- }
- }
-
-}
diff --git a/core/detached-tests/src/test/java/org/apache/isis/runtime/services/ServiceInstantiatorTestUsingCodegenPlugin.java b/core/detached-tests/src/test/java/org/apache/isis/runtime/services/ServiceInstantiatorTestUsingCodegenPlugin.java
deleted file mode 100644
index 7ec1817..0000000
--- a/core/detached-tests/src/test/java/org/apache/isis/runtime/services/ServiceInstantiatorTestUsingCodegenPlugin.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * 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.isis.runtime.services;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.BrokenBarrierException;
-import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-import javax.enterprise.context.RequestScoped;
-
-import org.apache.isis.runtime.scoping.RequestScopedService;
-import org.jmock.auto.Mock;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.apache.isis.applib.services.inject.ServiceInjector;
-import org.apache.isis.commons.internal.base._NullSafe;
-import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.unittestsupport.jmocking.JUnitRuleMockery2;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-public class ServiceInstantiatorTestUsingCodegenPlugin {
-
- @Rule
- public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(JUnitRuleMockery2.Mode.INTERFACES_AND_CLASSES);
-
- private ServiceInstantiator serviceInstantiator;
-
- @JUnitRuleMockery2.Ignoring
- @Mock
- private ServiceInjector mockServiceInjector;
-
- @Before
- public void setUp() throws Exception {
-
- serviceInstantiator = new ServiceInstantiator();
- }
-
- @Test
- public void singleton() {
- SingletonCalculator calculator = serviceInstantiator.createInstance(SingletonCalculator.class);
- assertThat(calculator.add(3,4), is(7));
- }
-
- @Test
- public void requestScoped_instantiate() {
- AccumulatingCalculator calculator = serviceInstantiator.createInstance(AccumulatingCalculator.class);
- assertThat(calculator instanceof RequestScopedService, is(true));
- }
-
- @Test
- public void requestScoped_justOneThread() {
- AccumulatingCalculator calculator = serviceInstantiator.createInstance(AccumulatingCalculator.class);
- try {
- ((RequestScopedService)calculator).__isis_startRequest(mockServiceInjector);
- assertThat(calculator.add(3), is(3));
- assertThat(calculator.add(4), is(7));
- assertThat(calculator.getTotal(), is(7));
- } finally {
- ((RequestScopedService)calculator).__isis_endRequest();
- }
- }
-
- @Test
- public void requestScoped_multipleThreads() throws InterruptedException, BrokenBarrierException {
-
- final AccumulatingCalculator calculator = serviceInstantiator.createInstance(AccumulatingCalculator.class);
-
- // will ask each thread's calculator to increment 10 times
- final int[] steps = new int[]{10};
-
- // each thread will post its totals here
- final int[] totals = new int[]{0,0,0};
-
- // after each step, all threads wait. The +1 is for this thread (the co-ordinator)
- final CyclicBarrier barrier =
- new CyclicBarrier(totals.length+1, new Runnable() {
- @Override
- public void run() {
- // all threads waiting; decrement number of steps
- steps[0]--;
- }
- });
-
- // start off all threads
- for(int i=0; i<totals.length; i++) {
- final int j=i;
- new Thread() {
- @Override
- public void run() {
- try {
- ((RequestScopedService)calculator).__isis_startRequest(mockServiceInjector);
- // keep incrementing, till no more steps
- while(steps[0]>0) {
- try {
- calculator.add((j+1));
- totals[j] = calculator.getTotal();
- barrier.await();
- } catch (InterruptedException | BrokenBarrierException e) {
- throw new RuntimeException(e);
- }
- }
- } finally {
- ((RequestScopedService)calculator).__isis_endRequest();
- }
- };
- }.start();
- }
-
- // this thread is the co-ordinator; move onto next step when all are waiting
- while(steps[0]>0) {
- barrier.await();
- }
-
- assertThat(totals[0], is(10));
- assertThat(totals[1], is(20));
- assertThat(totals[2], is(30));
- }
-
- @Test
- public void requestScoped_childThreads() throws InterruptedException {
-
- final Consumer consumer = serviceInstantiator.createInstance(Consumer.class);
-
- final List<Integer> allTheNumbers = Collections.synchronizedList(_Lists.<Integer>newArrayList());
-
- final int n = 100;
- for (int i = 0; i < n; i++) {
- allTheNumbers.add(i);
- }
-
- final int nThreads = 8;
- final ExecutorService execService = Executors.newFixedThreadPool(nThreads);
-
- // initialize the request scoped calculator on current thread ('main')
- ((RequestScopedService)consumer).__isis_startRequest(mockServiceInjector);
-
- for (int i = 0; i < n; i++) {
- final int j=i;
-
- execService.submit(new Runnable() {
- @Override public void run() {
- try {
-
- // access the request scoped calculator on a child thread of 'main'
- consumer.consume(allTheNumbers, j);
-
- } catch (Exception e) {
- System.err.println(e.getMessage());
- }
- }
- });
-
- }
-
- execService.shutdown();
-
- execService.awaitTermination(10, TimeUnit.SECONDS);
-
- ((RequestScopedService)consumer).__isis_endRequest();
-
- assertEquals(0L, _NullSafe.stream(allTheNumbers).filter(_NullSafe::isPresent).count());
- }
-
- public static class SingletonCalculator {
- public int add(int x, int y) {
- return x+y;
- }
- }
-
- @RequestScoped
- public static class AccumulatingCalculator {
- private int total;
- public int add(int x) {
- total += x;
- return getTotal();
- }
- public int getTotal() {
- return total;
- }
- }
-
- @RequestScoped
- public static class Consumer {
- public void consume(final List<Integer> queue, final int slot) {
- synchronized (queue) {
- final Integer integer = queue.get(slot);
- if(integer != null) {
- queue.set(slot, null);
- }
- }
- }
- }
-}
diff --git a/core/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java b/core/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java
index a5e3782..7a8b186 100644
--- a/core/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java
+++ b/core/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java
@@ -49,22 +49,12 @@ import org.apache.isis.applib.services.xactn.TransactionService;
import org.apache.isis.commons.exceptions.IsisException;
import org.apache.isis.commons.internal.collections._Maps;
import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.persistence.jdo.applib.exceptions.NotPersistableException;
-import org.apache.isis.persistence.jdo.applib.exceptions.UnsupportedFindException;
-import org.apache.isis.persistence.jdo.applib.fixturestate.FixturesInstalledStateHolder;
-import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.commands.DataNucleusCreateObjectCommand;
-import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.commands.DataNucleusDeleteObjectCommand;
-import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.queries.PersistenceQueryFindAllInstancesProcessor;
-import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.queries.PersistenceQueryFindUsingApplibQueryProcessor;
-import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.queries.PersistenceQueryProcessor;
-import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.spi.JdoObjectIdSerializer;
-import org.apache.isis.persistence.jdo.datanucleus5.objectadapter.ObjectAdapterContext;
-import org.apache.isis.metamodel.context.MetaModelContext;
import org.apache.isis.metamodel.adapter.ObjectAdapter;
import org.apache.isis.metamodel.adapter.oid.ObjectNotFoundException;
import org.apache.isis.metamodel.adapter.oid.Oid;
import org.apache.isis.metamodel.adapter.oid.PojoRefreshException;
import org.apache.isis.metamodel.adapter.oid.RootOid;
+import org.apache.isis.metamodel.context.MetaModelContext;
import org.apache.isis.metamodel.facets.collections.modify.CollectionFacet;
import org.apache.isis.metamodel.facets.object.callbacks.CallbackFacet;
import org.apache.isis.metamodel.facets.object.callbacks.LoadedCallbackFacet;
@@ -84,12 +74,21 @@ import org.apache.isis.metamodel.spec.EntityState;
import org.apache.isis.metamodel.spec.FreeStandingList;
import org.apache.isis.metamodel.spec.ManagedObject;
import org.apache.isis.metamodel.spec.ObjectSpecification;
+import org.apache.isis.persistence.jdo.applib.exceptions.NotPersistableException;
+import org.apache.isis.persistence.jdo.applib.exceptions.UnsupportedFindException;
+import org.apache.isis.persistence.jdo.applib.fixturestate.FixturesInstalledStateHolder;
+import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.commands.DataNucleusCreateObjectCommand;
+import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.commands.DataNucleusDeleteObjectCommand;
+import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.queries.PersistenceQueryFindAllInstancesProcessor;
+import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.queries.PersistenceQueryFindUsingApplibQueryProcessor;
+import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.queries.PersistenceQueryProcessor;
+import org.apache.isis.persistence.jdo.datanucleus5.datanucleus.persistence.spi.JdoObjectIdSerializer;
+import org.apache.isis.persistence.jdo.datanucleus5.objectadapter.ObjectAdapterContext;
import org.apache.isis.runtime.persistence.objectstore.transaction.CreateObjectCommand;
import org.apache.isis.runtime.persistence.objectstore.transaction.DestroyObjectCommand;
import org.apache.isis.runtime.persistence.objectstore.transaction.PersistenceCommand;
import org.apache.isis.runtime.persistence.query.PersistenceQueryFindAllInstances;
import org.apache.isis.runtime.persistence.query.PersistenceQueryFindUsingApplibQueryDefault;
-import org.apache.isis.runtime.scoping.RequestScopedService;
import org.apache.isis.runtime.system.persistence.PersistenceQuery;
import org.apache.isis.security.api.authentication.AuthenticationSession;
@@ -161,10 +160,10 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
// tell the proxy of all request-scoped services to instantiate the underlying
// services, store onto the thread-local and inject into them...
- startRequestOnRequestScopedServices();
+ //startRequestOnRequestScopedServices();
// ... and invoke all @PostConstruct
- postConstructOnRequestScopedServices();
+ //postConstructOnRequestScopedServices();
if(metricsService instanceof InstanceLifecycleListener) {
val metricsService = (InstanceLifecycleListener) this.metricsService;
@@ -190,16 +189,6 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
this.state = State.OPEN;
}
- private void postConstructOnRequestScopedServices() {
- serviceRegistry.select(RequestScopedService.class)
- .forEach(RequestScopedService::__isis_postConstruct);
- }
-
- private void startRequestOnRequestScopedServices() {
- serviceRegistry.select(RequestScopedService.class)
- .forEach(service->service.__isis_startRequest(serviceInjector));
- }
-
private Command createCommand() {
final Command command = commandService.create();
@@ -248,10 +237,10 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
// tell the proxy of all request-scoped services to invoke @PreDestroy
// (if any) on all underlying services stored on their thread-locals...
- preDestroyOnRequestScopedServices();
+ //preDestroyOnRequestScopedServices();
// ... and then remove those underlying services from the thread-local
- endRequestOnRequestScopeServices();
+ //endRequestOnRequestScopeServices();
persistenceManager.removeInstanceLifecycleListener(storeLifecycleListener);
@@ -268,15 +257,15 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
this.state = State.CLOSED;
}
- private void endRequestOnRequestScopeServices() {
- serviceRegistry.select(RequestScopedService.class)
- .forEach(RequestScopedService::__isis_endRequest);
- }
-
- private void preDestroyOnRequestScopedServices() {
- serviceRegistry.select(RequestScopedService.class)
- .forEach(RequestScopedService::__isis_preDestroy);
- }
+// private void endRequestOnRequestScopeServices() {
+// serviceRegistry.select(RequestScopedService.class)
+// .forEach(RequestScopedService::__isis_endRequest);
+// }
+//
+// private void preDestroyOnRequestScopedServices() {
+// serviceRegistry.select(RequestScopedService.class)
+// .forEach(RequestScopedService::__isis_preDestroy);
+// }
private void completeCommandFromInteractionAndClearDomainEvents() {
diff --git a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/ServiceInstantiator.java b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/ServiceInstantiator.java
deleted file mode 100644
index 7672c27..0000000
--- a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/ServiceInstantiator.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * 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.isis.runtime.services;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.enterprise.context.RequestScoped;
-
-import org.apache.isis.applib.services.inject.ServiceInjector;
-import org.apache.isis.commons.internal.collections._Arrays;
-import org.apache.isis.commons.internal.collections._Maps;
-import org.apache.isis.commons.internal.collections._Sets;
-import org.apache.isis.commons.internal.context._Context;
-import org.apache.isis.commons.internal.factory.InstanceCreationClassException;
-import org.apache.isis.commons.internal.factory.InstanceCreationException;
-import org.apache.isis.commons.internal.plugins.codegen.ProxyFactory;
-import org.apache.isis.metamodel.commons.MethodExtensions;
-import org.apache.isis.metamodel.specloader.classsubstitutor.ProxyEnhanced;
-import org.apache.isis.runtime.scoping.RequestScopedService;
-
-import lombok.extern.log4j.Log4j2;
-
-//import javassist.util.proxy.MethodFilter;
-//import javassist.util.proxy.MethodHandler;
-//import javassist.util.proxy.ProxyFactory;
-//import javassist.util.proxy.ProxyObject;
-
-/**
- * Instantiates the service, taking into account whether the service is annotated with
- * {@link RequestScoped} or not.
- *
- * <p>
- * For regular (non-annotated, global, singleton) services, this class simply instantiates
- * the object. This is then held as a singleton by Isis.
- *
- * <p>
- * For annotated, request-scoped services, this class instantiates a (singleton) proxy object
- * that internally uses a threadlocal to dispatch to the actual service object, one per thread.
- * The proxy additionally implements {@link RequestScopedService} interface, allowing the
- * system to initialize the proxy for the thread with every request, and tear down afterwards.
- *
- * <p>
- * Doing the thread-local stuff within the service proxy means that, for the rest of Isis,
- * services can continue to be considered to be singletons.
- *
- * <p>
- * <b>Note</b>: there is one limitation to using proxies, namely that field-level injection into
- * request-scoped services is not (yet) supported.
- */
-@Log4j2
-public final class ServiceInstantiator {
-
- public ServiceInstantiator() {
- }
-
- // //////////////////////////////////////
-
- public Object createInstance(String type) {
- final Class<?> cls = loadClass(type);
- if(cls == null || cls.isAnonymousClass()) {
- // eg a test class
- return null;
- }
-
- return createInstance(cls);
- }
-
- private Class<?> loadClass(final String className) {
- try {
- log.debug("loading class for service: {}", className);
- return _Context.loadClassAndInitialize(className);
- } catch (final ClassNotFoundException ex) {
- throw new InitialisationException(String.format("Cannot find class '%s' for service", className));
- }
- }
-
- // //////////////////////////////////////
-
- public <T> T createInstance(final Class<T> cls) {
- if(cls.isAnnotationPresent(RequestScoped.class)) {
- return instantiateRequestScopedProxy(cls);
- } else {
- return instantiateSingleton(cls);
- }
- }
-
- // //////////////////////////////////////
-
-
- private static <T> T instantiateSingleton(final Class<T> cls) {
- return instantiate(cls);
- }
-
- // //////////////////////////////////////
-
-
- private <T> T instantiateRequestScopedProxy(final Class<T> cls) {
-
- final Class<?>[] interfaces = _Arrays.combine(
- cls.getInterfaces(),
- new Class<?>[] { RequestScopedService.class, ProxyEnhanced.class });
-
- final ProxyFactory<T> proxyFactory = ProxyFactory.builder(cls)
- .interfaces(interfaces)
- .build();
-
- final InvocationHandler handler = new InvocationHandler() {
-
- // Allow serviceByThread to be propagated from the thread that starts the request
- // to any child-threads, hence InheritableThreadLocal.
- private InheritableThreadLocal<T> serviceByThread = new InheritableThreadLocal<>();
-
- @Override
- public Object invoke(final Object proxied, final Method proxyMethod, final Object[] args)
- throws Throwable {
-
- cacheMethodsIfNecessary(cls);
-
- if(proxyMethod.getName().equals("__isis_startRequest")) {
-
- T service = instantiate(cls);
- serviceByThread.set(service);
-
- ServiceInjector serviceInjector = (ServiceInjector) args[0];
- serviceInjector.injectServicesInto(service);
-
- return null;
-
- } else if(proxyMethod.getName().equals("__isis_postConstruct")) {
-
- final T service = serviceByThread.get();
-
- callPostConstructIfPresent(service);
-
- return null;
-
- } else if(proxyMethod.getName().equals("__isis_preDestroy")) {
-
- final T service = serviceByThread.get();
-
- callPreDestroyIfPresent(service);
-
- return null;
-
- } else if(proxyMethod.getName().equals("__isis_endRequest")) {
-
- serviceByThread.set(null);
- return null;
-
- } else if(proxyMethod.getName().equals("hashCode") && proxyMethod.getParameterTypes().length == 0) {
-
- final T service = serviceByThread.get();
- return service != null? service.hashCode(): this.hashCode();
-
- } else if(proxyMethod.getName().equals("equals") && proxyMethod.getParameterTypes().length == 1 && proxyMethod.getParameterTypes()[0] == Object.class) {
-
- final T service = serviceByThread.get();
- return service != null? service.equals(args[0]): this.equals(args[0]);
-
- } else if(proxyMethod.getName().equals("toString") && proxyMethod.getParameterTypes().length == 0) {
-
- final T service = serviceByThread.get();
- return service != null? service.toString(): this.toString();
-
- } else {
- T service = serviceByThread.get();
- if(service == null) {
- // shouldn't happen...
- throw new IllegalStateException("No service of type " + cls + " is available on this ");
- }
- final Object proxiedReturn = proxyMethod.invoke(service, args);
- return proxiedReturn;
- }
- }
-
- };
-
- return proxyFactory.createInstance(handler, false);
- }
-
- private Set<Class<?>> cached = _Sets.newHashSet();
- private Map<Class<?>, Method> postConstructMethodsByServiceClass = _Maps.newConcurrentHashMap();
- private Map<Class<?>, Method> preDestroyMethodsByServiceClass = _Maps.newConcurrentHashMap();
-
- <T> void callPostConstructIfPresent(T service) {
-
- final Class<?> serviceClass = service.getClass();
- final Method postConstructMethod = postConstructMethodsByServiceClass.get(serviceClass);
- if(postConstructMethod == null) {
- return;
- }
- final int numParams = postConstructMethod.getParameterTypes().length;
-
- if(log.isDebugEnabled()) {
- log.debug("... calling @PostConstruct method: {}: {}", serviceClass.getName(), postConstructMethod.getName());
- }
- // unlike shutdown, we don't swallow exceptions; would rather fail early
- if(numParams == 0) {
- MethodExtensions.invoke(postConstructMethod, service);
- } else {
- //TODO[2039] MethodExtensions.invoke(postConstructMethod, service, new Object[]{props});
- throw new UnsupportedOperationException("post-construct methods must not take any arguments");
- }
- }
-
- <T> void callPreDestroyIfPresent(T service) throws InvocationTargetException, IllegalAccessException {
-
- final Class<?> serviceClass = service.getClass();
- final Method preDestroyMethod = preDestroyMethodsByServiceClass.get(serviceClass);
- if(preDestroyMethod == null) {
- return;
- }
-
- if(log.isDebugEnabled()) {
- log.debug("... calling @PreDestroy method: {}: {}", serviceClass.getName(), preDestroyMethod.getName());
- }
- try {
- MethodExtensions.invoke(preDestroyMethod, service);
- } catch(Exception ex) {
- // do nothing
- log.warn("... @PreDestroy method threw exception - continuing anyway", ex);
- }
- }
-
-
- private void cacheMethodsIfNecessary(Class<?> serviceClass) {
- if(cached.contains(serviceClass)) {
- return;
- }
- cacheMethods(serviceClass);
- cached.add(serviceClass);
- }
-
- private void cacheMethods(Class<?> serviceClass) {
- final Method[] methods = serviceClass.getMethods();
-
- // @PostConstruct
- Method postConstructMethod = null;
- for (final Method method : methods) {
-
- final PostConstruct postConstructAnnotation = method.getAnnotation(PostConstruct.class);
- if (postConstructAnnotation == null) {
- continue;
- }
- if (postConstructMethod != null) {
- throw new RuntimeException("Found more than one @PostConstruct method; service is: " + serviceClass.getName() + ", found " + postConstructMethod.getName() + " and " + method.getName());
- }
-
- final Class<?>[] parameterTypes = method.getParameterTypes();
- switch (parameterTypes.length) {
- case 0:
- break;
- case 1:
- if (Map.class != parameterTypes[0]) {
- throw new RuntimeException("@PostConstruct method must be no-arg or 1-arg accepting java.util.Map; method is: " + serviceClass.getName() + "#" + method.getName());
- }
- break;
- default:
- throw new RuntimeException("@PostConstruct method must be no-arg or 1-arg accepting java.util.Map; method is: " + serviceClass.getName() + "#" + method.getName());
- }
- postConstructMethod = method;
- }
-
- // @PreDestroy
- Method preDestroyMethod = null;
- for (final Method method : methods) {
-
- final PreDestroy preDestroyAnnotation = method.getAnnotation(PreDestroy.class);
- if(preDestroyAnnotation == null) {
- continue;
- }
- if(preDestroyMethod != null) {
- throw new RuntimeException("Found more than one @PreDestroy method; service is: " + serviceClass.getName() + ", found " + preDestroyMethod.getName() + " and " + method.getName());
- }
-
- final Class<?>[] parameterTypes = method.getParameterTypes();
- switch(parameterTypes.length) {
- case 0:
- break;
- default:
- throw new RuntimeException("@PreDestroy method must be no-arg; method is: " + serviceClass.getName() + "#" + method.getName());
- }
- preDestroyMethod = method;
- }
-
- if(postConstructMethod != null) {
- postConstructMethodsByServiceClass.put(serviceClass, postConstructMethod);
- }
- if(preDestroyMethod != null) {
- preDestroyMethodsByServiceClass.put(serviceClass, preDestroyMethod);
- }
- }
-
- // //////////////////////////////////////
-
- private static <T> T instantiate(final Class<T> cls) {
- try {
- return cls.newInstance();
- } catch (final NoClassDefFoundError e) {
- throw new InstanceCreationClassException("Class found '" + cls + "', but is missing a dependent class", e);
- } catch (final InstantiationException e) {
- throw new InstanceCreationException("Could not instantiate an object of class '" + cls.getName() + "'; " + e.getMessage(), e);
- } catch (final IllegalAccessException e) {
- throw new InstanceCreationException("Could not access the class '" + cls.getName() + "'; " + e.getMessage(), e);
- }
- }
-
-
-}
diff --git a/core/runtime/src/main/java/org/apache/isis/runtime/scoping/RequestScopedService.java b/core/runtime/src/main/java/org/apache/isis/runtime/scoping/RequestScopedService.java
deleted file mode 100644
index 07081a5..0000000
--- a/core/runtime/src/main/java/org/apache/isis/runtime/scoping/RequestScopedService.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.isis.runtime.scoping;
-
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.applib.services.inject.ServiceInjector;
-
-/**
- * Interface in support of request-scoped domain services (is implemented by the Javassist proxy).
- *
- * <p>
- * Do NOT implement directly (will cause the javassist generation to fail). Instead the request-scoped service
- * can provide a (conventional) <code>@PostConstruct</code> and <code>@PreDestroy</code> method.
- * </p>
- */
-public interface RequestScopedService {
-
- /**
- * Indicates to the proxy that a new request is starting, so should instantiate a new instance of the underlying
- * service and bind to the thread, and inject into that service using the provided {@link ServiceInjector}.
- *
- * <p>
- * This is done before the <code>@PostConstruct</code>, see {@link #__isis_postConstruct()}.
- * </p>
- */
- @Programmatic
- public void __isis_startRequest(ServiceInjector injector);
-
- /**
- * Indicates to the proxy that <code>@PostConstruct</code> should be called on
- * underlying instance for current thread.
- *
- * <p>
- * This is done after the request has started, see {@link #__isis_startRequest(ServiceInjector)}.
- * </p>
- */
- @Programmatic
- public void __isis_postConstruct();
-
- /**
- * Indicates to the proxy that <code>@PreDestroy</code> should be called on
- * underlying instance for current thread.
- *
- * <p>
- * This is done prior to the request ending, see {@link #__isis_endRequest()}.
- * </p>
- */
- @Programmatic
- public void __isis_preDestroy();
-
- /**
- * Indicates to the proxy that request is ending, so should clean up and remove the
- * underlying instance for current thread.
- *
- * <p>
- * This is done after the <code>@PreDestroy</code>, see {@link #__isis_preDestroy()}.
- * </p>
- */
- @Programmatic
- public void __isis_endRequest();
-
-}