=== 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 { @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); } } ---- 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.