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 6e06e73c81b76fdb6db2a6850c74996d2def6e6b
Author: Andi Huber <ahu...@apache.org>
AuthorDate: Fri Feb 23 10:40:31 2018 +0100

    ISIS-1871 ISIS-1756 ISIS-1775 proper life-cycling + context-path support
    
    this works for DN 4 or 5 >= 5.1.5
---
 .../services/swagger/SwaggerServiceDefault.java    | 15 +++-
 .../isis/core/webapp/WebAppContextSupport.java     | 50 +++++++++++
 .../core/runtime/system/context/IsisContext.java   | 18 +++-
 .../DataNucleusApplicationComponents.java          | 21 ++++-
 .../persistence/PersistenceSessionFactory.java     | 31 ++-----
 .../datanucleus/DataNucleusLifeCycleHelper.java    | 57 +++++++++++++
 .../wicket/viewer/IsisWicketApplication.java       | 99 ++++++++++++----------
 7 files changed, 215 insertions(+), 76 deletions(-)

diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/SwaggerServiceDefault.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/SwaggerServiceDefault.java
index 968a93c..192b5f6 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/SwaggerServiceDefault.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/swagger/SwaggerServiceDefault.java
@@ -22,15 +22,15 @@ import java.util.Map;
 
 import javax.annotation.PostConstruct;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.swagger.SwaggerService;
 import 
org.apache.isis.core.metamodel.services.swagger.internal.SwaggerSpecGenerator;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.webapp.WebAppContextSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 @DomainService(
         nature = NatureOfService.DOMAIN,
@@ -48,7 +48,14 @@ public class SwaggerServiceDefault implements SwaggerService 
{
 
     @PostConstruct
     public void init(final Map<String,String> properties) {
-        this.basePath = getPropertyElse(properties, KEY_RESTFUL_BASE_PATH, 
KEY_RESTFUL_BASE_PATH_DEFAULT);
+       
+       final String webappContextPath = 
+                       getPropertyElse(properties, 
WebAppContextSupport.WEB_APP_CONTEXT_PATH, "/");
+       
+       final String basePath = 
+                       getPropertyElse(properties, KEY_RESTFUL_BASE_PATH, 
KEY_RESTFUL_BASE_PATH_DEFAULT);
+       
+       this.basePath = 
WebAppContextSupport.prependContextPathIfPresent(webappContextPath, basePath);
     }
 
     static String getPropertyElse(final Map<String, String> properties, final 
String key, final String dflt) {
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/webapp/WebAppContextSupport.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/webapp/WebAppContextSupport.java
new file mode 100644
index 0000000..10aa314
--- /dev/null
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/webapp/WebAppContextSupport.java
@@ -0,0 +1,50 @@
+/*
+ *  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.core.webapp;
+
+import javax.servlet.ServletContext;
+
+import com.google.common.base.Strings;
+
+public class WebAppContextSupport {
+
+    /**
+     * Property name given to the context path of the web application as 
returned by 
+     * {@link ServletContext#getContextPath()}.
+     */
+       public static final String WEB_APP_CONTEXT_PATH = 
"application.webapp.context-path";
+       
+       
+       public static String prependContextPathIfPresent(String contextPath, 
String path) {
+               if(Strings.isNullOrEmpty(contextPath) || 
contextPath.equals("/"))
+                       return path;
+               
+               if(!contextPath.startsWith("/"))
+                       throw new IllegalArgumentException(
+                                       "contextPath must start with a slash 
'/' character, got '"+contextPath+"'");
+
+               if(!path.startsWith("/"))
+                       throw new IllegalArgumentException(
+                                       "path must start with a slash '/' 
character, got '"+path+"'");
+               
+               return contextPath + path;
+       }
+       
+}
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 ee1cc1c..9763ff5 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
@@ -48,7 +48,7 @@ public interface IsisContext {
                                ()->new IllegalStateException(
                                                "internal error: should have 
been populated by IsisSessionFactoryBuilder") );
        }
-       
+
        /**
         * 
         * @return Isis's default class loader
@@ -65,6 +65,7 @@ public interface IsisContext {
      */
     public static void clear() {
        _Context.clear();
+       resetLogging();
     }
     
     // -- DEPRECATIONS
@@ -79,4 +80,19 @@ public interface IsisContext {
        clear();
     }
 
+       // -- HELPER
+
+       /**
+        * TODO [andi-huber] not sure if required, initial idea was to force 
log4j
+        * re-configuration on an undeploy/deploy cycle
+        */
+       static void resetLogging() {
+               try {
+                       org.apache.log4j.BasicConfigurator.resetConfiguration();
+                       
org.apache.log4j.Logger.getRootLogger().removeAllAppenders();
+               } catch (Exception e) {
+                       // at least we tried
+               }
+       }
+
 }
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/DataNucleusApplicationComponents.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/DataNucleusApplicationComponents.java
index 52ac35b..4e8d9fa 100644
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/DataNucleusApplicationComponents.java
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/DataNucleusApplicationComponents.java
@@ -41,7 +41,9 @@ import org.apache.isis.core.commons.config.IsisConfiguration;
 import org.apache.isis.core.commons.factory.InstanceUtil;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.runtime.system.context.IsisContext;
 import 
org.apache.isis.objectstore.jdo.datanucleus.CreateSchemaObjectFromClassMetadata;
+import org.apache.isis.objectstore.jdo.datanucleus.DataNucleusLifeCycleHelper;
 import org.apache.isis.objectstore.jdo.datanucleus.DataNucleusPropertiesAware;
 import 
org.apache.isis.objectstore.jdo.metamodel.facets.object.query.JdoNamedQuery;
 import 
org.apache.isis.objectstore.jdo.metamodel.facets.object.query.JdoQueryFacet;
@@ -109,6 +111,20 @@ public class DataNucleusApplicationComponents implements 
ApplicationScopedCompon
 
         namedQueryByName = catalogNamedQueries(persistableClassNameSet);
     }
+    
+    /** 
+     * Marks the end of DataNucleus' life-cycle. Purges any state associated 
with DN. 
+     * Subsequent calls have no effect.  
+     * 
+     * @since 2.0.0
+     */
+    public void shutdown() {
+       instance = null;
+       if(persistenceManagerFactory != null) {
+               DataNucleusLifeCycleHelper.cleanUp(persistenceManagerFactory);
+               persistenceManagerFactory = null;
+       }
+    }
 
     private static boolean isSchemaAwareStoreManager(Map<String,String> 
datanucleusProps) {
 
@@ -148,8 +164,9 @@ public class DataNucleusApplicationComponents implements 
ApplicationScopedCompon
                 
datanucleusProps.put(PropertyNames.PROPERTY_SCHEMA_AUTOCREATE_TABLES, "true"); 
// but have DN do everything else...
                 
datanucleusProps.put(PropertyNames.PROPERTY_SCHEMA_AUTOCREATE_COLUMNS, "true");
                 
datanucleusProps.put(PropertyNames.PROPERTY_SCHEMA_AUTOCREATE_CONSTRAINTS, 
"true");
-
-                persistenceManagerFactory = 
JDOHelper.getPersistenceManagerFactory(datanucleusProps);
+                
+                persistenceManagerFactory = JDOHelper
+                               .getPersistenceManagerFactory(datanucleusProps, 
IsisContext.getClassLoader() );
                 createSchema(persistenceManagerFactory, 
persistableClassNameSet, datanucleusProps);
 
             } else {
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactory.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactory.java
index 8a32edb..ad72168 100644
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactory.java
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactory.java
@@ -53,18 +53,12 @@ public class PersistenceSessionFactory implements 
ApplicationScopedComponent, Fi
 
     private static final Logger LOG = 
LoggerFactory.getLogger(PersistenceSessionFactory.class);
 
-    //region > constructor
-
     private final IsisConfigurationDefault configuration;
 
     public PersistenceSessionFactory(final IsisConfigurationDefault 
isisConfiguration) {
         this.configuration = isisConfiguration;
     }
 
-    //endregion
-
-    //region > init, createDataNucleusApplicationComponents
-
     public static final String JDO_OBJECTSTORE_CONFIG_PREFIX = 
"isis.persistor.datanucleus";  // specific to the JDO objectstore
     public static final String DATANUCLEUS_CONFIG_PREFIX = 
"isis.persistor.datanucleus.impl"; // reserved for datanucleus' own config props
 
@@ -93,7 +87,7 @@ public class PersistenceSessionFactory implements 
ApplicationScopedComponent, Fi
             final Map<String, String> datanucleusProps = 
dataNucleusConfig.asMap();
             addDataNucleusPropertiesIfRequired(datanucleusProps);
 
-            final RegisterEntities registerEntities = new 
RegisterEntities(configuration.asMap(), specificationLoader);
+            final RegisterEntities registerEntities = new 
RegisterEntities(specificationLoader);
             final Set<String> classesToBePersisted = 
registerEntities.getEntityTypes();
 
             applicationComponents = new 
DataNucleusApplicationComponents(jdoObjectstoreConfig, specificationLoader,
@@ -159,19 +153,18 @@ public class PersistenceSessionFactory implements 
ApplicationScopedComponent, Fi
             props.put(key, value);
         }
     }
-    //endregion
 
-    //region > shutdown
     @Programmatic
     public final void shutdown() {
-        // no-op
+        if(!isInitialized()) {
+            return;
+        }
+       if(applicationComponents != null) {
+               applicationComponents.shutdown();
+            applicationComponents = null;
+       }
     }
 
-    //endregion
-
-
-    //region > createPersistenceSession
-
     /**
      * Called by {@link 
org.apache.isis.core.runtime.system.session.IsisSessionFactory#openSession(AuthenticationSession)}.
      */
@@ -190,12 +183,6 @@ public class PersistenceSessionFactory implements 
ApplicationScopedComponent, Fi
                 fixturesInstalledFlag);
     }
 
-
-
-    //endregion
-
-    //region > FixturesInstalledFlag impl
-
     private Boolean fixturesInstalled;
 
     @Programmatic
@@ -210,7 +197,5 @@ public class PersistenceSessionFactory implements 
ApplicationScopedComponent, Fi
         this.fixturesInstalled = fixturesInstalled;
     }
 
-    //endregion
-
 
 }
diff --git 
a/core/runtime/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/DataNucleusLifeCycleHelper.java
 
b/core/runtime/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/DataNucleusLifeCycleHelper.java
new file mode 100644
index 0000000..bc19b81
--- /dev/null
+++ 
b/core/runtime/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/DataNucleusLifeCycleHelper.java
@@ -0,0 +1,57 @@
+/*
+ *  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.objectstore.jdo.datanucleus;
+
+import javax.jdo.PersistenceManagerFactory;
+
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.datanucleus.enhancer.EnhancementHelper;
+
+/**
+ * 
+ * Purges any state associated with DataNucleus.
+ * <br/><br/>
+ * (requires datanucleus-core 4 or 5 >= 5.1.5)
+ * 
+ * @since 2.0.0
+ *
+ */
+public class DataNucleusLifeCycleHelper {
+       
+    //private static final Logger LOG = 
LoggerFactory.getLogger(DataNucleusLifeCycleHelper.class);
+
+       public static void cleanUp(PersistenceManagerFactory 
persistenceManagerFactory) {
+               
+               try {
+                       
+                       final ClassLoader cl = IsisContext.getClassLoader();
+                       
+                       persistenceManagerFactory.close();
+                       
+                       // for info, on why we do this see
+                       // 
https://github.com/datanucleus/datanucleus-core/issues/272
+                       EnhancementHelper.getInstance().unregisterClasses(cl);
+                       
+               } catch (Exception e) {
+                       // ignore, since it only affects re-deploy-ability, 
which is nice to have but not critical
+               }
+
+       }
+
+}
diff --git 
a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
 
b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
index 03426ac..ecf8d4c 100644
--- 
a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
+++ 
b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
@@ -30,52 +30,7 @@ import java.util.UUID;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Future;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import com.google.common.io.Resources;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Module;
-
-import org.apache.wicket.Application;
-import org.apache.wicket.Component;
-import org.apache.wicket.ConverterLocator;
-import org.apache.wicket.IConverterLocator;
-import org.apache.wicket.Page;
-import org.apache.wicket.RuntimeConfigurationType;
-import org.apache.wicket.SharedResources;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.authentication.IAuthenticationStrategy;
-import org.apache.wicket.authentication.strategy.DefaultAuthenticationStrategy;
-import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;
-import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
-import org.apache.wicket.core.request.mapper.MountedMapper;
-import org.apache.wicket.devutils.debugbar.DebugBar;
-import org.apache.wicket.devutils.debugbar.InspectorDebugPanel;
-import org.apache.wicket.devutils.debugbar.PageSizeDebugPanel;
-import org.apache.wicket.devutils.debugbar.SessionSizeDebugPanel;
-import org.apache.wicket.devutils.debugbar.VersionDebugContributor;
-import org.apache.wicket.devutils.diskstore.DebugDiskDataStore;
-import org.apache.wicket.guice.GuiceComponentInjector;
-import org.apache.wicket.markup.head.IHeaderResponse;
-import 
org.apache.wicket.markup.head.filter.JavaScriptFilteredIntoFooterHeaderResponse;
-import org.apache.wicket.markup.html.IHeaderContributor;
-import org.apache.wicket.markup.html.IHeaderResponseDecorator;
-import org.apache.wicket.markup.html.WebPage;
-import org.apache.wicket.request.cycle.IRequestCycleListener;
-import org.apache.wicket.request.cycle.PageRequestHandlerTracker;
-import org.apache.wicket.request.cycle.RequestCycleListenerCollection;
-import org.apache.wicket.request.resource.CssResourceReference;
-import org.apache.wicket.settings.DebugSettings;
-import org.apache.wicket.settings.RequestCycleSettings;
-import org.apache.wicket.util.IContextProvider;
-import org.apache.wicket.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.wicketstuff.select2.ApplicationSettings;
-
+import org.apache.isis.applib.internal.context._Context;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.config.IsisConfiguration;
 import org.apache.isis.core.commons.config.IsisConfigurationDefault;
@@ -91,6 +46,7 @@ import 
org.apache.isis.core.runtime.system.session.IsisSessionFactory;
 import org.apache.isis.core.runtime.threadpool.ThreadPoolSupport;
 import org.apache.isis.core.webapp.IsisWebAppBootstrapper;
 import org.apache.isis.core.webapp.WebAppConstants;
+import org.apache.isis.core.webapp.WebAppContextSupport;
 import org.apache.isis.schema.utils.ChangesDtoUtils;
 import org.apache.isis.schema.utils.CommandDtoUtils;
 import org.apache.isis.schema.utils.InteractionDtoUtils;
@@ -119,6 +75,51 @@ import 
org.apache.isis.viewer.wicket.viewer.integration.wicket.ConverterForObjec
 import 
org.apache.isis.viewer.wicket.viewer.integration.wicket.ConverterForObjectAdapterMemento;
 import 
org.apache.isis.viewer.wicket.viewer.integration.wicket.WebRequestCycleForIsis;
 import org.apache.isis.viewer.wicket.viewer.settings.IsisResourceSettings;
+import org.apache.wicket.Application;
+import org.apache.wicket.Component;
+import org.apache.wicket.ConverterLocator;
+import org.apache.wicket.IConverterLocator;
+import org.apache.wicket.Page;
+import org.apache.wicket.RuntimeConfigurationType;
+import org.apache.wicket.SharedResources;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.authentication.IAuthenticationStrategy;
+import org.apache.wicket.authentication.strategy.DefaultAuthenticationStrategy;
+import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;
+import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
+import org.apache.wicket.core.request.mapper.MountedMapper;
+import org.apache.wicket.devutils.debugbar.DebugBar;
+import org.apache.wicket.devutils.debugbar.InspectorDebugPanel;
+import org.apache.wicket.devutils.debugbar.PageSizeDebugPanel;
+import org.apache.wicket.devutils.debugbar.SessionSizeDebugPanel;
+import org.apache.wicket.devutils.debugbar.VersionDebugContributor;
+import org.apache.wicket.devutils.diskstore.DebugDiskDataStore;
+import org.apache.wicket.guice.GuiceComponentInjector;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import 
org.apache.wicket.markup.head.filter.JavaScriptFilteredIntoFooterHeaderResponse;
+import org.apache.wicket.markup.html.IHeaderContributor;
+import org.apache.wicket.markup.html.IHeaderResponseDecorator;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.request.cycle.IRequestCycleListener;
+import org.apache.wicket.request.cycle.PageRequestHandlerTracker;
+import org.apache.wicket.request.cycle.RequestCycleListenerCollection;
+import org.apache.wicket.request.resource.CssResourceReference;
+import org.apache.wicket.settings.DebugSettings;
+import org.apache.wicket.settings.RequestCycleSettings;
+import org.apache.wicket.util.IContextProvider;
+import org.apache.wicket.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.wicketstuff.select2.ApplicationSettings;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.io.Resources;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
 
 import de.agilecoders.wicket.core.Bootstrap;
 import 
de.agilecoders.wicket.core.markup.html.bootstrap.behavior.BootstrapBaseBehavior;
@@ -333,6 +334,8 @@ public class IsisWicketApplication
         List<Future<Object>> futures = null;
         try {
             super.init();
+            
+            _Context.putSingleton(ClassLoader.class, 
this.getClass().getClassLoader());
 
             futures = startBackgroundInitializationThreads();
 
@@ -346,6 +349,9 @@ public class IsisWicketApplication
 
             final IsisConfigurationBuilder isisConfigurationBuilder = 
obtainConfigBuilder();
             
isisConfigurationBuilder.addDefaultConfigurationResourcesAndPrimers();
+            
+            final String webappContextPath = 
getServletContext().getContextPath();
+            
isisConfigurationBuilder.add(WebAppContextSupport.WEB_APP_CONTEXT_PATH, 
webappContextPath);
 
             final IsisConfigurationDefault configuration = 
isisConfigurationBuilder.getConfiguration();
 
@@ -859,6 +865,7 @@ public class IsisWicketApplication
             }
             
getServletContext().setAttribute(WebAppConstants.ISIS_SESSION_FACTORY, null);
             super.onDestroy();
+            IsisContext.clear();
         } catch(final RuntimeException ex) {
             // symmetry with #init()
             LOG.error("Failed to destroy", ex);

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

Reply via email to