forked from ehrbase/ehrbase
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature/add plugin system (ehrbase#772)
* add plugin system see CDR-276 * switch to return uuid instead of full composition logic see CDR-276 * retro error in aspect see CDR-276 * cleanup code see CDR-276 * cleanup code and add javadoc see CDR-276 * add javadoc more javadoc see CDR-276 * run test with test_plugins see CDR-276 * fix ci see CDR-276 * run test with test_plugins see CDR-276 * fix ci see CDR-276 * add test plugins with error handling see CDR-276 * edit changelog see CDR-276 * check for duplicate plugin uri see CDR-276 * fix review see CDR-276 * fix review see CDR-276
- Loading branch information
1 parent
ce77006
commit 31a08e1
Showing
23 changed files
with
859 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -217,3 +217,4 @@ vulnerability_analysis.json | |
# Docker | ||
.pgdata | ||
application/.pgdata | ||
/plugin_dir/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
application/src/main/java/org/ehrbase/application/config/plugin/EhrBasePluginManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* | ||
* Copyright (c) 2022. vitasystems GmbH and Hannover Medical School. | ||
* | ||
* Licensed 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 | ||
* | ||
* https://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.ehrbase.application.config.plugin; | ||
|
||
|
||
import org.pf4j.spring.ExtensionsInjector; | ||
import org.pf4j.spring.SpringPluginManager; | ||
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory; | ||
|
||
/** | ||
* @author Stefan Spiska | ||
*/ | ||
public class EhrBasePluginManager extends SpringPluginManager { | ||
|
||
public EhrBasePluginManager(PluginManagerProperties properties) { | ||
super(properties.getPluginDir()); | ||
} | ||
|
||
private boolean init = false; | ||
|
||
@Override | ||
public void init() { | ||
// Plugins will be initialised in initPlugins | ||
} | ||
|
||
public void initPlugins() { | ||
|
||
|
||
if (!init) { | ||
|
||
startPlugins(); | ||
|
||
AbstractAutowireCapableBeanFactory beanFactory = | ||
(AbstractAutowireCapableBeanFactory) | ||
getApplicationContext().getAutowireCapableBeanFactory(); | ||
ExtensionsInjector extensionsInjector = new ExtensionsInjector(this, beanFactory); | ||
extensionsInjector.injectExtensions(); | ||
init = true; | ||
} | ||
} | ||
} |
141 changes: 141 additions & 0 deletions
141
application/src/main/java/org/ehrbase/application/config/plugin/PluginConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
/* | ||
* Copyright (c) 2022. vitasystems GmbH and Hannover Medical School. | ||
* | ||
* Licensed 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 | ||
* | ||
* https://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.ehrbase.application.config.plugin; | ||
|
||
import static org.ehrbase.plugin.PluginHelper.PLUGIN_MANAGER_PREFIX; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import org.ehrbase.api.exception.InternalServerException; | ||
import org.ehrbase.plugin.EhrBasePlugin; | ||
import org.pf4j.PluginWrapper; | ||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; | ||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.boot.context.properties.bind.Binder; | ||
import org.springframework.boot.web.servlet.ServletRegistrationBean; | ||
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent; | ||
import org.springframework.context.ApplicationListener; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.core.env.Environment; | ||
import org.springframework.web.servlet.DispatcherServlet; | ||
import org.springframework.web.util.UriComponentsBuilder; | ||
|
||
/** | ||
* @author Stefan Spiska | ||
*/ | ||
@Configuration | ||
@EnableConfigurationProperties(PluginManagerProperties.class) | ||
@ConditionalOnProperty(prefix = PLUGIN_MANAGER_PREFIX, name = "enable", havingValue = "true") | ||
public class PluginConfig { | ||
|
||
@Bean | ||
public EhrBasePluginManager pluginManager(Environment environment) { | ||
|
||
return new EhrBasePluginManager(getPluginManagerProperties(environment)); | ||
} | ||
// since this is used in a BeanFactoryPostProcessor the PluginManagerProperties must be bound | ||
// manually. | ||
private PluginManagerProperties getPluginManagerProperties(Environment environment) { | ||
return Binder.get(environment).bind(PLUGIN_MANAGER_PREFIX, PluginManagerProperties.class).get(); | ||
} | ||
|
||
/** Register the {@link DispatcherServlet} for all {@link EhrBasePlugin} */ | ||
@Bean | ||
public BeanFactoryPostProcessor beanFactoryPostProcessor( | ||
EhrBasePluginManager pluginManager, Environment environment) { | ||
|
||
PluginManagerProperties pluginManagerProperties = getPluginManagerProperties(environment); | ||
|
||
Map<String, String> registeredUrl = new HashMap<>(); | ||
|
||
return beanFactory -> { | ||
pluginManager.loadPlugins(); | ||
|
||
pluginManager.getPlugins().stream() | ||
.map(PluginWrapper::getPlugin) | ||
.filter(p -> EhrBasePlugin.class.isAssignableFrom(p.getClass())) | ||
.map(EhrBasePlugin.class::cast) | ||
.forEach(p -> register(beanFactory, pluginManagerProperties, registeredUrl, p)); | ||
}; | ||
} | ||
|
||
/** | ||
* Register the {@link DispatcherServlet} for a {@link EhrBasePlugin} | ||
* | ||
* @param beanFactory | ||
* @param pluginManagerProperties | ||
* @param registeredUrl | ||
* @param p | ||
*/ | ||
private void register( | ||
ConfigurableListableBeanFactory beanFactory, | ||
PluginManagerProperties pluginManagerProperties, | ||
Map<String, String> registeredUrl, | ||
EhrBasePlugin p) { | ||
|
||
String pluginId = p.getWrapper().getPluginId(); | ||
|
||
final String uri = | ||
UriComponentsBuilder.newInstance() | ||
.path(pluginManagerProperties.getPluginContextPath()) | ||
.path(p.getContextPath()) | ||
.path("/*") | ||
.build() | ||
.getPath(); | ||
|
||
// check for duplicate plugin uri | ||
registeredUrl.entrySet().stream() | ||
.filter(e -> e.getValue().equals(uri)) | ||
.findAny() | ||
.ifPresent( | ||
e -> { | ||
throw new InternalServerException( | ||
String.format( | ||
"uri %s for plugin %s already registered by plugin %s", | ||
uri, pluginId, e.getKey())); | ||
}); | ||
|
||
registeredUrl.put(pluginId, uri); | ||
|
||
ServletRegistrationBean<DispatcherServlet> bean = | ||
new ServletRegistrationBean<>(p.getDispatcherServlet(), uri); | ||
|
||
bean.setLoadOnStartup(1); | ||
bean.setOrder(1); | ||
bean.setName(pluginId); | ||
beanFactory.initializeBean(bean, pluginId); | ||
beanFactory.autowireBean(bean); | ||
beanFactory.registerSingleton(pluginId, bean); | ||
} | ||
|
||
/** | ||
* Create a Listener for the {@link ServletWebServerInitializedEvent } to initialise the {@link | ||
* org.pf4j.ExtensionPoint} after all {@link DispatcherServlet} have been initialised. | ||
* | ||
* @param pluginManager | ||
* @return | ||
*/ | ||
@Bean | ||
ApplicationListener<ServletWebServerInitializedEvent> | ||
servletWebServerInitializedEventApplicationListener(EhrBasePluginManager pluginManager) { | ||
|
||
return event -> pluginManager.initPlugins(); | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
application/src/main/java/org/ehrbase/application/config/plugin/PluginManagerProperties.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright (c) 2022. vitasystems GmbH and Hannover Medical School. | ||
* | ||
* Licensed 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 | ||
* | ||
* https://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.ehrbase.application.config.plugin; | ||
|
||
import static org.ehrbase.plugin.PluginHelper.PLUGIN_MANAGER_PREFIX; | ||
|
||
import java.nio.file.Path; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
|
||
/** | ||
* @author Stefan Spiska | ||
* <p>{@link ConfigurationProperties} for {@link EhrBasePluginManager}. | ||
*/ | ||
@ConfigurationProperties(prefix = PLUGIN_MANAGER_PREFIX) | ||
public class PluginManagerProperties { | ||
|
||
private Path pluginDir; | ||
private boolean enable; | ||
private String pluginContextPath; | ||
|
||
public void setPluginDir(Path pluginDir) { | ||
this.pluginDir = pluginDir; | ||
} | ||
|
||
public boolean isEnable() { | ||
return enable; | ||
} | ||
|
||
public void setEnable(boolean enable) { | ||
this.enable = enable; | ||
} | ||
|
||
public Path getPluginDir() { | ||
return pluginDir; | ||
} | ||
|
||
public void setPluginDir(String pluginDir) { | ||
this.pluginDir = Path.of(pluginDir); | ||
} | ||
|
||
public String getPluginContextPath() { | ||
return pluginContextPath; | ||
} | ||
|
||
public void setPluginContextPath(String pluginContextPath) { | ||
this.pluginContextPath = pluginContextPath; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.