keycloak-aplcache

Changes

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/
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
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>