2016-12-03 00:55:47 +00:00
|
|
|
|
|
|
|
=== Leveraging Java EE
|
|
|
|
|
|
|
|
The user storage providers can be packaged within any Java EE component so long as you set up the `META-INF/services`
|
|
|
|
file correctly to point to your providers. For example, if your provider needs to use third party libraries, you
|
|
|
|
can package up your provider within an ear and store these third pary libraries in the ear's `lib/` directory.
|
|
|
|
Also note that provider jars can make use of the `jboss-deployment-structure.xml` file that EJBs, WARS, and EARs
|
|
|
|
can use in a JBoss/Wildfly environment. See the JBoss/Wildfly documentation for more details on this file. It
|
|
|
|
allows you to pull in external dependencies among other fine grain actions.
|
|
|
|
|
|
|
|
Implementations of `UserStorageProviderFactory` are required to be plain java objects. But, we also currently support
|
|
|
|
implementing `UserStorageProvider` classes as Stateful EJBs. This is especially useful if you want to use JPA
|
|
|
|
to connect to a relational store. This is how you would do it:
|
|
|
|
|
|
|
|
[source,java]
|
|
|
|
----
|
|
|
|
@Stateful
|
|
|
|
@Local(EjbExampleUserStorageProvider.class)
|
|
|
|
public class EjbExampleUserStorageProvider implements UserStorageProvider,
|
|
|
|
UserLookupProvider,
|
|
|
|
UserRegistrationProvider,
|
|
|
|
UserQueryProvider,
|
|
|
|
CredentialInputUpdater,
|
|
|
|
CredentialInputValidator,
|
|
|
|
OnUserCache
|
|
|
|
{
|
|
|
|
@PersistenceContext
|
|
|
|
protected EntityManager em;
|
|
|
|
|
|
|
|
protected ComponentModel model;
|
|
|
|
protected KeycloakSession session;
|
|
|
|
|
|
|
|
public void setModel(ComponentModel model) {
|
|
|
|
this.model = model;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setSession(KeycloakSession session) {
|
|
|
|
this.session = session;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Remove
|
|
|
|
@Override
|
|
|
|
public void close() {
|
|
|
|
}
|
|
|
|
...
|
|
|
|
}
|
|
|
|
----
|
|
|
|
|
|
|
|
You have to define the `@Local` annotation and specify your provider class there. If you don't do this, EJB will
|
|
|
|
not proxy the user correctly and your provider won't work.
|
|
|
|
|
|
|
|
You must put the `@Remove` annotation on the `close()` method of your provider. If you don't, the stateful bean
|
|
|
|
will never be cleaned up and you may eventually see error messages.
|
|
|
|
|
|
|
|
Implementations of `UserStorageProviderFactory` are required to be plain java objects. Your factory class would
|
|
|
|
perform a JNDI lookup of the Stateful EJB in its create() method.
|
|
|
|
|
|
|
|
[source,java]
|
|
|
|
----
|
|
|
|
public class EjbExampleUserStorageProviderFactory
|
|
|
|
implements UserStorageProviderFactory<EjbExampleUserStorageProvider> {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public EjbExampleUserStorageProvider create(KeycloakSession session, ComponentModel model) {
|
|
|
|
try {
|
|
|
|
InitialContext ctx = new InitialContext();
|
|
|
|
EjbExampleUserStorageProvider provider = (EjbExampleUserStorageProvider)ctx.lookup(
|
|
|
|
"java:global/user-storage-jpa-example/" + EjbExampleUserStorageProvider.class.getSimpleName());
|
|
|
|
provider.setModel(model);
|
|
|
|
provider.setSession(session);
|
|
|
|
return provider;
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
|
|
|
|
2016-12-07 21:58:25 +00:00
|
|
|
This example also assumes that you've defined a JPA deployment in the same jar as the provider. This means a `persistence.xml`
|
|
|
|
file as well as any JPA `@Entity` classes.
|
|
|
|
|
|
|
|
WARNING: When doing JPA any additional datasource you use must be an XA datasource. The {{book.project.name}} datasource
|
|
|
|
is non-xa. If you interact with two or more non-xa datasource in the same transaction, the server will barf with
|
|
|
|
an error message. You can only have one non-xa resource in a single transaction.
|
|
|
|
|
|
|
|
See the JBoss/Wildfly manual for more details on deploying an XA datasource.
|
|
|
|
|