diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationProvider.java b/model/api/src/main/java/org/keycloak/models/UserFederationProvider.java
index 68b0834..7c97d67 100755
--- a/model/api/src/main/java/org/keycloak/models/UserFederationProvider.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationProvider.java
@@ -7,7 +7,8 @@ import java.util.Map;
import java.util.Set;
/**
- * SPI for plugging in federation storage.
+ * SPI for plugging in federation storage. This class is instantiated once per session/request and is closed after
+ * the session/request is finished.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@@ -72,7 +73,8 @@ public interface UserFederationProvider extends Provider {
boolean removeUser(RealmModel realm, UserModel user);
/**
- * Required to import into local storage any user found.
+ * Keycloak will search for user in local storage first. If it can't find the UserModel is local storage,
+ * it will call this method. You are required to import the returned UserModel into local storage.
*
* @param realm
* @param username
@@ -81,7 +83,8 @@ public interface UserFederationProvider extends Provider {
UserModel getUserByUsername(RealmModel realm, String username);
/**
- * Required to import into local storage any user found.
+ * Keycloak will search for user in local storage first. If it can't find the UserModel is local storage,
+ * it will call this method. You are required to import the returned UserModel into local storage.
*
* @param realm
* @param email
@@ -90,7 +93,8 @@ public interface UserFederationProvider extends Provider {
UserModel getUserByEmail(RealmModel realm, String email);
/**
- * Required to import into local storage any user found. Must not import if user already exists in KeycloakSession.userStorage()!
+ * Keycloak does not search in local storage first before calling this method. The implementation must check
+ * to see if user is already in local storage (KeycloakSession.userStorage()) before doing an import.
* Currently only attributes USERNAME, EMAIL, FIRST_NAME and LAST_NAME will be used.
*
* @param attributes
@@ -115,7 +119,8 @@ public interface UserFederationProvider extends Provider {
void preRemove(RealmModel realm, RoleModel role);
/**
- * Is the Keycloak UserModel still valid and/or existing in federated storage?
+ * Is the Keycloak UserModel still valid and/or existing in federated storage? Keycloak may call this method
+ * in various user operations. The local storage may be deleted if this method returns false.
*
* @param local
* @return
@@ -158,6 +163,12 @@ public interface UserFederationProvider extends Provider {
*/
CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel credential);
+ /**
+ * This method is called at the end of requests.
+ *
+ */
void close();
+
+
}
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationProviderFactory.java b/model/api/src/main/java/org/keycloak/models/UserFederationProviderFactory.java
index 746b222..215b86d 100755
--- a/model/api/src/main/java/org/keycloak/models/UserFederationProviderFactory.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationProviderFactory.java
@@ -56,4 +56,12 @@ public interface UserFederationProviderFactory extends ProviderFactory<UserFeder
* @param lastSync
*/
UserFederationSyncResult syncChangedUsers(KeycloakSessionFactory sessionFactory, String realmId, UserFederationProviderModel model, Date lastSync);
+
+ /**
+ * This method is never called and is only an artifact of ProviderFactory. Returning null with no implementation is recommended.
+ * @param session
+ * @return
+ */
+ @Override
+ UserFederationProvider create(KeycloakSession session);
}
diff --git a/model/api/src/main/java/org/keycloak/provider/ProviderFactory.java b/model/api/src/main/java/org/keycloak/provider/ProviderFactory.java
index e047d66..5e8adbe 100755
--- a/model/api/src/main/java/org/keycloak/provider/ProviderFactory.java
+++ b/model/api/src/main/java/org/keycloak/provider/ProviderFactory.java
@@ -5,12 +5,22 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
/**
+ * At boot time, keycloak discovers all factories. For each discovered factory, the init() method is called. After
+ * all factories have been initialized, the postInit() method is called. close() is called when the server shuts down.
+ *
+ * Only one instance of a factory exists per server.
+ *
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public interface ProviderFactory<T extends Provider> {
public T create(KeycloakSession session);
+ /**
+ * Only called once when the factory is first created. This config is pulled from keycloak_server.json
+ *
+ * @param config
+ */
public void init(Config.Scope config);
/**
@@ -18,6 +28,10 @@ public interface ProviderFactory<T extends Provider> {
*/
public void postInit(KeycloakSessionFactory factory);
+ /**
+ * This is called when the server shuts down.
+ *
+ */
public void close();
public String getId();