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/02/23 09:53:39 UTC
[isis] 02/04: ISIS-1871 ISIS-1756 ISIS-1775 proper life-cycling +
context-path support
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 <ah...@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
ahuber@apache.org.