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 2018/01/23 18:52:17 UTC

[isis] branch ISIS-1846_internal_utils updated: ISIS-1846 minor refactoring: introduces _Context (internal API)

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch ISIS-1846_internal_utils
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/ISIS-1846_internal_utils by this push:
     new da7b587  ISIS-1846 minor refactoring: introduces _Context (internal API)
da7b587 is described below

commit da7b58731073f96958807c50722cba309623fe72
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Jan 23 19:51:46 2018 +0100

    ISIS-1846 minor refactoring: introduces _Context (internal API)
    
    IsisContext is no longer a concrete class, but instead an interface,
    that has only static methods and can not hold any state itself.
    
    Singletons are now internal API via _Context. _Context also provides the
    framework's internal single entry-point for requesting the framework's
    default class-loader. (The public entry-point is via IsisContext.)
---
 .../isis/applib/internal/context/_Context.java     | 136 +++++++++++++++++++++
 .../isis/applib/internal/context/_Contexts.java    |  72 -----------
 .../applib/internal/exceptions/_Exceptions.java    |   4 +-
 .../isis/applib/internal/reflection/_Reflect.java  |   4 +-
 .../isis/core/runtime/headless/IsisSystem.java     |   2 +-
 .../core/runtime/system/context/IsisContext.java   | 102 +++++++---------
 .../system/session/IsisSessionFactoryBuilder.java  |   8 +-
 7 files changed, 187 insertions(+), 141 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/context/_Context.java b/core/applib/src/main/java/org/apache/isis/applib/internal/context/_Context.java
new file mode 100644
index 0000000..ab7b256
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/internal/context/_Context.java
@@ -0,0 +1,136 @@
+/*
+ *  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.applib.internal.context;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+import org.apache.isis.applib.internal.base._Casts;
+
+/**
+ * <h1>- internal use only -</h1>
+ * <p>
+ * Provides a context for storing and retrieving singletons (usually application scoped).
+ * </p>
+ * <p>
+ * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/> 
+ * These may be changed or removed without notice!
+ * </p>
+ * @since 2.0.0
+ */
+public final class _Context {
+
+	private _Context(){}
+	
+	private final static Map<String, Object> singletonMap = new HashMap<>(); 
+
+	/**
+	 * Puts a singleton instance onto the current context.
+	 * @param type non-null
+	 * @param singleton non-null
+	 * @throws IllegalStateException if there is already an instance of same type on the current context.
+	 */
+	public static void putSingleton(Class<?> type, Object singleton) {
+		Objects.requireNonNull(type);
+		Objects.requireNonNull(singleton);
+		
+		if(singletonMap.containsKey(toKey(type)))
+			throw new IllegalStateException("there is already a singleton of type '"+type+"' on this context.");
+		
+		singletonMap.put(toKey(type), singleton);
+	}
+
+	/**
+	 * Gets a singleton instance of {@code type} if there is any, null otherwise.
+	 * @param type non-null
+	 * @return null, if there is no such instance
+	 */
+	public static <T> T getIfAny(Class<? super T> type) {
+		return _Casts.uncheckedCast(singletonMap.get(toKey(type)));
+	}
+	
+	/**
+	 * Gets a singleton instance of {@code type} if there is any, 
+	 * otherwise returns the {@code fallback}'s result,
+	 * which could be null.
+	 * @param type non-null
+	 * @param fallback non-null
+	 * @return
+	 */
+	public static <T> T getOrElse(Class<? super T> type, Supplier<T> fallback) {
+		Objects.requireNonNull(fallback);
+		final T singleton = getIfAny(type);
+		if(singleton!=null) {
+			return singleton;
+		}
+		return fallback.get(); 
+	}
+	
+	/**
+	 * Gets a singleton instance of {@code type} if there is any, 
+	 * otherwise throws the {@code onNotFound}'s result,
+	 * which could be null.
+	 * @param type non-null
+	 * @param onNotFound non-null
+	 * @return
+	 * @throws Exception 
+	 */
+	public static <T, E extends Exception> T getOrThrow(
+			Class<? super T> type, 
+			Supplier<E> onNotFound) 
+			throws E {
+		Objects.requireNonNull(onNotFound);
+		final T singleton = getIfAny(type);
+		if(singleton!=null) {
+			return singleton;
+		}
+		throw onNotFound.get();
+	}
+	
+	/**
+	 * Removes any singleton references from the current context.
+	 */
+	public static void clear() {
+		singletonMap.clear();
+	}
+	
+	// -- DEFAULT CLASSLOADER
+	
+	private final static Supplier<ClassLoader> FALLBACK_CLASSLOADER = 
+			Thread.currentThread()::getContextClassLoader;
+	
+	/**
+	 * Will be set by the framework's bootstrapping mechanism if required.
+	 * @return the default class loader
+	 */
+	public static ClassLoader getDefaultClassLoader() {
+		return getOrElse(ClassLoader.class, FALLBACK_CLASSLOADER);
+	}
+
+	// -- HELPER
+	
+	private static String toKey(Class<?> type) {
+		return type.getName();
+	}
+
+	
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/context/_Contexts.java b/core/applib/src/main/java/org/apache/isis/applib/internal/context/_Contexts.java
deleted file mode 100644
index 72c75ed..0000000
--- a/core/applib/src/main/java/org/apache/isis/applib/internal/context/_Contexts.java
+++ /dev/null
@@ -1,72 +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.applib.internal.context;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * <h1>- internal use only -</h1>
- * <p>
- * Entry point for providing application scoped contexts.
- * </p>
- * <p>
- * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/> 
- * These may be changed or removed without notice!
- * </p>
- * @since 2.0.0
- */
-public final class _Contexts {
-
-	private _Contexts(){}
-	
-	public interface Context {
-		public ClassLoader getDefaultClassLoader();
-	}
-
-	private final static Map<Long, Context> contextMap = new HashMap<Long, _Contexts.Context>(); 	
-	
-	/**
-	 * TODO this is just a stub yet
-	 * @return the current context
-	 * 
-	 * @throws IllegalStateException if there is more than one context available, 
-	 * use {@link #get(long)} instead
-	 */
-	public static Context current() {
-		return new Context() {
-			@Override
-			public ClassLoader getDefaultClassLoader() {
-				return Thread.currentThread().getContextClassLoader();
-			}
-		};
-	}
-	
-	/**
-	 * Get a context by id
-	 * @param contextId
-	 * @return
-	 */
-	public static Context get(long contextId) {
-		return contextMap.get(contextId);
-	}
-	
-	
-}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/exceptions/_Exceptions.java b/core/applib/src/main/java/org/apache/isis/applib/internal/exceptions/_Exceptions.java
index b503853..f3af4b8 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/internal/exceptions/_Exceptions.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/internal/exceptions/_Exceptions.java
@@ -64,8 +64,8 @@ public final class _Exceptions {
 		return new IllegalArgumentException(String.format(format, _case));
 	}
 	
-	public static final RuntimeException unexpectedCodeReach() {
-		return new RuntimeException("internal error: code was reached, that is expected unreachable");
+	public static final IllegalStateException unexpectedCodeReach() {
+		return new IllegalStateException("internal error: code was reached, that is expected unreachable");
 	}	
 	
 	// -- STACKTRACE UTILITITIES
diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/reflection/_Reflect.java b/core/applib/src/main/java/org/apache/isis/applib/internal/reflection/_Reflect.java
index 01b6fd6..fcffa73 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/internal/reflection/_Reflect.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/internal/reflection/_Reflect.java
@@ -23,7 +23,7 @@ import java.lang.annotation.Annotation;
 import java.util.List;
 import java.util.Set;
 
-import org.apache.isis.applib.internal.context._Contexts;
+import org.apache.isis.applib.internal.context._Context;
 import org.reflections.scanners.SubTypesScanner;
 import org.reflections.util.ClasspathHelper;
 
@@ -62,7 +62,7 @@ public final class _Reflect {
 	public static Discovery discoverFullscan(String packageNamePrefix) {
 		_Reflect_Manifest.prepareDiscovery();
 		return _Reflect_Discovery.of(
-				ClasspathHelper.forClassLoader(_Contexts.current().getDefaultClassLoader()),
+				ClasspathHelper.forClassLoader(_Context.getDefaultClassLoader()),
 				ClasspathHelper.forClass(Object.class),
 				ClasspathHelper.forPackage(packageNamePrefix),
 				new SubTypesScanner(false)
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/headless/IsisSystem.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/headless/IsisSystem.java
index b57e97b..f6c8142 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/headless/IsisSystem.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/headless/IsisSystem.java
@@ -245,7 +245,7 @@ public class IsisSystem {
 
                 // for subsequent tests; the attempt to bootstrap the framework will leave
                 // the IsisContext singleton as set.
-                IsisContext.testReset();
+                IsisContext.clear();
 
                 final Set<String> validationErrors = ex.getValidationErrors();
                 final StringBuilder buf = new StringBuilder();
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
index dd63f0f..ee1cc1c 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/IsisContext.java
@@ -19,80 +19,64 @@
 
 package org.apache.isis.core.runtime.system.context;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.applib.internal.context._Context;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelInvalidException;
-import org.apache.isis.core.runtime.system.session.IsisSessionFactoryBuilder;
-import org.apache.isis.core.runtime.system.session.IsisSession;
 import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
 
 /**
- * Simply a static field holding the {@link IsisSessionFactory} singleton, and conveneince methods to obtain the
- * current {@link IsisSession}, along with application-scoped components and also any transaction-scoped components.
+ * Provides static access to current context's singletons 
+ * {@link MetaModelInvalidException} and {@link IsisSessionFactory}.  
  */
-public final class IsisContext {
-
-    private static final Logger LOG = LoggerFactory.getLogger(IsisContext.class);
-
-    private IsisContext(){
-        throw new IllegalStateException("Never instantiated");
-    }
-
-    //region > metaModelInvalidExceptionIfAny (static)
-    /**
-     * Populated only if the metamodel was found to be invalid
-     */
-    private static MetaModelInvalidException metamodelInvalidException;
-
-    public static MetaModelInvalidException getMetaModelInvalidExceptionIfAny() {
-        return IsisContext.metamodelInvalidException;
-    }
-    public static void setMetaModelInvalidException(final MetaModelInvalidException metaModelInvalid) {
-        IsisContext.metamodelInvalidException = metaModelInvalid;
-    }
-    //endregion
-
-    //region > sessionFactory (static)
-
-    private static IsisSessionFactory sessionFactory;
-
-    public static IsisSessionFactory getSessionFactory() {
-        return sessionFactory;
-    }
-
-
+public interface IsisContext {
+
+	/**
+	 * Populated only if the meta-model was found to be invalid.
+	 * @return null, if there is none
+	 */
+	public static MetaModelInvalidException getMetaModelInvalidExceptionIfAny() {
+		return _Context.getIfAny(MetaModelInvalidException.class);
+	}
+
+	/**
+	 * 
+	 * @return Isis's session factory
+	 */
+	// Implementation Note: Populated only by {@link IsisSessionFactoryBuilder}.
+	public static IsisSessionFactory getSessionFactory() {
+		return _Context.getOrThrow(
+				IsisSessionFactory.class, 
+				()->new IllegalStateException(
+						"internal error: should have been populated by IsisSessionFactoryBuilder") );
+	}
+	
+	/**
+	 * 
+	 * @return Isis's default class loader
+	 */
+	public static ClassLoader getClassLoader() {
+		return _Context.getDefaultClassLoader();
+	}
+	
+	// -- LIFE-CYCLING
+    
     /**
-     * Intended to be called only by {@link IsisSessionFactoryBuilder}.
+     * Destroys this context and clears any state associated with it. 
+     * It marks the end of IsisContext's life-cycle. Subsequent calls have no effect. 
      */
-    public static void setSessionFactory(final IsisSessionFactory sessionFactory) {
-        if (IsisContext.sessionFactory != null) {
-            throw new IsisException("SessionFactory already set up");
-        }
-        IsisContext.sessionFactory = sessionFactory;
+    public static void clear() {
+    	_Context.clear();
     }
     
+    // -- DEPRECATIONS
+    
     /**
      * Resets
-     * @deprecated replaced by {@link #destroy()}
+     * @deprecated replaced by {@link #clear()}
      * 
      */
     @Deprecated
     public static void testReset() {
-    	destroy();
+    	clear();
     }
-    
-    /**
-     * Destroys this context and clears any state associated with it. 
-     * It marks the end of IsisContext's lifecycle. Subsequent calls have no effect. 
-     */
-    public static void destroy() {
-        sessionFactory = null;
-        metamodelInvalidException = null;
-    }
-
-    //endregion
-
 
 }
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryBuilder.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryBuilder.java
index 1ddcaf7..bb08a05 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryBuilder.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryBuilder.java
@@ -30,6 +30,7 @@ import org.apache.isis.applib.AppManifest;
 import org.apache.isis.applib.clock.Clock;
 import org.apache.isis.applib.fixtures.FixtureClock;
 import org.apache.isis.applib.fixturescripts.FixtureScripts;
+import org.apache.isis.applib.internal.context._Context;
 import org.apache.isis.applib.services.fixturespec.FixtureScriptsDefault;
 import org.apache.isis.core.commons.config.IsisConfigurationDefault;
 import org.apache.isis.core.commons.lang.ListExtensions;
@@ -173,12 +174,9 @@ public class IsisSessionFactoryBuilder {
             // finally, wire up components and components into services...
             servicesInjector.autowire();
 
-
             // ... and make IsisSessionFactory available via the IsisContext static for those places where we cannot
             // yet inject.
-            IsisContext.setSessionFactory(isisSessionFactory);
-
-
+            _Context.putSingleton(IsisSessionFactory.class, isisSessionFactory);
 
             // time to initialize...
             specificationLoader.init();
@@ -221,7 +219,7 @@ public class IsisSessionFactoryBuilder {
                                 if(LOG.isDebugEnabled()) {
                                     LOG.debug("Meta model invalid", ex);
                                 }
-                                IsisContext.setMetaModelInvalidException(ex);
+                                _Context.putSingleton(MetaModelInvalidException.class, ex);
                             }
 
                         }

-- 
To stop receiving notification emails like this one, please contact
ahuber@apache.org.