keycloak-aplcache
Changes
distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml 1(+1 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml 1(+1 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml 1(+1 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-server-subsystem/main/module.xml 1(+1 -0)
examples/providers/user-storage-jpa/pom.xml 45(+18 -27)
examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProvider.java 22(+16 -6)
examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProviderFactory.java 59(+26 -33)
examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserAdapter.java 3(+1 -2)
examples/providers/user-storage-jpa/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory 2(+1 -1)
pom.xml 6(+6 -0)
services/pom.xml 4(+4 -0)
testsuite/integration/pom.xml 4(+4 -0)
wildfly/server-subsystem/pom.xml 10(+10 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDependencyProcessor.java 112(+112 -0)
wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDeploymentProcessor.java 84(+84 -0)
Details
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
index d52c9a4..e5dc8ec 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
@@ -20,6 +20,7 @@
<config>
<subsystems>
<subsystem>logging.xml</subsystem>
+ <subsystem>deployment-scanner.xml</subsystem>
<subsystem>bean-validation.xml</subsystem>
<subsystem supplement="default">keycloak-datasources.xml</subsystem>
<subsystem>ee.xml</subsystem>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
index b96cb8a..d9345a1 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
@@ -20,6 +20,7 @@
<config>
<subsystems>
<subsystem>logging.xml</subsystem>
+ <subsystem>deployment-scanner.xml</subsystem>
<subsystem>bean-validation.xml</subsystem>
<subsystem supplement="default">keycloak-datasources.xml</subsystem>
<subsystem>ee.xml</subsystem>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
index 42042e6..e769a7b 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
@@ -68,5 +68,6 @@
<module name="javax.activation.api"/>
<module name="org.apache.httpcomponents"/>
<module name="org.twitter4j"/>
+ <module name="javax.transaction.api"/>
</dependencies>
</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-server-subsystem/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-server-subsystem/main/module.xml
index 62b2616..9f44e59 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-server-subsystem/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-server-subsystem/main/module.xml
@@ -40,6 +40,7 @@
<module name="org.jboss.as.web-common" optional="true"/>
<module name="org.jboss.as.web" optional="true"/>
<module name="org.jboss.as.version" optional="true"/>
+ <module name="org.keycloak.keycloak-services"/>
<module name="org.keycloak.keycloak-wildfly-adapter" optional="true"/>
<module name="org.jboss.metadata"/>
</dependencies>
diff --git a/distribution/server-dist/assembly.xml b/distribution/server-dist/assembly.xml
index c8dd06c..9e24567 100755
--- a/distribution/server-dist/assembly.xml
+++ b/distribution/server-dist/assembly.xml
@@ -44,8 +44,6 @@
<exclude>welcome-content/**</exclude>
<exclude>appclient</exclude>
<exclude>appclient/**</exclude>
- <exclude>standalone/deployments</exclude>
- <exclude>standalone/deployments/*</exclude>
<exclude>copyright.txt</exclude>
<exclude>README.txt</exclude>
</excludes>
examples/providers/user-storage-jpa/pom.xml 45(+18 -27)
diff --git a/examples/providers/user-storage-jpa/pom.xml b/examples/providers/user-storage-jpa/pom.xml
index c1c38d2..75c3a6f 100755
--- a/examples/providers/user-storage-jpa/pom.xml
+++ b/examples/providers/user-storage-jpa/pom.xml
@@ -42,11 +42,6 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>org.keycloak</groupId>
- <artifactId>keycloak-model-jpa</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
@@ -61,6 +56,12 @@
<artifactId>hibernate-entitymanager</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.ejb</groupId>
+ <artifactId>jboss-ejb-api_3.2_spec</artifactId>
+ <version>1.0.0.Final</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<build>
@@ -75,28 +76,18 @@
</configuration>
</plugin>
<plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>assemble</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- <configuration>
- <descriptors>
- <descriptor>assembly.xml</descriptor>
- </descriptors>
- <recompressZippedFiles>true</recompressZippedFiles>
- <finalName>modules</finalName>
- <appendAssemblyId>false</appendAssemblyId>
- <outputDirectory>${project.build.directory}</outputDirectory>
- <workDirectory>${project.build.directory}/assembly/work</workDirectory>
- <tarLongFileMode>gnu</tarLongFileMode>
- </configuration>
- </execution>
- </executions>
+ <groupId>org.jboss.as.plugins</groupId>
+ <artifactId>jboss-as-maven-plugin</artifactId>
+ <configuration>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.wildfly.plugins</groupId>
+ <artifactId>wildfly-maven-plugin</artifactId>
+ <configuration>
+ <skip>false</skip>
+ </configuration>
</plugin>
</plugins>
</build>
diff --git a/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserAdapter.java b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserAdapter.java
index f4ff5a7..6276f7f 100644
--- a/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserAdapter.java
+++ b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserAdapter.java
@@ -22,7 +22,6 @@ import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
@@ -35,7 +34,7 @@ import java.util.Map;
* @version $Revision: 1 $
*/
public class UserAdapter extends AbstractUserAdapterFederatedStorage {
- private static final Logger logger = Logger.getLogger(ExampleUserStorageProvider.class);
+ private static final Logger logger = Logger.getLogger(EjbExampleUserStorageProvider.class);
protected UserEntity entity;
protected String keycloakId;
diff --git a/examples/providers/user-storage-jpa/src/main/resources/META-INF/persistence.xml b/examples/providers/user-storage-jpa/src/main/resources/META-INF/persistence.xml
index d082c23..9894af4 100644
--- a/examples/providers/user-storage-jpa/src/main/resources/META-INF/persistence.xml
+++ b/examples/providers/user-storage-jpa/src/main/resources/META-INF/persistence.xml
@@ -4,9 +4,8 @@
xsi:schemaLocation="
http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
- <persistence-unit name="user-storage-jpa-example" transaction-type="RESOURCE_LOCAL">
- <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
- <non-jta-data-source>java:jboss/datasources/ExampleDS</non-jta-data-source>
+ <persistence-unit name="user-storage-jpa-example">
+ <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
<class>org.keycloak.examples.storage.user.UserEntity</class>
diff --git a/examples/providers/user-storage-jpa/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory b/examples/providers/user-storage-jpa/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory
index 1634d11..8f92432 100644
--- a/examples/providers/user-storage-jpa/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory
+++ b/examples/providers/user-storage-jpa/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory
@@ -1 +1 @@
-org.keycloak.examples.storage.user.ExampleUserStorageProviderFactory
\ No newline at end of file
+org.keycloak.examples.storage.user.EjbExampleUserStorageProviderFactory
\ No newline at end of file
pom.xml 6(+6 -0)
diff --git a/pom.xml b/pom.xml
index 77d3678..c106063 100755
--- a/pom.xml
+++ b/pom.xml
@@ -63,6 +63,7 @@
<jboss.logging.tools.version>2.0.1.Final</jboss.logging.tools.version>
<jboss.logging.tools.wf8.version>1.2.0.Final</jboss.logging.tools.wf8.version>
<jboss-jaxrs-api_2.0_spec>1.0.0.Final</jboss-jaxrs-api_2.0_spec>
+ <jboss-transaction-api_1.2_spec>1.0.0.Final</jboss-transaction-api_1.2_spec>
<jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version>1.0.4.Final</jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version>
<log4j.version>1.2.16</log4j.version>
<resteasy.version>3.0.14.Final</resteasy.version>
@@ -228,6 +229,11 @@
<version>${javax.mail.version}</version>
</dependency>
<dependency>
+ <groupId>org.jboss.spec.javax.transaction</groupId>
+ <artifactId>jboss-transaction-api_1.2_spec</artifactId>
+ <version>${jboss-transaction-api_1.2_spec}</version>
+ </dependency>
+ <dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
<version>${jboss-jaxrs-api_2.0_spec}</version>
services/pom.xml 4(+4 -0)
diff --git a/services/pom.xml b/services/pom.xml
index 180c16b..3ae57e3 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -110,6 +110,10 @@
<artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
</dependency>
<dependency>
+ <groupId>org.jboss.spec.javax.transaction</groupId>
+ <artifactId>jboss-transaction-api_1.2_spec</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
</dependency>
diff --git a/services/src/main/java/org/keycloak/provider/ProviderManager.java b/services/src/main/java/org/keycloak/provider/ProviderManager.java
index e906df9..e5d9712 100644
--- a/services/src/main/java/org/keycloak/provider/ProviderManager.java
+++ b/services/src/main/java/org/keycloak/provider/ProviderManager.java
@@ -16,8 +16,10 @@
*/
package org.keycloak.provider;
+import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.services.ServicesLogger;
+import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedList;
@@ -33,7 +35,8 @@ public class ProviderManager {
private static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
private List<ProviderLoader> loaders = new LinkedList<ProviderLoader>();
- private Map<String, List<ProviderFactory>> cache = new HashMap<String, List<ProviderFactory>>();
+ private MultivaluedHashMap<Class<? extends Provider>, ProviderFactory> cache = new MultivaluedHashMap<>();
+
public ProviderManager(ClassLoader baseClassLoader, String... resources) {
List<ProviderLoaderFactory> factories = new LinkedList<ProviderLoaderFactory>();
@@ -65,6 +68,10 @@ public class ProviderManager {
}
}
+ public ProviderManager(ClassLoader baseClassLoader) {
+ loaders.add(new DefaultProviderLoader(baseClassLoader));
+ }
+
public synchronized List<Spi> loadSpis() {
// Use a map to prevent duplicates, since the loaders may have overlapping classpaths.
Map<String, Spi> spiMap = new HashMap<>();
@@ -80,9 +87,7 @@ public class ProviderManager {
}
public synchronized List<ProviderFactory> load(Spi spi) {
- List<ProviderFactory> factories = cache.get(spi.getName());
- if (factories == null) {
- factories = new LinkedList<ProviderFactory>();
+ if (!cache.containsKey(spi.getProviderClass())) {
IdentityHashMap factoryClasses = new IdentityHashMap();
for (ProviderLoader loader : loaders) {
List<ProviderFactory> f = loader.load(spi);
@@ -90,14 +95,26 @@ public class ProviderManager {
for (ProviderFactory pf: f) {
// make sure there are no duplicates
if (!factoryClasses.containsKey(pf.getClass())) {
- factories.add(pf);
+ cache.add(spi.getProviderClass(), pf);
factoryClasses.put(pf.getClass(), pf);
}
}
}
}
}
- return factories;
+ List<ProviderFactory> rtn = cache.get(spi.getProviderClass());
+ return rtn == null ? Collections.EMPTY_LIST : rtn;
+ }
+
+ /**
+ * returns a copy of internal factories.
+ *
+ * @return
+ */
+ public synchronized MultivaluedHashMap<Class<? extends Provider>, ProviderFactory> getLoadedFactories() {
+ MultivaluedHashMap<Class<? extends Provider>, ProviderFactory> copy = new MultivaluedHashMap<>();
+ copy.addAll(cache);
+ return copy;
}
public synchronized ProviderFactory load(Spi spi, String providerId) {
diff --git a/services/src/main/java/org/keycloak/provider/ProviderManagerDeployer.java b/services/src/main/java/org/keycloak/provider/ProviderManagerDeployer.java
new file mode 100644
index 0000000..e8ed910
--- /dev/null
+++ b/services/src/main/java/org/keycloak/provider/ProviderManagerDeployer.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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
+ *
+ * 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.keycloak.provider;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ProviderManagerDeployer {
+ void deploy(ProviderManager pm);
+ void undeploy(ProviderManager pm);
+}
diff --git a/services/src/main/java/org/keycloak/provider/ProviderManagerRegistry.java b/services/src/main/java/org/keycloak/provider/ProviderManagerRegistry.java
new file mode 100644
index 0000000..69cd92e
--- /dev/null
+++ b/services/src/main/java/org/keycloak/provider/ProviderManagerRegistry.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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
+ *
+ * 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.keycloak.provider;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ProviderManagerRegistry {
+ public static final ProviderManagerRegistry SINGLETON = new ProviderManagerRegistry();
+ protected List<ProviderManager> preBoot = Collections.synchronizedList(new LinkedList<>());
+ protected AtomicReference<ProviderManagerDeployer> deployerRef = new AtomicReference<>();
+
+ public void setDeployer(ProviderManagerDeployer deployer) {
+ this.deployerRef.set(deployer);
+ }
+
+ public void deploy(ProviderManager pm) {
+ ProviderManagerDeployer deployer = getDeployer();
+ if (deployer == null) {
+ preBoot.add(pm);
+ } else {
+ deployer.deploy(pm);
+ }
+
+ }
+
+ public void undeploy(ProviderManager pm) {
+ preBoot.remove(pm);
+ ProviderManagerDeployer deployer = getDeployer();
+ if (deployer != null) {
+ deployer.undeploy(pm);
+ }
+ }
+
+ public ProviderManagerDeployer getDeployer() {
+ return deployerRef.get();
+ }
+
+ public List<ProviderManager> getPreBoot() {
+ return preBoot;
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
index b56af8d..3b0a572 100755
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
@@ -17,6 +17,7 @@
package org.keycloak.services;
import org.keycloak.Config;
+import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.Provider;
@@ -24,9 +25,12 @@ import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.ProviderManager;
+import org.keycloak.provider.ProviderManagerDeployer;
+import org.keycloak.provider.ProviderManagerRegistry;
import org.keycloak.provider.Spi;
import org.keycloak.services.ServicesLogger;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@@ -36,14 +40,15 @@ import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
-public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
+public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, ProviderManagerDeployer {
private static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
private Set<Spi> spis = new HashSet<>();
- private Map<Class<? extends Provider>, String> provider = new HashMap<Class<? extends Provider>, String>();
- private Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoriesMap = new HashMap<Class<? extends Provider>, Map<String, ProviderFactory>>();
- protected CopyOnWriteArrayList<ProviderEventListener> listeners = new CopyOnWriteArrayList<ProviderEventListener>();
+ private Map<Class<? extends Provider>, String> provider = new HashMap<>();
+ private volatile Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoriesMap = new HashMap<>();
+ protected CopyOnWriteArrayList<ProviderEventListener> listeners = new CopyOnWriteArrayList<>();
+ private JtaRegistration jta;
// TODO: Likely should be changed to int and use Time.currentTime() to be compatible with all our "time" reps
protected long serverStartupTimestamp;
@@ -67,17 +72,152 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
public void init() {
serverStartupTimestamp = System.currentTimeMillis();
+ jta = new JtaRegistration();
ProviderManager pm = new ProviderManager(getClass().getClassLoader(), Config.scope().getArray("providers"));
-
- // Load the SPI classes through the provider manager, so both Keycloak internal SPI's and
- // the ones defined in deployed modules will be found.
- loadSPIs(pm, pm.loadSpis());
+ spis.addAll(pm.loadSpis());
+ factoriesMap = loadFactories(pm);
+ for (ProviderManager manager : ProviderManagerRegistry.SINGLETON.getPreBoot()) {
+ Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoryMap = loadFactories(manager);
+ for (Map.Entry<Class<? extends Provider>, Map<String, ProviderFactory>> entry : factoryMap.entrySet()) {
+ Map<String, ProviderFactory> factories = factoriesMap.get(entry.getKey());
+ if (factories == null) {
+ factoriesMap.put(entry.getKey(), entry.getValue());
+ } else {
+ factories.putAll(entry.getValue());
+ }
+ }
+ }
+ checkProvider();
for ( Map<String, ProviderFactory> factories : factoriesMap.values()) {
for (ProviderFactory factory : factories.values()) {
factory.postInit(this);
}
}
+ // make the session factory ready for hot deployment
+ ProviderManagerRegistry.SINGLETON.setDeployer(this);
+ }
+ protected Map<Class<? extends Provider>, Map<String, ProviderFactory>> getFactoriesCopy() {
+ Map<Class<? extends Provider>, Map<String, ProviderFactory>> copy = new HashMap<>();
+ for (Map.Entry<Class<? extends Provider>, Map<String, ProviderFactory>> entry : factoriesMap.entrySet()) {
+ Map<String, ProviderFactory> valCopy = new HashMap<>();
+ valCopy.putAll(entry.getValue());
+ copy.put(entry.getKey(), valCopy);
+ }
+ return copy;
+
+ }
+
+ @Override
+ public void deploy(ProviderManager pm) {
+ Map<Class<? extends Provider>, Map<String, ProviderFactory>> copy = getFactoriesCopy();
+ Map<Class<? extends Provider>, Map<String, ProviderFactory>> newFactories = loadFactories(pm);
+ List<ProviderFactory> undeployed = new LinkedList<>();
+
+ for (Map.Entry<Class<? extends Provider>, Map<String, ProviderFactory>> entry : newFactories.entrySet()) {
+ Map<String, ProviderFactory> current = copy.get(entry.getKey());
+ if (current == null) {
+ copy.put(entry.getKey(), entry.getValue());
+ } else {
+ for (ProviderFactory f : entry.getValue().values()) {
+ ProviderFactory old = current.remove(f.getId());
+ if (old != null) undeployed.add(old);
+ }
+ current.putAll(entry.getValue());
+ }
+
+ }
+ factoriesMap = copy;
+ for (ProviderFactory factory : undeployed) {
+ factory.close();
+ }
+ }
+
+ @Override
+ public void undeploy(ProviderManager pm) {
+ // we make a copy to avoid concurrent access exceptions
+ Map<Class<? extends Provider>, Map<String, ProviderFactory>> copy = getFactoriesCopy();
+ MultivaluedHashMap<Class<? extends Provider>, ProviderFactory> factories = pm.getLoadedFactories();
+ List<ProviderFactory> undeployed = new LinkedList<>();
+ for (Map.Entry<Class<? extends Provider>, List<ProviderFactory>> entry : factories.entrySet()) {
+ Map<String, ProviderFactory> registered = copy.get(entry.getKey());
+ for (ProviderFactory factory : entry.getValue()) {
+ undeployed.add(factory);
+ if (registered != null) {
+ registered.remove(factory.getId());
+ }
+ }
+ }
+ factoriesMap = copy;
+ for (ProviderFactory factory : undeployed) {
+ factory.close();
+ }
+ }
+
+ protected void checkProvider() {
+ for (Spi spi : spis) {
+ String provider = Config.getProvider(spi.getName());
+ if (provider != null) {
+ this.provider.put(spi.getProviderClass(), provider);
+ if (getProviderFactory(spi.getProviderClass(), provider) == null) {
+ throw new RuntimeException("Failed to find provider " + provider + " for " + spi.getName());
+ }
+ } else {
+ Map<String, ProviderFactory> factories = factoriesMap.get(spi.getProviderClass());
+ if (factories != null && factories.size() == 1) {
+ provider = factories.values().iterator().next().getId();
+ this.provider.put(spi.getProviderClass(), provider);
+ }
+ }
+ }
+ }
+
+ protected Map<Class<? extends Provider>, Map<String, ProviderFactory>> loadFactories(ProviderManager pm) {
+ Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoryMap = new HashMap<>();
+ Set<Spi> spiList = spis;
+
+ for (Spi spi : spiList) {
+
+ Map<String, ProviderFactory> factories = new HashMap<String, ProviderFactory>();
+ factoryMap.put(spi.getProviderClass(), factories);
+
+ String provider = Config.getProvider(spi.getName());
+ if (provider != null) {
+
+ ProviderFactory factory = pm.load(spi, provider);
+ if (factory == null) {
+ continue;
+ }
+
+ Config.Scope scope = Config.scope(spi.getName(), provider);
+ factory.init(scope);
+
+ if (spi.isInternal() && !isInternal(factory)) {
+ logger.spiMayChange(factory.getId(), factory.getClass().getName(), spi.getName());
+ }
+
+ factories.put(factory.getId(), factory);
+
+ logger.debugv("Loaded SPI {0} (provider = {1})", spi.getName(), provider);
+ } else {
+ for (ProviderFactory factory : pm.load(spi)) {
+ Config.Scope scope = Config.scope(spi.getName(), factory.getId());
+ if (scope.getBoolean("enabled", true)) {
+ factory.init(scope);
+
+ if (spi.isInternal() && !isInternal(factory)) {
+ logger.spiMayChange(factory.getId(), factory.getClass().getName(), spi.getName());
+ }
+
+ factories.put(factory.getId(), factory);
+ } else {
+ logger.debugv("SPI {0} provider {1} disabled", spi.getName(), factory.getId());
+ }
+ }
+ }
+ }
+ return factoryMap;
+
}
protected void loadSPIs(ProviderManager pm, List<Spi> spiList) {
@@ -135,7 +275,9 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
}
public KeycloakSession create() {
- return new DefaultKeycloakSession(this);
+ KeycloakSession session = new DefaultKeycloakSession(this);
+ jta.begin(session);
+ return session;
}
<T extends Provider> String getDefaultProvider(Class<T> clazz) {
@@ -180,6 +322,7 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
}
public void close() {
+ ProviderManagerRegistry.SINGLETON.setDeployer(null);
for (Map<String, ProviderFactory> factories : factoriesMap.values()) {
for (ProviderFactory factory : factories.values()) {
factory.close();
diff --git a/services/src/main/java/org/keycloak/services/JtaRegistration.java b/services/src/main/java/org/keycloak/services/JtaRegistration.java
new file mode 100644
index 0000000..cdd6e94
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/JtaRegistration.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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
+ *
+ * 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.keycloak.services;
+
+import org.keycloak.models.KeycloakSession;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JtaRegistration {
+ private static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
+
+ private TransactionManager tm;
+
+ public JtaRegistration() {
+ try {
+ InitialContext ctx = new InitialContext();
+ tm = (TransactionManager)ctx.lookup("java:jboss/TransactionManager");
+ if (tm == null) {
+ logger.debug("Could not locate TransactionManager");
+ }
+ } catch (NamingException e) {
+ logger.debug("Could not load TransactionManager", e);
+ }
+
+ }
+
+ public void begin(KeycloakSession session) {
+ if (tm == null) return;
+
+ session.getTransactionManager().enlist(new JtaTransactionWrapper(tm));
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/JtaTransactionWrapper.java b/services/src/main/java/org/keycloak/services/JtaTransactionWrapper.java
new file mode 100644
index 0000000..5eb1233
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/JtaTransactionWrapper.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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
+ *
+ * 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.keycloak.services;
+
+import org.keycloak.models.KeycloakTransaction;
+
+import javax.transaction.InvalidTransactionException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JtaTransactionWrapper implements KeycloakTransaction {
+ protected TransactionManager tm;
+ protected Transaction ut;
+ protected Transaction suspended;
+
+ public JtaTransactionWrapper(TransactionManager tm) {
+ this.tm = tm;
+ try {
+ suspended = tm.suspend();
+ tm.begin();
+ ut = tm.getTransaction();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void begin() {
+ }
+
+ @Override
+ public void commit() {
+ try {
+ ut.commit();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void rollback() {
+ try {
+ ut.rollback();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ end();
+ }
+
+ }
+
+ @Override
+ public void setRollbackOnly() {
+ try {
+ ut.setRollbackOnly();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean getRollbackOnly() {
+ try {
+ return ut.getStatus() == Status.STATUS_MARKED_ROLLBACK;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean isActive() {
+ try {
+ return ut.getStatus() == Status.STATUS_ACTIVE;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void end() {
+ if (suspended != null) {
+ try {
+ tm.resume(suspended);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/UserTransactionWrapper.java b/services/src/main/java/org/keycloak/services/UserTransactionWrapper.java
new file mode 100644
index 0000000..a106321
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/UserTransactionWrapper.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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
+ *
+ * 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.keycloak.services;
+
+import org.keycloak.models.KeycloakTransaction;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.UserTransaction;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserTransactionWrapper implements KeycloakTransaction {
+ protected UserTransaction ut;
+
+ public UserTransactionWrapper(UserTransaction ut) {
+ this.ut = ut;
+ }
+
+ @Override
+ public void begin() {
+ try {
+ ut.begin();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void commit() {
+ try {
+ ut.commit();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void rollback() {
+ try {
+ ut.rollback();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ @Override
+ public void setRollbackOnly() {
+ try {
+ ut.setRollbackOnly();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean getRollbackOnly() {
+ try {
+ return ut.getStatus() == Status.STATUS_MARKED_ROLLBACK;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean isActive() {
+ try {
+ return ut.getStatus() == Status.STATUS_ACTIVE;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
testsuite/integration/pom.xml 4(+4 -0)
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 0e3c17c..acb0534 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -69,6 +69,10 @@
<artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
</dependency>
<dependency>
+ <groupId>org.jboss.spec.javax.transaction</groupId>
+ <artifactId>jboss-transaction-api_1.2_spec</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>async-http-servlet-3.0</artifactId>
</dependency>
wildfly/server-subsystem/pom.xml 10(+10 -0)
diff --git a/wildfly/server-subsystem/pom.xml b/wildfly/server-subsystem/pom.xml
index 02c7ab1..20c9d66 100755
--- a/wildfly/server-subsystem/pom.xml
+++ b/wildfly/server-subsystem/pom.xml
@@ -78,6 +78,16 @@
<artifactId>jboss-logging-processor</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-services</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-spi</artifactId>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.wildfly.core</groupId>
diff --git a/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDependencyProcessor.java b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDependencyProcessor.java
new file mode 100644
index 0000000..aa0c1b2
--- /dev/null
+++ b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDependencyProcessor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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
+ *
+ * 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.keycloak.subsystem.server.extension;
+
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.server.deployment.module.ModuleDependency;
+import org.jboss.as.server.deployment.module.ModuleSpecification;
+import org.jboss.as.server.deployment.module.ResourceRoot;
+import org.jboss.logging.Logger;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleIdentifier;
+import org.jboss.modules.ModuleLoader;
+import org.jboss.vfs.VirtualFile;
+import org.jboss.vfs.util.AbstractVirtualFileFilterWithAttributes;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakProviderDependencyProcessor implements DeploymentUnitProcessor {
+ private static final ModuleIdentifier KEYCLOAK_COMMON = ModuleIdentifier.create("org.keycloak.keycloak-common");
+ private static final ModuleIdentifier KEYCLOAK_CORE = ModuleIdentifier.create("org.keycloak.keycloak-core");
+ private static final ModuleIdentifier KEYCLOAK_SERVER_SPI = ModuleIdentifier.create("org.keycloak.keycloak-server-spi");
+ private static final ModuleIdentifier KEYCLOAK_JPA = ModuleIdentifier.create("org.keycloak.keycloak-model-jpa");
+ private static final ModuleIdentifier JAXRS = ModuleIdentifier.create("javax.ws.rs.api");
+ private static final ModuleIdentifier RESTEASY = ModuleIdentifier.create("org.jboss.resteasy.resteasy-jaxrs");
+ private static final ModuleIdentifier APACHE = ModuleIdentifier.create("org.apache.httpcomponents");
+
+ private static final Logger logger = Logger.getLogger(KeycloakProviderDependencyProcessor.class);
+
+ @Override
+ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+ DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
+ KeycloakAdapterConfigService config = KeycloakAdapterConfigService.INSTANCE;
+ String deploymentName = deploymentUnit.getName();
+
+ if (config.isKeycloakServerDeployment(deploymentName)) {
+ return;
+ }
+
+ if (!isKeycloakProviderDeployment(deploymentUnit)) return;
+
+ logger.info("FOUND KEYCLOAK PROVIDER DEPLOYMENT!!!!: " + deploymentUnit.getName());
+
+ final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
+ final ModuleLoader moduleLoader = Module.getBootModuleLoader();
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_COMMON, false, false, false, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE, false, false, false, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_SERVER_SPI, false, false, false, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, JAXRS, false, false, false, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, RESTEASY, false, false, false, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, APACHE, false, false, false, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_JPA, false, false, false, false));
+
+
+ }
+
+ public KeycloakProviderDependencyProcessor() {
+ super();
+ }
+
+ public static boolean isKeycloakProviderDeployment(DeploymentUnit du) {
+ final ResourceRoot resourceRoot = du.getAttachment(Attachments.DEPLOYMENT_ROOT);
+ if (resourceRoot == null) {
+ return false;
+ }
+ final VirtualFile deploymentRoot = resourceRoot.getRoot();
+ if (deploymentRoot == null || !deploymentRoot.exists()) {
+ return false;
+ }
+ VirtualFile services = deploymentRoot.getChild("META-INF/services");
+ if (!services.exists()) return false;
+ try {
+ List<VirtualFile> archives = services.getChildren(new AbstractVirtualFileFilterWithAttributes(){
+ @Override
+ public boolean accepts(VirtualFile file) {
+ return file.getName().startsWith("org.keycloak");
+ }
+ });
+ return !archives.isEmpty();
+ } catch (IOException e) {
+
+ }
+ return false;
+ }
+
+ @Override
+ public void undeploy(DeploymentUnit context) {
+
+ }
+}
diff --git a/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDeploymentProcessor.java b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDeploymentProcessor.java
new file mode 100644
index 0000000..c573754
--- /dev/null
+++ b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDeploymentProcessor.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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
+ *
+ * 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.keycloak.subsystem.server.extension;
+
+import org.jboss.as.server.deployment.AttachmentKey;
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.server.deployment.module.ModuleDependency;
+import org.jboss.as.server.deployment.module.ModuleSpecification;
+import org.jboss.as.server.deployment.module.ResourceRoot;
+import org.jboss.logging.Logger;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleIdentifier;
+import org.jboss.modules.ModuleLoader;
+import org.jboss.vfs.VirtualFile;
+import org.jboss.vfs.util.AbstractVirtualFileFilterWithAttributes;
+import org.keycloak.provider.ProviderManager;
+import org.keycloak.provider.ProviderManagerRegistry;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakProviderDeploymentProcessor implements DeploymentUnitProcessor {
+
+ AttachmentKey<ProviderManager> ATTACHMENT_KEY = AttachmentKey.create(ProviderManager.class);
+
+ private static final Logger logger = Logger.getLogger(KeycloakProviderDeploymentProcessor.class);
+ @Override
+ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+ DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
+ KeycloakAdapterConfigService config = KeycloakAdapterConfigService.INSTANCE;
+ String deploymentName = deploymentUnit.getName();
+
+ if (config.isKeycloakServerDeployment(deploymentName)) {
+ return;
+ }
+
+ if (!KeycloakProviderDependencyProcessor.isKeycloakProviderDeployment(deploymentUnit)) return;
+
+ logger.infof("Deploying Keycloak provider: {0}", deploymentUnit.getName());
+ final Module module = deploymentUnit.getAttachment(Attachments.MODULE);
+ ProviderManager pm = new ProviderManager(module.getClassLoader());
+ ProviderManagerRegistry.SINGLETON.deploy(pm);
+ deploymentUnit.putAttachment(ATTACHMENT_KEY, pm);
+
+
+
+ }
+
+ public KeycloakProviderDeploymentProcessor() {
+ super();
+ }
+
+ @Override
+ public void undeploy(DeploymentUnit context) {
+ ProviderManager pm = context.getAttachment(ATTACHMENT_KEY);
+ if (pm != null) {
+ logger.infof("Undeploying Keycloak provider: {0}", context.getName());
+ ProviderManagerRegistry.SINGLETON.undeploy(pm);
+ context.removeAttachment(ATTACHMENT_KEY);
+ }
+ }
+}
diff --git a/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
index a5d9e85..3c6dc34 100755
--- a/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
+++ b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
@@ -44,12 +44,22 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
context.addStep(new AbstractDeploymentChainStep() {
@Override
protected void execute(DeploymentProcessorTarget processorTarget) {
+ processorTarget.addDeploymentProcessor(SUBSYSTEM_NAME, Phase.DEPENDENCIES, 0, new KeycloakProviderDependencyProcessor());
+ processorTarget.addDeploymentProcessor(SUBSYSTEM_NAME,
+ Phase.POST_MODULE, // PHASE
+ Phase.POST_MODULE_VALIDATOR_FACTORY - 2, // PRIORITY
+ new KeycloakProviderDeploymentProcessor());
processorTarget.addDeploymentProcessor(SUBSYSTEM_NAME,
Phase.POST_MODULE, // PHASE
Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
new KeycloakServerDeploymentProcessor());
}
}, OperationContext.Stage.RUNTIME);
+ context.addStep(new AbstractDeploymentChainStep() {
+ @Override
+ protected void execute(DeploymentProcessorTarget processorTarget) {
+ }
+ }, OperationContext.Stage.RUNTIME);
}
protected void populateModel(final OperationContext context, final ModelNode operation, final Resource resource) throws OperationFailedException {
diff --git a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml
index c823e4f..326fa7f 100755
--- a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml
+++ b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml
@@ -29,7 +29,7 @@
<password>sa</password>
</security>
</datasource>
- <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+ <datasource jndi-name="java:jboss/datasources/KeycloakDS" jta="false" pool-name="KeycloakDS" enabled="true" use-java-context="true">
<?KEYCLOAK_DS_CONNECTION_URL?>
<driver>h2</driver>
<security>