keycloak-scim/topics/extensions.adoc
Marek Posolda 2f0408bb39 KEYCLOAK-2474 Added docs for custom REST endpoints, SPI and JPA entities (#10)
* KEYCLOAK-2474 Added docs for custom REST endpoints, SPI and JPA entities

* Review + corrections extension documentation
2016-06-23 16:32:09 +02:00

147 lines
6.7 KiB
Text

[[_extensions]]
== Extending the Server
The {{book.project.name}} SPI framework offers the possibility to implement or override particular built-in providers. However {{book.project.name}}
also provides capabilities to extend it's core functionalities and domain. This includes possibilities to:
* Add custom REST endpoints to the {{book.project.name}} server
* Add your own custom SPI
* Add custom JPA entities to the {{book.project.name}} data model
[[_extensions_rest]]
=== Add custom REST endpoints
This is a very powerful extension, which allows you to deploy your own REST endpoints to the {{book.project.name}} server. It enables all kinds of extensions, for example
the possibility to trigger functionality on the {{book.project.name}} server, which is not available through the default set of built-in {{book.project.name}} REST endpoints.
To add a custom REST endpoint, you need to implement the `RealmResourceProviderFactory` and `RealmResourceProvider` interfaces. `RealmResourceProvider` has one important method:
[source,java]
----
Object getResource();
----
which allows you to return an object, which acts as a https://jax-rs-spec.java.net/[JAX-RS Resource]. For more details, see the Javadoc and our examples.
There is a very simple example in the example distribution in `providers/rest` and there is a more advanced example in `providers/domain-extension`,
which shows how to add an authenticated REST endpoint and other functionalities like <<extensions.adoc#_extensions_spi,Adding your own SPI>>
or <<extensions.adoc#_extensions_jpa,Extending datamodel with your own JPA entities>>.
For details on how to package and deploy a custom provider, refer to the <<providers.adoc#_providers,Service Provider Interfaces>> chapter.
[[_extensions_spi]]
=== Add your own custom SPI
This is useful especially with the <<extensions.adoc#_extensions_rest,Custom REST endpoints>>. To add your own kind of SPI, you need to
implement the interface `org.keycloak.provider.Spi` and define the ID of your SPI and the `ProviderFactory` and `Provider` classes. That looks like this:
[source,java]
----
package org.keycloak.examples.domainextension.spi;
import ...
public class ExampleSpi implements Spi {
@Override
public boolean isInternal() {
return false;
}
@Override
public String getName() {
return "example";
}
@Override
public Class<? extends Provider> getProviderClass() {
return ExampleService.class;
}
@Override
@SuppressWarnings("rawtypes")
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return ExampleServiceProviderFactory.class;
}
}
----
Then you need to create the file `META-INF/services/org.keycloak.provider.Spi` and add the class of your SPI to it. For example:
[source]
----
org.keycloak.examples.domainextension.spi.ExampleSpi
----
The next step is to create the interfaces `ExampleServiceProviderFactory`, which extends from `ProviderFactory` and `ExampleService`, which extends from `Provider`.
The `ExampleService` will usually contain the business methods you need for your use case. Note that the `ExampleServiceProviderFactory` instance
is always scoped per application, however `ExampleService` is scoped per-request (or more accurately per `KeycloakSession` lifecycle).
Finally you need to implement your providers in the same manner as described in the <<providers.adoc#_providers,Service Provider Interfaces>> chapter.
For more details, take a look at the example distribution at `providers/domain-extension`, which shows an Example SPI similar to the one above.
[[_extensions_jpa]]
=== Add custom JPA entities to the {{book.project.name}} data model
If the {{book.project.name}} data model does not exactly match your desired solution, or if you want to add some core functionality to {{book.project.name}},
or when you have your own REST endpoint, you might want to extend the {{book.project.name}} data model. We enable you to add your
own JPA entities to the {{book.project.name}} JPA `EntityManager` .
To add your own JPA entities, you need to implement `JpaEntityProviderFactory` and `JpaEntityProvider`. The `JpaEntityProvider`
allows you to return a list of your custom JPA entities and provide the location and id of the liquibase changelog. An example implementation can look like this:
[source,java]
----
public class ExampleJpaEntityProvider implements JpaEntityProvider {
// List of your JPA entities.
@Override
public List<Class<?>> getEntities() {
return Collections.<Class<?>>singletonList(Company.class);
}
// This is used to return the location of the Liquibase changelog file.
// You can return null if you don't want Liquibase to create and update the DB schema.
@Override
public String getChangelogLocation() {
return "META-INF/example-changelog.xml";
}
// Helper method, which will be used internally by Liquibase.
@Override
public String getFactoryId() {
return "sample";
}
...
}
----
In the example above, we added a single JPA entity represented by class `Company`. In the code of your REST endpoint, you can then use something like
this to retrieve `EntityManager` and call DB operations on it.
[source,java]
----
EntityManager em = session.getProvider(JpaConnectionProvider.class).getEntityManager();
Company myCompany = em.find(Company.class, "123");
----
The methods `getChangelogLocation` and `getFactoryId` are important to support automatic updating of your entities by Liquibase. http://www.liquibase.org/[Liquibase]
is a framework for updating the database schema, which {{book.project.name}} internally uses to create the DB schema and update the DB schema among versions. You may need to use
it as well and create a changelog for your entities. Note that versioning of your own liquibase changelog is independent
of {{book.project.name}} versions. In other words, when you update to a new {{book.project.name}} version, you are not forced to update your
schema at the same time. And vice versa, you can update your schema even without updating the {{book.project.name}} version. The Liquibase update
is always done at the server startup, so to trigger a DB update of your schema, you just need to add the new changeset to your liquibase changelog file (in the example above
it's the file `META-INF/example-changelog.xml` (which must be packed in same JAR as the JPA entities and `ExampleJpaEntityProvider`) and then restart server.
The DB schema will be automatically updated at startup.
For more details, take a look at the example distribution at example `providers/domain-extension`, which shows the `ExampleJpaEntityProvider` and `example-changelog.xml` described above.
NOTE: Don't forget to always backup your database before doing any changes in the Liquibase changelog and triggering a DB update.