keycloak-aplcache
Changes
examples/providers/domain-extension/pom.xml 64(+64 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/Company.java 110(+110 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/Region.java 62(+62 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/UserAccount.java 73(+73 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/UserAccountRegionRole.java 79(+79 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/entity/ExampleJpaEntityProvider.java 50(+50 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/entity/ExampleJpaEntityProviderFactory.java 57(+57 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/rest/ExampleRealmResourceProvider.java 41(+41 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/rest/ExampleRealmResourceProviderFactory.java 52(+52 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/CompanyResource.java 41(+41 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRestResource.java 20(+20 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/model/CompanyView.java 26(+26 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/ExampleService.java 33(+33 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/ExampleServiceImpl.java 71(+71 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/repository/AbstractRepository.java 51(+51 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/repository/CompanyRepository.java 41(+41 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleServiceProviderFactory.java 25(+25 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleServiceProviderFactoryImpl.java 53(+53 -0)
examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleSpi.java 48(+48 -0)
examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory 18(+18 -0)
examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.examples.domainextension.services.spi.ExampleServiceProviderFactory 18(+18 -0)
examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.provider.Spi 18(+18 -0)
examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory 18(+18 -0)
examples/providers/pom.xml 1(+1 -0)
Details
diff --git a/examples/providers/domain-extension/.gitignore b/examples/providers/domain-extension/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/examples/providers/domain-extension/.gitignore
@@ -0,0 +1 @@
+/target/
examples/providers/domain-extension/pom.xml 64(+64 -0)
diff --git a/examples/providers/domain-extension/pom.xml b/examples/providers/domain-extension/pom.xml
new file mode 100755
index 0000000..8d8e496
--- /dev/null
+++ b/examples/providers/domain-extension/pom.xml
@@ -0,0 +1,64 @@
+<!--
+ ~ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-examples-providers-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>2.0.0.CR1-SNAPSHOT</version>
+ </parent>
+
+ <name>Domain Extension Example</name>
+ <description/>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-examples-providers-domain-extension</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core</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.keycloak</groupId>
+ <artifactId>keycloak-model-jpa</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.ws.rs</groupId>
+ <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>domain-extension-example</finalName>
+ </build>
+</project>
+
diff --git a/examples/providers/domain-extension/README.md b/examples/providers/domain-extension/README.md
new file mode 100644
index 0000000..c8163cd
--- /dev/null
+++ b/examples/providers/domain-extension/README.md
@@ -0,0 +1,15 @@
+Example Domain Extension
+========================
+
+To run, deploy as a module by running:
+
+ $KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.domain-extension-example --resources=target/domain-extension-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-model-jpa,org.keycloak.keycloak-server-spi,javax.ws.rs.api"
+
+Then registering the provider by editing keycloak-server.json and adding the module to the providers field:
+
+ "providers": [
+ ....
+ "module:org.keycloak.examples.domain-extension-example"
+ ],
+
+Then start (or restart) the server. Once started do xyz TODO.
\ No newline at end of file
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/Company.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/Company.java
new file mode 100644
index 0000000..6e61d33
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/Company.java
@@ -0,0 +1,110 @@
+/*
+ * 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.examples.domainextension.entities;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "EXAMPLE_COMPANY")
+@NamedQueries({ @NamedQuery(name = "findAllCompanies", query = "from Company"),
+ @NamedQuery(name = "findByRealm", query = "from Company where realmId = :realmId") })
+public class Company {
+
+ @Id
+ @Column(name = "ID")
+ private String id;
+
+ @Column(name = "NAME", nullable = false)
+ private String name;
+
+ @Column(name = "REALM_ID", nullable = false)
+ private String realmId;
+
+ @OneToMany(cascade = CascadeType.ALL, mappedBy = "company", orphanRemoval = true)
+ private final Set<Region> regions = new HashSet<>();
+
+ @OneToMany(cascade = CascadeType.ALL, mappedBy = "company", orphanRemoval = true)
+ private final Set<UserAccount> userAccounts = new HashSet<>();
+
+ @SuppressWarnings("unused")
+ private Company() {
+
+ }
+
+ public Company(String realmId, String name) {
+ this.id = UUID.randomUUID().toString();
+ this.realmId = realmId;
+ this.name = name;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getRealmId() {
+ return realmId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Set<UserAccount> getUserAccounts() {
+ return Collections.unmodifiableSet(userAccounts);
+ }
+
+ public void addUserAccount(UserAccount userAccount) {
+ userAccounts.add(userAccount);
+ }
+
+ public boolean removeUserAccount(UserAccount userAccount) {
+ return userAccounts.remove(userAccount);
+ }
+
+ public UserAccount getUserAccountByUsername(String username) {
+ for (UserAccount userAccount : userAccounts) {
+ if (userAccount.getUser().getUsername().equals(username)) {
+ return userAccount;
+ }
+ }
+
+ throw new NoSuchElementException("No user found with name '" + username + "'");
+ }
+
+ public void addRegion(Region region) {
+ regions.add(region);
+ }
+
+ public boolean removeRegion(Region region) {
+ return regions.remove(region);
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/Region.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/Region.java
new file mode 100644
index 0000000..c0d9fc2
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/Region.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.examples.domainextension.entities;
+
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "EXAMPLE_REGION")
+public class Region {
+
+ @Id
+ @Column(name = "ID")
+ private String id;
+
+ @Column(name = "NAME", nullable = false)
+ private String name;
+
+ @ManyToOne
+ @JoinColumn(name = "COMPANY_ID", nullable = true)
+ private Company company;
+
+ @SuppressWarnings("unused")
+ private Region() {
+
+ }
+
+ public Region(String name) {
+ this.id = UUID.randomUUID().toString();
+ this.name = name;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/UserAccount.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/UserAccount.java
new file mode 100644
index 0000000..7015d42
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/UserAccount.java
@@ -0,0 +1,73 @@
+/*
+ * 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.examples.domainextension.entities;
+
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import org.keycloak.models.jpa.entities.UserEntity;
+
+/**
+ * The Class UserAccount.
+ */
+@Entity
+@Table(name = "EXAMPLE_USER_ACCOUNT")
+public class UserAccount {
+
+ @Id
+ @Column(name = "ID")
+ private String id;
+
+ @ManyToOne
+ @JoinColumn(name = "USER_ID", nullable = false)
+ private UserEntity user;
+
+ @ManyToOne
+ @JoinColumn(name = "COMPANY_ID", nullable = true)
+ private Company company;
+
+ @SuppressWarnings("unused")
+ private UserAccount() {
+
+ }
+
+ public UserAccount(String id, UserEntity userEntity, Company company) {
+ this.id = UUID.randomUUID().toString();
+ user = userEntity;
+ this.company = company;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public UserEntity getUser() {
+ return user;
+ }
+
+ public Company getCompany() {
+ return company;
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/UserAccountRegionRole.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/UserAccountRegionRole.java
new file mode 100644
index 0000000..17635dc
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/entities/UserAccountRegionRole.java
@@ -0,0 +1,79 @@
+/*
+ * 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.examples.domainextension.entities;
+
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import org.keycloak.models.jpa.entities.RoleEntity;
+
+@Entity
+@Table(name = "EXAMPLE_USER_ACCOUNT_REGION_ROLE")
+public class UserAccountRegionRole {
+
+ @Id
+ @Column(name = "ID")
+ private String id;
+
+ @ManyToOne
+ @JoinColumn(name = "USER_ACCOUNT_ID", nullable = false)
+ private UserAccount userAccount;
+
+ @ManyToOne
+ @JoinColumn(name = "REGION_ID", nullable = false)
+ private Region region;
+
+ @ManyToOne
+ @JoinColumn(name = "ROLE_ID", nullable = false)
+ private RoleEntity role;
+
+ @SuppressWarnings("unused")
+ private UserAccountRegionRole() {
+
+ }
+
+ public UserAccountRegionRole(UserAccount userAccount, Region region, RoleEntity role) {
+ this.id = UUID.randomUUID().toString();
+ this.userAccount = userAccount;
+ this.region = region;
+ this.role = role;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public UserAccount getUserAccount() {
+ return userAccount;
+ }
+
+ public Region getRegion() {
+ return region;
+ }
+
+ public RoleEntity getRole() {
+ return role;
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/entity/ExampleJpaEntityProvider.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/entity/ExampleJpaEntityProvider.java
new file mode 100644
index 0000000..e18056d
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/entity/ExampleJpaEntityProvider.java
@@ -0,0 +1,50 @@
+/*
+ * 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.examples.domainextension.providers.entity;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
+import org.keycloak.examples.domainextension.entities.Company;
+import org.keycloak.examples.domainextension.entities.Region;
+import org.keycloak.examples.domainextension.entities.UserAccount;
+import org.keycloak.examples.domainextension.entities.UserAccountRegionRole;
+
+/**
+ * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a>
+ *
+ * Example JpaEntityProvider.
+ */
+public class ExampleJpaEntityProvider implements JpaEntityProvider {
+
+ @Override
+ public List<Class<?>> getEntities() {
+ return Arrays.asList(Company.class, Region.class, UserAccount.class, UserAccountRegionRole.class);
+ }
+
+ @Override
+ public String getChangelogLocation() {
+ return "example-changelog.xml";
+ }
+
+ @Override
+ public void close() {
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/entity/ExampleJpaEntityProviderFactory.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/entity/ExampleJpaEntityProviderFactory.java
new file mode 100644
index 0000000..181559c
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/entity/ExampleJpaEntityProviderFactory.java
@@ -0,0 +1,57 @@
+/*
+ * 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.examples.domainextension.providers.entity;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a>
+ *
+ * Example JpaEntityProviderFactory.
+ */
+public class ExampleJpaEntityProviderFactory implements JpaEntityProviderFactory {
+
+ private static final String ID = "example-entity-provider";
+
+ @Override
+ public JpaEntityProvider create(KeycloakSession session) {
+ return new ExampleJpaEntityProvider();
+ }
+
+ @Override
+ public String getId() {
+ return ID;
+ }
+
+ @Override
+ public void init(Scope config) {
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/rest/ExampleRealmResourceProvider.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/rest/ExampleRealmResourceProvider.java
new file mode 100644
index 0000000..e2aa72c
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/rest/ExampleRealmResourceProvider.java
@@ -0,0 +1,41 @@
+/*
+ * 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.examples.domainextension.providers.rest;
+
+import org.keycloak.examples.domainextension.rest.ExampleRestResource;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.resource.RealmResourceProvider;
+
+public class ExampleRealmResourceProvider implements RealmResourceProvider {
+
+ private KeycloakSession session;
+
+ public ExampleRealmResourceProvider(KeycloakSession session) {
+ this.session = session;
+ }
+
+ @Override
+ public Object getResource() {
+ return new ExampleRestResource(session);
+ }
+
+ @Override
+ public void close() {
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/rest/ExampleRealmResourceProviderFactory.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/rest/ExampleRealmResourceProviderFactory.java
new file mode 100644
index 0000000..a3eef60
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/providers/rest/ExampleRealmResourceProviderFactory.java
@@ -0,0 +1,52 @@
+/*
+ * 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.examples.domainextension.providers.rest;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.services.resource.RealmResourceProvider;
+import org.keycloak.services.resource.RealmResourceProviderFactory;
+
+public class ExampleRealmResourceProviderFactory implements RealmResourceProviderFactory {
+
+ public static final String ID = "example";
+
+ @Override
+ public String getId() {
+ return ID;
+ }
+
+ @Override
+ public RealmResourceProvider create(KeycloakSession session) {
+ return new ExampleRealmResourceProvider(session);
+ }
+
+ @Override
+ public void init(Scope config) {
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/CompanyResource.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/CompanyResource.java
new file mode 100644
index 0000000..b3dab2b
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/CompanyResource.java
@@ -0,0 +1,41 @@
+package org.keycloak.examples.domainextension.rest;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+import org.keycloak.examples.domainextension.entities.Company;
+import org.keycloak.examples.domainextension.rest.model.CompanyView;
+import org.keycloak.examples.domainextension.services.ExampleService;
+import org.keycloak.models.KeycloakSession;
+
+public class CompanyResource {
+
+ private KeycloakSession session;
+
+ public CompanyResource(KeycloakSession session) {
+ this.session = session;
+ }
+
+ @GET
+ @Path("")
+ public Set<CompanyView> getMasterAccounts() {
+ List<Company> companies = session.getProvider(ExampleService.class).listCompanies();
+ Set<CompanyView> companyViews = new HashSet<>();
+ for (Company company : companies) {
+ companyViews.add(new CompanyView(company));
+ }
+ return companyViews;
+ }
+
+ @GET
+ @Path("{id}")
+ public CompanyView getCompany(@PathParam("id") final String id) {
+ return new CompanyView(session.getProvider(ExampleService.class).findCompany(id));
+ }
+
+}
\ No newline at end of file
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRestResource.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRestResource.java
new file mode 100644
index 0000000..4309810
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRestResource.java
@@ -0,0 +1,20 @@
+package org.keycloak.examples.domainextension.rest;
+
+import javax.ws.rs.Path;
+
+import org.keycloak.models.KeycloakSession;
+
+public class ExampleRestResource {
+
+ private KeycloakSession session;
+
+ public ExampleRestResource(KeycloakSession session) {
+ this.session = session;
+ }
+
+ @Path("companies")
+ public CompanyResource getCompanyResource() {
+ return new CompanyResource(session);
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/model/CompanyView.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/model/CompanyView.java
new file mode 100644
index 0000000..ae6d166
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/model/CompanyView.java
@@ -0,0 +1,26 @@
+package org.keycloak.examples.domainextension.rest.model;
+
+import org.keycloak.examples.domainextension.entities.Company;
+
+public class CompanyView {
+
+ private String id;
+ private String name;
+
+ public CompanyView() {
+ }
+
+ public CompanyView(Company company) {
+ id = company.getId();
+ name = company.getName();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/ExampleService.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/ExampleService.java
new file mode 100644
index 0000000..0b5e7dd
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/ExampleService.java
@@ -0,0 +1,33 @@
+/*
+ * 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.examples.domainextension.services;
+
+import java.util.List;
+
+import org.keycloak.examples.domainextension.entities.Company;
+import org.keycloak.provider.Provider;
+
+public interface ExampleService extends Provider {
+
+ List<Company> listCompanies();
+
+ Company findCompany(String id);
+
+ void addCompany(Company company);
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/ExampleServiceImpl.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/ExampleServiceImpl.java
new file mode 100644
index 0000000..ecadcc1
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/ExampleServiceImpl.java
@@ -0,0 +1,71 @@
+/*
+ * 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.examples.domainextension.services;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+
+import org.keycloak.connections.jpa.JpaConnectionProvider;
+import org.keycloak.examples.domainextension.entities.Company;
+import org.keycloak.examples.domainextension.services.repository.CompanyRepository;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+
+public class ExampleServiceImpl implements ExampleService {
+
+ private final KeycloakSession session;
+ private CompanyRepository companyRepository;
+
+ public ExampleServiceImpl(KeycloakSession session) {
+ this.session = session;
+ if (getRealm() == null) {
+ throw new IllegalStateException("The service cannot accept a session without a realm in it's context.");
+ }
+
+ companyRepository = new CompanyRepository(getEntityManager());
+ }
+
+ private EntityManager getEntityManager() {
+ return session.getProvider(JpaConnectionProvider.class).getEntityManager();
+ }
+
+ protected RealmModel getRealm() {
+ return session.getContext().getRealm();
+ }
+
+ @Override
+ public List<Company> listCompanies() {
+ return companyRepository.getAll();
+ }
+
+ @Override
+ public Company findCompany(String id) {
+ return companyRepository.findById(id);
+ }
+
+ @Override
+ public void addCompany(Company company) {
+ companyRepository.persist(company);
+ }
+
+ public void close() {
+ // Nothing to do.
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/repository/AbstractRepository.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/repository/AbstractRepository.java
new file mode 100644
index 0000000..5aeac0c
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/repository/AbstractRepository.java
@@ -0,0 +1,51 @@
+/*
+ * 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.examples.domainextension.services.repository;
+
+import java.lang.reflect.ParameterizedType;
+
+import javax.persistence.EntityManager;
+
+public abstract class AbstractRepository<T> {
+
+ private final EntityManager entityManager;
+ private final Class<T> clazz;
+
+ @SuppressWarnings("unchecked")
+ public AbstractRepository(EntityManager entityManager) {
+ this.entityManager = entityManager;
+
+ clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
+ }
+
+ protected EntityManager getEntityManager() {
+ return entityManager;
+ }
+
+ public T findById(String id) {
+ return entityManager.find(clazz, id);
+ }
+
+ public void remove(T entity) {
+ entityManager.remove(entity);
+ }
+
+ public void persist(T entity) {
+ entityManager.persist(entity);
+ }
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/repository/CompanyRepository.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/repository/CompanyRepository.java
new file mode 100644
index 0000000..d1c0516
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/repository/CompanyRepository.java
@@ -0,0 +1,41 @@
+/*
+ * 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.examples.domainextension.services.repository;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+
+import org.keycloak.examples.domainextension.entities.Company;
+
+public class CompanyRepository extends AbstractRepository<Company> {
+
+ public CompanyRepository(EntityManager entityManager) {
+ super(entityManager);
+ }
+
+ public List<Company> getAll() {
+ return getEntityManager().createNamedQuery("findAllCompanies", Company.class).getResultList();
+ }
+
+ public List<Company> getAll(String realmId) {
+ return getEntityManager().createNamedQuery("findByRealm", Company.class).setParameter("realmId", realmId)
+ .getResultList();
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleServiceProviderFactory.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleServiceProviderFactory.java
new file mode 100644
index 0000000..f1b72a7
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleServiceProviderFactory.java
@@ -0,0 +1,25 @@
+/*
+ * 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.examples.domainextension.services.spi;
+
+import org.keycloak.examples.domainextension.services.ExampleService;
+import org.keycloak.provider.ProviderFactory;
+
+public interface ExampleServiceProviderFactory extends ProviderFactory<ExampleService> {
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleServiceProviderFactoryImpl.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleServiceProviderFactoryImpl.java
new file mode 100644
index 0000000..6fb110b
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleServiceProviderFactoryImpl.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.examples.domainextension.services.spi;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.examples.domainextension.services.ExampleService;
+import org.keycloak.examples.domainextension.services.ExampleServiceImpl;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+public class ExampleServiceProviderFactoryImpl implements ExampleServiceProviderFactory {
+
+ @Override
+ public ExampleService create(KeycloakSession session) {
+ return new ExampleServiceImpl(session);
+ }
+
+ @Override
+ public void init(Scope config) {
+
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public String getId() {
+ return "exampleService";
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleSpi.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleSpi.java
new file mode 100644
index 0000000..481a5e0
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/services/spi/ExampleSpi.java
@@ -0,0 +1,48 @@
+/*
+ * 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.examples.domainextension.services.spi;
+
+import org.keycloak.examples.domainextension.services.ExampleService;
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+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;
+ }
+
+}
diff --git a/examples/providers/domain-extension/src/main/resources/META-INF/example-changelog.xml b/examples/providers/domain-extension/src/main/resources/META-INF/example-changelog.xml
new file mode 100644
index 0000000..3d96bdb
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/resources/META-INF/example-changelog.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
+ <changeSet author="erik.mulder@docdatapayments.com" id="example-1.0">
+
+ <createTable tableName="EXAMPLE_COMPANY">
+ <column name="ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="NAME" type="VARCHAR(255)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="REALM_ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ </createTable>
+
+ <addPrimaryKey
+ constraintName="PK_COMPANY"
+ tableName="DOCDATA_COMPANY"
+ columnNames="ID"
+ />
+
+ <addForeignKeyConstraint
+ constraintName="FK_COMPANY_REALM"
+ baseTableName="EXAMPLE_COMPANY"
+ baseColumnNames="REALM_ID"
+ referencedTableName="REALM"
+ referencedColumnNames="ID"
+ />
+
+ <createTable tableName="EXAMPLE_REGION">
+ <column name="ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="NAME" type="VARCHAR(255)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="COMPANY_ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ </createTable>
+
+ <addPrimaryKey
+ constraintName="PK_REGION"
+ tableName="EXAMPLE_REGION"
+ columnNames="ID"
+ />
+
+ <addForeignKeyConstraint
+ constraintName="FK_REGION_COMPANY"
+ baseTableName="EXAMPLE_REGION"
+ baseColumnNames="COMPANY_ID"
+ referencedTableName="EXAMPLE_COMPANY"
+ referencedColumnNames="ID"
+ />
+
+ <createTable tableName="EXAMPLE_USER_ACCOUNT">
+ <column name="ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="USER_ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="COMPANY_ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ </createTable>
+
+ <addPrimaryKey
+ constraintName="PK_USER_ACCOUNT"
+ tableName="EXAMPLE_USER_ACCOUNT"
+ columnNames="ID"
+ />
+
+ <addUniqueConstraint
+ constraintName="UC_USER_ACCOUNT_USER_ID"
+ tableName="EXAMPLE_USER_ACCOUNT"
+ columnNames="USER_ID"
+ />
+
+ <addForeignKeyConstraint
+ constraintName="FK_USER_ACCOUNT_USER_ENTITY"
+ baseTableName="EXAMPLE_USER_ACCOUNT"
+ baseColumnNames="USER_ID"
+ referencedTableName="USER_ENTITY"
+ referencedColumnNames="ID"
+ />
+
+ <addForeignKeyConstraint
+ constraintName="FK_USER_ACCOUNT_COMPANY"
+ baseTableName="EXAMPLE_USER_ACCOUNT"
+ baseColumnNames="COMPANY_ID"
+ referencedTableName="EXAMPLE_COMPANY"
+ referencedColumnNames="ID"
+ />
+
+ <createTable tableName="EXAMPLE_USER_ACCOUNT_REGION_ROLE">
+ <column name="ID" type="VARCHAR(36)">
+ <constraints nullable="false" />
+ </column>
+ <column name="USER_ACCOUNT_ID" type="VARCHAR(36)">
+ <constraints nullable="false" />
+ </column>
+ <column name="REGION_ID" type="VARCHAR(36)">
+ <constraints nullable="false" />
+ </column>
+ <column name="ROLE_ID" type="VARCHAR(36)">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <addPrimaryKey
+ constraintName="PK_USER_ACCOUNT_REGION_ROLE"
+ tableName="EXAMPLE_USER_ACCOUNT_REGION_ROLE"
+ columnNames="ID"
+ />
+
+ <addForeignKeyConstraint
+ constraintName="FK_USER_ACCOUNT_REGION_ROLE_USER_ACCOUNT"
+ baseTableName="EXAMPLE_USER_ACCOUNT_REGION_ROLE"
+ baseColumnNames="USER_ACCOUNT_ID"
+ referencedTableName="EXAMPLE_USER_ACCOUNT"
+ referencedColumnNames="ID"
+ />
+
+ <addForeignKeyConstraint
+ constraintName="FK_USER_ACCOUNT_REGION_ROLE_REGION"
+ baseTableName="EXAMPLE_USER_ACCOUNT_REGION_ROLE"
+ baseColumnNames="REGION_ID"
+ referencedTableName="EXAMPLE_REGION"
+ referencedColumnNames="ID"
+ />
+
+ <addForeignKeyConstraint
+ constraintName="FK_USER_ACCOUNT_REGION_ROLE_ROLE"
+ baseTableName="EXAMPLE_USER_ACCOUNT_REGION_ROLE"
+ baseColumnNames="ROLE_ID"
+ referencedTableName="KEYCLOAK_ROLE"
+ referencedColumnNames="ID"
+ />
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory
new file mode 100644
index 0000000..19058b3
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.keycloak.examples.domainextension.DomainExtensionProviderFactory
diff --git a/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.examples.domainextension.services.spi.ExampleServiceProviderFactory b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.examples.domainextension.services.spi.ExampleServiceProviderFactory
new file mode 100644
index 0000000..0b04865
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.examples.domainextension.services.spi.ExampleServiceProviderFactory
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.keycloak.examples.domainextension.services.spi.ExampleServiceProviderFactoryImpl
diff --git a/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100644
index 0000000..47b695e
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.keycloak.examples.domainextension.services.spi.ExampleSpi
diff --git a/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
new file mode 100644
index 0000000..f46b8a6
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.keycloak.examples.domainextension.rest.ExampleResourceProviderFactory
\ No newline at end of file
examples/providers/pom.xml 1(+1 -0)
diff --git a/examples/providers/pom.xml b/examples/providers/pom.xml
index 9557807..7153c45 100755
--- a/examples/providers/pom.xml
+++ b/examples/providers/pom.xml
@@ -36,5 +36,6 @@
<module>federation-provider</module>
<module>authenticator</module>
<module>rest</module>
+ <module>domain-extension</module>
</modules>
</project>