Merge branch 'release/2.2'
diff --git a/pom.xml b/pom.xml
index f935ca0..48023ee 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
 
   <groupId>edu.psu.swe.scim</groupId>
   <artifactId>scim-parent</artifactId>
-  <version>2.1</version>
+  <version>2.2</version>
   <packaging>pom</packaging>
   <name>SCIM - Parent</name>
   <description>Penn State's Open Source JavaEE implmentation of the SCIM version 2.0 specification (RFC7642, RFC7643 and RFC7644)</description>
@@ -13,8 +13,8 @@
     <maven.compiler.source>1.8</maven.compiler.source>
     <maven.compiler.target>1.8</maven.compiler.target>
 
-    <version.errai>4.0.0.Beta2</version.errai>
-    <version.gwt>2.8.0-rc2</version.gwt>
+    <version.errai>4.0.0.Beta4</version.errai>
+    <version.gwt>2.8.0</version.gwt>
     <version.lombok>1.16.10</version.lombok>
     <version.lombok.plugin>${version.lombok}.0</version.lombok.plugin>
     <version.restfuse>1.2.0</version.restfuse>
diff --git a/scim-client/pom.xml b/scim-client/pom.xml
index c1bb852..3c6b46a 100644
--- a/scim-client/pom.xml
+++ b/scim-client/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-parent</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
   <artifactId>scim-client</artifactId>
   <name>SCIM - Client</name>
@@ -36,6 +36,11 @@
         <groupId>edu.psu.swe.scim</groupId>
         <artifactId>scim-common</artifactId>
     </dependency>
+    <dependency>
+      <groupId>edu.psu.swe.commons</groupId>
+      <artifactId>commons-jaxrs</artifactId>
+      <version>1.17</version>
+    </dependency>
   </dependencies>
   
 </project>
diff --git a/scim-client/src/main/java/edu/psu/swe/scim/client/filter/FilterClient.java b/scim-client/src/main/java/edu/psu/swe/scim/client/filter/FilterClient.java
index b5e11ca..a66d09e 100644
--- a/scim-client/src/main/java/edu/psu/swe/scim/client/filter/FilterClient.java
+++ b/scim-client/src/main/java/edu/psu/swe/scim/client/filter/FilterClient.java
@@ -15,15 +15,21 @@
 import edu.psu.swe.scim.spec.protocol.filter.LogicalExpression;
 import edu.psu.swe.scim.spec.protocol.filter.LogicalOperator;
 import edu.psu.swe.scim.spec.protocol.filter.ValuePathExpression;
+import edu.psu.swe.scim.spec.protocol.search.Filter;
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
 public class FilterClient {
 
+  private FilterClient() {
+    
+  }
+  
   public abstract static class SimpleLogicalBuilder extends Builder {
     SimpleLogicalBuilder() {
     }
 
+    @Override
     public Builder and() {
       if (filterExpression == null) {
         throw new IllegalStateException();
@@ -37,6 +43,7 @@
       return this;
     }
 
+    @Override
     public Builder or() {
       if (filterExpression == null) {
         throw new IllegalStateException();
@@ -53,6 +60,7 @@
 
   public abstract static class ComplexLogicalBuilder extends SimpleLogicalBuilder {
 
+    @Override
     public Builder or(FilterExpression fe1) {
       if (filterExpression instanceof AttributeComparisonExpression) {
         LogicalExpression logicalExpression = new LogicalExpression();
@@ -70,6 +78,7 @@
       return handleLogicalExpression(logicalExpression, LogicalOperator.OR);
     }
     
+    @Override
     public Builder or(FilterExpression fe1, FilterExpression fe2) {
       LogicalExpression logicalExpression = new LogicalExpression();
       logicalExpression.setLeft(fe1);
@@ -79,6 +88,7 @@
       return handleLogicalExpression(logicalExpression, LogicalOperator.OR);
     }
 
+    @Override
     public Builder and(FilterExpression fe1, FilterExpression fe2) {
       LogicalExpression logicalExpression = new LogicalExpression();
       logicalExpression.setLeft(fe1);
@@ -88,6 +98,7 @@
       return handleLogicalExpression(logicalExpression, LogicalOperator.AND);
     }
     
+    @Override
     public Builder and(FilterExpression fe1) {
       if (filterExpression instanceof AttributeComparisonExpression) {
         LogicalExpression logicalExpression = new LogicalExpression();
@@ -110,6 +121,7 @@
   // that the next step is correct
   public static class ComparisonBuilder extends ComplexLogicalBuilder {
 
+    @Override
     public Builder equalTo(String key, String value) {
 
       AttributeReference ar = new AttributeReference(key);
@@ -120,6 +132,7 @@
       return this;
     }
 
+    @Override
     public Builder equalTo(String key, Boolean value) {
 
       AttributeReference ar = new AttributeReference(key);
@@ -130,6 +143,7 @@
       return this;
     }
 
+    @Override
     public Builder equalTo(String key, Date value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.EQ, value);
@@ -139,6 +153,7 @@
       return this;
     }
 
+    @Override
     public Builder equalTo(String key, LocalDate value) {
 
       AttributeReference ar = new AttributeReference(key);
@@ -149,6 +164,7 @@
       return this;
     }
 
+    @Override
     public Builder equalTo(String key, LocalDateTime value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.EQ, value);
@@ -158,6 +174,7 @@
       return this;
     }
 
+    @Override
     public <T extends Number> Builder equalTo(String key, T value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.EQ, value);
@@ -167,6 +184,7 @@
       return this;
     }
 
+    @Override
     public Builder equalNull(String key) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.EQ, null);
@@ -176,6 +194,7 @@
       return this;
     }
 
+    @Override
     public Builder notEqual(String key, String value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.NE, value);
@@ -185,6 +204,7 @@
       return this;
     }
 
+    @Override
     public Builder notEqual(String key, Boolean value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.NE, value);
@@ -194,6 +214,7 @@
       return this;
     }
 
+    @Override
     public Builder notEqual(String key, Date value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.NE, value);
@@ -203,6 +224,7 @@
       return this;
     }
 
+    @Override
     public Builder notEqual(String key, LocalDate value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.NE, value);
@@ -212,6 +234,7 @@
       return this;
     }
 
+    @Override
     public Builder notEqual(String key, LocalDateTime value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.NE, value);
@@ -221,6 +244,7 @@
       return this;
     }
 
+    @Override
     public <T extends Number> Builder notEqual(String key, T value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.NE, value);
@@ -230,6 +254,7 @@
       return this;
     }
 
+    @Override
     public Builder notEqualNull(String key) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.NE, null);
@@ -239,6 +264,7 @@
       return this;
     }
 
+    @Override
     public Builder endsWith(String key, String value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.EW, value);
@@ -248,6 +274,7 @@
       return this;
     }
 
+    @Override
     public Builder startsWith(String key, String value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.SW, value);
@@ -257,6 +284,7 @@
       return this;
     }
 
+    @Override
     public Builder contains(String key, String value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.CO, value);
@@ -266,6 +294,7 @@
       return this;
     }
 
+    @Override
     public <T extends Number> Builder greaterThan(String key, T value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.GT, value);
@@ -275,6 +304,7 @@
       return this;
     }
 
+    @Override
     public Builder greaterThan(String key, Date value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.GT, value);
@@ -284,6 +314,7 @@
       return this;
     }
 
+    @Override
     public Builder greaterThan(String key, LocalDate value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.GT, value);
@@ -293,6 +324,7 @@
       return this;
     }
 
+    @Override
     public Builder greaterThan(String key, LocalDateTime value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.GT, value);
@@ -302,6 +334,7 @@
       return this;
     }
 
+    @Override
     public <T extends Number> Builder greaterThanOrEquals(String key, T value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.GT, value);
@@ -311,6 +344,7 @@
       return this;
     }
 
+    @Override
     public Builder greaterThanOrEquals(String key, Date value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.GE, value);
@@ -320,6 +354,7 @@
       return this;
     }
 
+    @Override
     public Builder greaterThanOrEquals(String key, LocalDate value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.GE, value);
@@ -329,6 +364,7 @@
       return this;
     }
 
+    @Override
     public Builder greaterThanOrEquals(String key, LocalDateTime value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.GE, value);
@@ -338,6 +374,7 @@
       return this;
     }
 
+    @Override
     public <T extends Number> Builder lessThan(String key, T value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.LT, value);
@@ -347,6 +384,7 @@
       return this;
     }
 
+    @Override
     public Builder lessThan(String key, Date value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.LT, value);
@@ -356,6 +394,7 @@
       return this;
     }
 
+    @Override
     public Builder lessThan(String key, LocalDate value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.LT, value);
@@ -365,6 +404,7 @@
       return this;
     }
 
+    @Override
     public Builder lessThan(String key, LocalDateTime value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.LT, value);
@@ -374,6 +414,7 @@
       return this;
     }
 
+    @Override
     public <T extends Number> Builder lessThanOrEquals(String key, T value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.LE, value);
@@ -383,6 +424,7 @@
       return this;
     }
 
+    @Override
     public Builder lessThanOrEquals(String key, Date value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.LE, value);
@@ -392,6 +434,7 @@
       return this;
     }
 
+    @Override
     public Builder lessThanOrEquals(String key, LocalDate value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.LE, value);
@@ -401,6 +444,7 @@
       return this;
     }
 
+    @Override
     public Builder lessThanOrEquals(String key, LocalDateTime value) {
       AttributeReference ar = new AttributeReference(key);
       FilterExpression filterExpression = new AttributeComparisonExpression(ar, CompareOperator.LE, value);
@@ -410,6 +454,7 @@
       return this;
     }
 
+    @Override
     public Builder not(FilterExpression expression) {
       GroupExpression groupExpression = new GroupExpression();
 
@@ -523,7 +568,7 @@
       if (filterExpression == null) {
         filterExpression = expression;
       } else if (filterExpression instanceof AttributeComparisonExpression) {
-        System.out.println("Adding a logical expression as the new root");
+        log.info("Adding a logical expression as the new root");
 
         log.info("Setting as left: " + filterExpression.toFilter());
         expression.setLeft(filterExpression);
@@ -531,7 +576,7 @@
 
         filterExpression = expression;
       } else if (filterExpression instanceof LogicalExpression) {
-        System.out.println("filter exression is a logical expression");
+        log.info("filter exression is a logical expression");
         LogicalExpression le = (LogicalExpression) filterExpression;
 
         if (le.getLeft() == null) {
@@ -548,7 +593,7 @@
           filterExpression = newRoot;
         }
       } else if (filterExpression instanceof GroupExpression) {
-        System.out.println("Found group expression");
+        log.info("Found group expression");
         LogicalExpression newRoot = new LogicalExpression();
         newRoot.setLeft(filterExpression);
         newRoot.setRight(expression);
@@ -579,10 +624,20 @@
       }
     }
 
-    public String build() throws UnsupportedEncodingException {
+    @Override
+    public String toString() {
       
       String filterString = filterExpression.toFilter();
-      return URLEncoder.encode(filterString, "UTF-8").replace("+", "%20");
+      try {
+        return URLEncoder.encode(filterString, "UTF-8").replace("+", "%20");
+      } catch (UnsupportedEncodingException e) {
+        log.error("Unsupported encoding:", e);
+        return null;
+      }
+    }
+    
+    public Filter build() {
+      return new Filter(filterExpression);
     }
 
     public FilterExpression filter() {
diff --git a/scim-client/src/main/java/edu/psu/swe/scim/client/filter/exception/InvalidValueFilterExpression.java b/scim-client/src/main/java/edu/psu/swe/scim/client/filter/exception/InvalidValueFilterExpression.java
index b892f84..338b2e7 100644
--- a/scim-client/src/main/java/edu/psu/swe/scim/client/filter/exception/InvalidValueFilterExpression.java
+++ b/scim-client/src/main/java/edu/psu/swe/scim/client/filter/exception/InvalidValueFilterExpression.java
@@ -1,6 +1,9 @@
 package edu.psu.swe.scim.client.filter.exception;
 
 public class InvalidValueFilterExpression extends Exception {
+
+  private static final long serialVersionUID = -5165945768240326983L;
+
   public InvalidValueFilterExpression(String what) {
     super(what);
   }
diff --git a/scim-client/src/main/java/edu/psu/swe/scim/client/rest/BaseScimClient.java b/scim-client/src/main/java/edu/psu/swe/scim/client/rest/BaseScimClient.java
new file mode 100644
index 0000000..ea1b873
--- /dev/null
+++ b/scim-client/src/main/java/edu/psu/swe/scim/client/rest/BaseScimClient.java
@@ -0,0 +1,264 @@
+package edu.psu.swe.scim.client.rest;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.Response;
+
+import edu.psu.swe.commons.jaxrs.RestCall;
+import edu.psu.swe.commons.jaxrs.exceptions.BackingStoreChangedException;
+import edu.psu.swe.commons.jaxrs.exceptions.ConflictingDataException;
+import edu.psu.swe.commons.jaxrs.exceptions.RestClientException;
+import edu.psu.swe.commons.jaxrs.exceptions.RestServerException;
+import edu.psu.swe.commons.jaxrs.exceptions.ServiceAuthException;
+import edu.psu.swe.commons.jaxrs.utilities.RestClientUtil;
+import edu.psu.swe.scim.spec.annotation.ScimResourceType;
+import edu.psu.swe.scim.spec.protocol.BaseResourceTypeResource;
+import edu.psu.swe.scim.spec.protocol.Constants;
+import edu.psu.swe.scim.spec.protocol.attribute.AttributeReference;
+import edu.psu.swe.scim.spec.protocol.attribute.AttributeReferenceListWrapper;
+import edu.psu.swe.scim.spec.protocol.data.ListResponse;
+import edu.psu.swe.scim.spec.protocol.data.PatchRequest;
+import edu.psu.swe.scim.spec.protocol.data.SearchRequest;
+import edu.psu.swe.scim.spec.protocol.search.Filter;
+import edu.psu.swe.scim.spec.protocol.search.SortOrder;
+import edu.psu.swe.scim.spec.resources.ScimResource;
+
+public abstract class BaseScimClient<T extends ScimResource> implements AutoCloseable {
+
+  private final Client client;
+  private final Class<T> scimResourceClass;
+  private final GenericType<ListResponse<T>> scimResourceListResponseGenericType;
+  private final WebTarget target;
+  private final ScimClient scimClient;
+  private RestCall invoke = Invocation::invoke;
+
+  public BaseScimClient(Client client, String baseUrl, Class<T> scimResourceClass, GenericType<ListResponse<T>> scimResourceListGenericType) throws IllegalArgumentException {
+    ScimResourceType scimResourceType = scimResourceClass.getAnnotation(ScimResourceType.class);
+    String endpoint = scimResourceType != null ? scimResourceType.endpoint() : null;
+
+    if (endpoint == null) {
+      throw new IllegalArgumentException("scimResourceClass: " + scimResourceClass.getSimpleName() + " must have annotation " + ScimResourceType.class.getSimpleName() + " and annotation must have non-null endpoint");
+    }
+    this.client = client;
+    this.scimResourceClass = scimResourceClass;
+    this.scimResourceListResponseGenericType = scimResourceListGenericType;
+    this.target = this.client.target(baseUrl).path(endpoint);
+    this.scimClient = new ScimClient();
+  }
+
+  public BaseScimClient(Client client, String baseUrl, Class<T> scimResourceClass, GenericType<ListResponse<T>> scimResourceListGenericType, RestCall invoke) throws IllegalArgumentException {
+    this(client, baseUrl, scimResourceClass, scimResourceListGenericType);
+
+    this.invoke = invoke;
+  }
+
+  @Override
+  public void close() {
+    this.client.close();
+  }
+
+  public Optional<T> getById(String id) throws RestClientException, ProcessingException, IllegalStateException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    return this.getById(id, null, null);
+  }
+
+  public Optional<T> getById(String id, AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes) throws RestClientException, ProcessingException, IllegalStateException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    Optional<T> resource;
+    Response response = this.scimClient.getById(id, attributes, excludedAttributes);
+
+    try {
+      resource = RestClientUtil.readEntity(response, scimResourceClass);
+    } finally {
+      RestClientUtil.close(response);
+    }
+    return resource;
+  }
+
+  public ListResponse<T> query(AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes, Filter filter, AttributeReference sortBy, SortOrder sortOrder, Integer startIndex, Integer count) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    ListResponse<T> listResponse;;
+    Response response = this.scimClient.query(attributes, excludedAttributes, filter, sortBy, sortOrder, startIndex, count);
+    listResponse = handleResponse(response, scimResourceListResponseGenericType, response::readEntity);
+
+    return listResponse;
+  }
+
+  public void create(T resource) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    this.create(resource, null, null);
+  }
+
+  public void create(T resource, AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    Response response = this.scimClient.create(resource, attributes, excludedAttributes);
+
+    handleResponse(response);
+  }
+
+  public ListResponse<T> find(SearchRequest searchRequest) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    ListResponse<T> listResponse;
+    Response response = this.scimClient.find(searchRequest);
+    listResponse = handleResponse(response, scimResourceListResponseGenericType, response::readEntity);
+
+    return listResponse;
+  }
+
+  public void update(String id, T resource) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    this.update(id, resource, null, null);
+  }
+
+  public void update(String id, T resource, AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    Response response = this.scimClient.update(resource, id, attributes, excludedAttributes);
+
+    handleResponse(response);
+  }
+
+  public void patch(PatchRequest patchRequest) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    Response response = this.scimClient.patch(patchRequest);
+
+    handleResponse(response);
+  }
+
+  public void delete(String id) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    Response response = this.scimClient.delete(id);
+
+    handleResponse(response);
+  }
+
+  private static <E, T> E handleResponse(Response response, T type, Function<T, E> readEntity) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    E entity;
+
+    try {
+      RestClientUtil.checkForSuccess(response);
+
+      entity = readEntity.apply(type);
+    } finally {
+      RestClientUtil.close(response);
+    }
+    return entity;
+  }
+
+  private static void handleResponse(Response response) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    try {
+      RestClientUtil.checkForSuccess(response);
+    } finally {
+      RestClientUtil.close(response);
+    }
+  }
+
+  public RestCall getInvoke() {
+    return this.invoke;
+  }
+
+  public void setInvoke(RestCall invoke) {
+    this.invoke = invoke;
+  }
+
+  private class ScimClient implements BaseResourceTypeResource<T> {
+
+    private static final String ATTRIBUTES_QUERY_PARAM = "attributes";
+    private static final String EXCLUDED_ATTRIBUTES_QUERY_PARAM = "excludedAttributes";
+    private static final String FILTER_QUERY_PARAM = "filter";
+    private static final String SORT_BY_QUERY_PARAM = "sortBy";
+    private static final String SORT_ORDER_QUERY_PARAM = "sortOrder";
+    private static final String START_INDEX_QUERY_PARAM = "startIndex";
+    private static final String COUNT_QUERY_PARAM = "count";
+
+    @Override
+    public Response getById(String id, AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes) throws RestClientException {
+      Response response;
+      Invocation request = BaseScimClient.this.target
+          .path(id)
+          .queryParam(ATTRIBUTES_QUERY_PARAM, attributes)
+          .queryParam(EXCLUDED_ATTRIBUTES_QUERY_PARAM, excludedAttributes)
+          .request(Constants.SCIM_CONTENT_TYPE)
+          .buildGet();
+      response = invoke.apply(request);
+
+      return response;
+    }
+
+    @Override
+    public Response query(AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes, Filter filter, AttributeReference sortBy, SortOrder sortOrder, Integer startIndex, Integer count) throws RestClientException {
+      Response response;
+      Invocation request = BaseScimClient.this.target
+          .queryParam(ATTRIBUTES_QUERY_PARAM, attributes)
+          .queryParam(EXCLUDED_ATTRIBUTES_QUERY_PARAM, excludedAttributes)
+          .queryParam(FILTER_QUERY_PARAM, filter)
+          .queryParam(SORT_BY_QUERY_PARAM, sortBy)
+          .queryParam(SORT_ORDER_QUERY_PARAM, sortOrder != null ? sortOrder.name() : null)
+          .queryParam(START_INDEX_QUERY_PARAM, startIndex)
+          .queryParam(COUNT_QUERY_PARAM, count)
+          .request(Constants.SCIM_CONTENT_TYPE)
+          .buildGet();
+      response = invoke.apply(request);
+
+      return response;
+    }
+
+    @Override
+    public Response create(T resource, AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes) throws RestClientException {
+      Response response;
+      Invocation request = BaseScimClient.this.target
+          .queryParam(ATTRIBUTES_QUERY_PARAM, attributes)
+          .queryParam(EXCLUDED_ATTRIBUTES_QUERY_PARAM, excludedAttributes)
+          .request(Constants.SCIM_CONTENT_TYPE)
+          .buildPost(Entity.entity(resource, Constants.SCIM_CONTENT_TYPE));
+      response = invoke.apply(request);
+
+      return response;
+    }
+
+    @Override
+    public Response find(SearchRequest searchRequest) throws RestClientException {
+      Response response;
+      Invocation request = BaseScimClient.this.target
+          .path(".search")
+          .request(Constants.SCIM_CONTENT_TYPE)
+          .buildPost(Entity.entity(searchRequest, Constants.SCIM_CONTENT_TYPE));
+      response = invoke.apply(request);
+
+      return response;
+    }
+
+    @Override
+    public Response update(T resource, String id, AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes) throws RestClientException {
+      Response response;
+      Invocation request = BaseScimClient.this.target
+          .path(id)
+          .queryParam(ATTRIBUTES_QUERY_PARAM, attributes)
+          .queryParam(EXCLUDED_ATTRIBUTES_QUERY_PARAM, excludedAttributes)
+          .request(Constants.SCIM_CONTENT_TYPE)
+          .buildPut(Entity.entity(resource, Constants.SCIM_CONTENT_TYPE));
+      response = invoke.apply(request);
+
+      return response;
+    }
+
+    @Override
+    public Response patch(PatchRequest patchRequest) throws RestClientException {
+      Response response;
+      Invocation request = BaseScimClient.this.target
+          .request(Constants.SCIM_CONTENT_TYPE)
+          .build("PATCH", Entity.entity(patchRequest, Constants.SCIM_CONTENT_TYPE));
+      response = invoke.apply(request);
+
+      return response;
+    }
+
+    @Override
+    public Response delete(String id) throws RestClientException {
+      Response response;
+      Invocation request = BaseScimClient.this.target
+          .path(id)
+          .request(Constants.SCIM_CONTENT_TYPE)
+          .buildDelete();
+      response = invoke.apply(request);
+
+      return response;
+    }
+  }
+}
diff --git a/scim-client/src/main/java/edu/psu/swe/scim/client/rest/ResourceTypesClient.java b/scim-client/src/main/java/edu/psu/swe/scim/client/rest/ResourceTypesClient.java
new file mode 100644
index 0000000..e6c7cf7
--- /dev/null
+++ b/scim-client/src/main/java/edu/psu/swe/scim/client/rest/ResourceTypesClient.java
@@ -0,0 +1,87 @@
+package edu.psu.swe.scim.client.rest;
+
+import java.util.List;
+import java.util.Optional;
+
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.Response;
+
+import edu.psu.swe.commons.jaxrs.exceptions.BackingStoreChangedException;
+import edu.psu.swe.commons.jaxrs.exceptions.ConflictingDataException;
+import edu.psu.swe.commons.jaxrs.exceptions.RestClientException;
+import edu.psu.swe.commons.jaxrs.exceptions.RestServerException;
+import edu.psu.swe.commons.jaxrs.exceptions.ServiceAuthException;
+import edu.psu.swe.commons.jaxrs.utilities.RestClientUtil;
+import edu.psu.swe.scim.spec.protocol.ResourceTypesResource;
+import edu.psu.swe.scim.spec.schema.ResourceType;
+
+public class ResourceTypesClient implements AutoCloseable {
+
+  private static final GenericType<List<ResourceType>> LIST_RESOURCE_TYPE = new GenericType<List<ResourceType>>(){};
+
+  private final Client client;
+  private final WebTarget target;
+  private final ResourceTypesResourceClient resourceTypesResourceClient = new ResourceTypesResourceClient();
+
+  public ResourceTypesClient(Client client, String baseUrl) {
+    this.client = client;
+    this.target = this.client.target(baseUrl).path("ResourceTypes");
+  }
+
+  public List<ResourceType> getAllResourceTypes(String filter) throws RestClientException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    List<ResourceType> resourceTypes;
+    Response response = this.resourceTypesResourceClient.getAllResourceTypes(filter);
+
+    try {
+      RestClientUtil.checkForSuccess(response);
+
+      resourceTypes = response.readEntity(LIST_RESOURCE_TYPE);
+    } finally {
+      RestClientUtil.close(response);
+    }
+    return resourceTypes;
+  }
+
+  public Optional<ResourceType> getResourceType(String name) throws RestClientException, ProcessingException, IllegalStateException, RestServerException, BackingStoreChangedException, ConflictingDataException, ServiceAuthException {
+    Optional<ResourceType> resourceType;
+    Response response = this.resourceTypesResourceClient.getResourceType(name);
+
+    try {
+      resourceType = RestClientUtil.readEntity(response, ResourceType.class);
+    } finally {
+      RestClientUtil.close(response);
+    }
+    return resourceType;
+  }
+
+  @Override
+  public void close() throws Exception {
+    this.client.close();
+  }
+
+  private class ResourceTypesResourceClient implements ResourceTypesResource {
+
+    @Override
+    public Response getAllResourceTypes(String filter) throws RestClientException {
+      Response response = ResourceTypesClient.this.target
+          .queryParam("filter", filter)
+          .request("application/scim+json")
+          .get();
+
+      return response;
+    }
+
+    @Override
+    public Response getResourceType(String name) throws RestClientException {
+      Response response = ResourceTypesClient.this.target
+          .path(name)
+          .request("application/scim+json")
+          .get();
+
+      return response;
+    }
+  }
+}
diff --git a/scim-client/src/main/java/edu/psu/swe/scim/client/rest/ScimGroupClient.java b/scim-client/src/main/java/edu/psu/swe/scim/client/rest/ScimGroupClient.java
new file mode 100644
index 0000000..7a29ce7
--- /dev/null
+++ b/scim-client/src/main/java/edu/psu/swe/scim/client/rest/ScimGroupClient.java
@@ -0,0 +1,21 @@
+package edu.psu.swe.scim.client.rest;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.core.GenericType;
+
+import edu.psu.swe.commons.jaxrs.RestCall;
+import edu.psu.swe.scim.spec.protocol.data.ListResponse;
+import edu.psu.swe.scim.spec.resources.ScimGroup;
+
+public class ScimGroupClient extends BaseScimClient<ScimGroup> {
+
+  private static final GenericType<ListResponse<ScimGroup>> SCIM_GROUP_LIST = new GenericType<ListResponse<ScimGroup>>(){};
+
+  public ScimGroupClient(Client client, String baseUrl) {
+    super(client, baseUrl, ScimGroup.class, SCIM_GROUP_LIST);
+  }
+
+  public ScimGroupClient(Client client, String baseUrl, RestCall invoke) {
+    super(client, baseUrl, ScimGroup.class, SCIM_GROUP_LIST, invoke);
+  }
+}
diff --git a/scim-client/src/main/java/edu/psu/swe/scim/client/rest/ScimUserClient.java b/scim-client/src/main/java/edu/psu/swe/scim/client/rest/ScimUserClient.java
new file mode 100644
index 0000000..46f99f7
--- /dev/null
+++ b/scim-client/src/main/java/edu/psu/swe/scim/client/rest/ScimUserClient.java
@@ -0,0 +1,21 @@
+package edu.psu.swe.scim.client.rest;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.core.GenericType;
+
+import edu.psu.swe.commons.jaxrs.RestCall;
+import edu.psu.swe.scim.spec.protocol.data.ListResponse;
+import edu.psu.swe.scim.spec.resources.ScimUser;
+
+public class ScimUserClient extends BaseScimClient<ScimUser> {
+
+  private static final GenericType<ListResponse<ScimUser>> LIST_SCIM_USER = new GenericType<ListResponse<ScimUser>>(){};
+
+  public ScimUserClient(Client client, String baseUrl) {
+    super(client, baseUrl, ScimUser.class, LIST_SCIM_USER);
+  }
+
+  public ScimUserClient(Client client, String baseUrl, RestCall invoke) {
+    super(client, baseUrl, ScimUser.class, LIST_SCIM_USER, invoke);
+  }
+}
diff --git a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderGreaterTest.java b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderGreaterTest.java
index 416bdc9..bea5621 100644
--- a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderGreaterTest.java
+++ b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderGreaterTest.java
@@ -44,7 +44,7 @@
   @Parameters(method="getIntExamples")
   public void testGreaterThanT_Int(Integer arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().greaterThan("dog.weight", arg).build();
+    String encoded = FilterClient.builder().greaterThan("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
@@ -52,7 +52,7 @@
   @Parameters(method="getLongExamples")
   public void testGreaterThanT_Long(Long arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().greaterThan("dog.weight", arg).build();
+    String encoded = FilterClient.builder().greaterThan("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
@@ -60,7 +60,7 @@
   @Parameters(method="getFloatExamples")
   public void testGreaterThanT_Float(Float arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().greaterThan("dog.weight", arg).build();
+    String encoded = FilterClient.builder().greaterThan("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
@@ -68,25 +68,25 @@
   @Parameters(method="getDoubleExamples")
   public void testGreaterThanT_Double(Double arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().greaterThan("dog.weight", arg).build();
+    String encoded = FilterClient.builder().greaterThan("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
   @Test
   public void testGreaterThanDate() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().greaterThan("dog.dob", new Date()).build();
+    String encoded = FilterClient.builder().greaterThan("dog.dob", new Date()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testGreaterThanLocalDate() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().greaterThan("dog.dob", LocalDate.now()).build();
+    String encoded = FilterClient.builder().greaterThan("dog.dob", LocalDate.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testGreaterThanLocalDateTime() throws UnsupportedEncodingException, FilterParseException  {
-    String encoded = FilterClient.builder().greaterThan("dog.dob", LocalDateTime.now()).build();
+    String encoded = FilterClient.builder().greaterThan("dog.dob", LocalDateTime.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
@@ -94,7 +94,7 @@
   @Parameters(method="getIntExamples")
   public void testGreaterThanOrEqualsT_Int(Integer arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().greaterThanOrEquals("dog.weight", arg).build();
+    String encoded = FilterClient.builder().greaterThanOrEquals("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
@@ -102,7 +102,7 @@
   @Parameters(method="getLongExamples")
   public void testGreaterThanOrEqualsT_Long(Long arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().greaterThanOrEquals("dog.weight", arg).build();
+    String encoded = FilterClient.builder().greaterThanOrEquals("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
@@ -110,7 +110,7 @@
   @Parameters(method="getFloatExamples")
   public void testGreaterThanOrEqualsT_Float(Float arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().greaterThanOrEquals("dog.weight", arg).build();
+    String encoded = FilterClient.builder().greaterThanOrEquals("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
@@ -118,25 +118,25 @@
   @Parameters(method="getDoubleExamples")
   public void testGreaterThanOrEqualsT_Double(Double arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().greaterThanOrEquals("dog.weight", arg).build();
+    String encoded = FilterClient.builder().greaterThanOrEquals("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
   @Test
   public void testGreaterThanOrEqualsDate() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().greaterThanOrEquals("dog.dob", new Date()).build();
+    String encoded = FilterClient.builder().greaterThanOrEquals("dog.dob", new Date()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testGreaterThanOrEqualsLocalDate()  throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().greaterThanOrEquals("dog.dob", LocalDate.now()).build();
+    String encoded = FilterClient.builder().greaterThanOrEquals("dog.dob", LocalDate.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testGreaterThanOrEqualsLocalDateTime() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().greaterThanOrEquals("dog.dob", LocalDateTime.now()).build();
+    String encoded = FilterClient.builder().greaterThanOrEquals("dog.dob", LocalDateTime.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
diff --git a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderLessThanTest.java b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderLessThanTest.java
index cc748b0..b811901 100644
--- a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderLessThanTest.java
+++ b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderLessThanTest.java
@@ -44,7 +44,7 @@
   @Parameters(method="getIntExamples")
   public void testLessThanT_Int(Integer arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().lessThan("dog.weight", arg).build();
+    String encoded = FilterClient.builder().lessThan("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
@@ -52,7 +52,7 @@
   @Parameters(method="getLongExamples")
   public void testLessThanT_Long(Long arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().lessThan("dog.weight", arg).build();
+    String encoded = FilterClient.builder().lessThan("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
@@ -60,7 +60,7 @@
   @Parameters(method="getFloatExamples")
   public void testLessThanT_Float(Float arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().lessThan("dog.weight", arg).build();
+    String encoded = FilterClient.builder().lessThan("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
@@ -68,26 +68,26 @@
   @Parameters(method="getDoubleExamples")
   public void testLessThanT_Double(Double arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().lessThan("dog.weight", arg).build();
+    String encoded = FilterClient.builder().lessThan("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
   
   @Test
   public void testLessThanDate() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().lessThan("dog.dob", new Date()).build();
+    String encoded = FilterClient.builder().lessThan("dog.dob", new Date()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testLessThanLocalDate() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().lessThan("dog.dob", LocalDate.now()).build();
+    String encoded = FilterClient.builder().lessThan("dog.dob", LocalDate.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testLessThanLocalDateTime() throws UnsupportedEncodingException, FilterParseException  {
-    String encoded = FilterClient.builder().lessThan("dog.dob", LocalDateTime.now()).build();
+    String encoded = FilterClient.builder().lessThan("dog.dob", LocalDateTime.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
@@ -95,7 +95,7 @@
   @Parameters(method="getIntExamples")
   public void testLessThanOrEqualsT_Int(Integer arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().lessThanOrEquals("dog.weight", arg).build();
+    String encoded = FilterClient.builder().lessThanOrEquals("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
@@ -103,7 +103,7 @@
   @Parameters(method="getLongExamples")
   public void testLessThanOrEqualsT_Long(Long arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().lessThanOrEquals("dog.weight", arg).build();
+    String encoded = FilterClient.builder().lessThanOrEquals("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
@@ -111,7 +111,7 @@
   @Parameters(method="getFloatExamples")
   public void testLessThanOrEqualsT_Float(Float arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().lessThanOrEquals("dog.weight", arg).build();
+    String encoded = FilterClient.builder().lessThanOrEquals("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
@@ -119,25 +119,25 @@
   @Parameters(method="getDoubleExamples")
   public void testLessThanOrEqualsT_Double(Double arg) throws UnsupportedEncodingException, FilterParseException {
     
-    String encoded = FilterClient.builder().lessThanOrEquals("dog.weight", arg).build();
+    String encoded = FilterClient.builder().lessThanOrEquals("dog.weight", arg).toString();
     Filter filter = new Filter(decode(encoded));
   }
   
   @Test
   public void testLessThanOrEqualsDate() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().lessThanOrEquals("dog.dob", new Date()).build();
+    String encoded = FilterClient.builder().lessThanOrEquals("dog.dob", new Date()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testLessThanOrEqualsLocalDate()  throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().lessThanOrEquals("dog.dob", LocalDate.now()).build();
+    String encoded = FilterClient.builder().lessThanOrEquals("dog.dob", LocalDate.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testLessThanOrEqualsLocalDateTime() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().lessThanOrEquals("dog.dob", LocalDateTime.now()).build();
+    String encoded = FilterClient.builder().lessThanOrEquals("dog.dob", LocalDateTime.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
diff --git a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderStringTests.java b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderStringTests.java
index 28912e5..b0c094d 100644
--- a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderStringTests.java
+++ b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderStringTests.java
@@ -15,19 +15,19 @@
 
   @Test
   public void testEndsWith() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().endsWith("address.streetAddress", "Way").build();
+    String encoded = FilterClient.builder().endsWith("address.streetAddress", "Way").toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testStartsWith()  throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().startsWith("address.streetAddress", "133").build();
+    String encoded = FilterClient.builder().startsWith("address.streetAddress", "133").toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testContains()  throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().contains("address.streetAddress", "MacDuff").build();
+    String encoded = FilterClient.builder().contains("address.streetAddress", "MacDuff").toString();
     Filter filter = new Filter(decode(encoded));
   }
 
diff --git a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTest.java b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTest.java
index dc5bef3..def52ec 100644
--- a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTest.java
+++ b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTest.java
@@ -59,7 +59,7 @@
   @Test
   public void testSimpleAnd() throws UnsupportedEncodingException, FilterParseException {
   
-    String encoded = FilterClient.builder().equalTo("name.givenName", "Bilbo").and().equalTo("name.familyName", "Baggins").build();
+    String encoded = FilterClient.builder().equalTo("name.givenName", "Bilbo").and().equalTo("name.familyName", "Baggins").toString();
   
     String decoded = decode(encoded);
     Filter filter = new Filter(decoded); 
@@ -68,7 +68,7 @@
   @Test
   public void testSimpleOr() throws UnsupportedEncodingException, FilterParseException {
   
-    String encoded = FilterClient.builder().equalTo("name.givenName", "Bilbo").or().equalTo("name.familyName", "Baggins").build();
+    String encoded = FilterClient.builder().equalTo("name.givenName", "Bilbo").or().equalTo("name.familyName", "Baggins").toString();
   
     String decoded = decode(encoded);
     Filter filter = new Filter(decoded); 
@@ -77,7 +77,7 @@
   @Test
   public void testAndOrChain() throws UnsupportedEncodingException, FilterParseException {
   
-    String encoded = FilterClient.builder().equalTo("name.givenName", "Bilbo").or().equalTo("name.givenName", "Frodo").and().equalTo("name.familyName", "Baggins").build();
+    String encoded = FilterClient.builder().equalTo("name.givenName", "Bilbo").or().equalTo("name.givenName", "Frodo").and().equalTo("name.familyName", "Baggins").toString();
   
     String decoded = decode(encoded);
     Filter filter = new Filter(decoded); 
@@ -86,7 +86,7 @@
   @Test
   public void testAndOrChainComplex() throws UnsupportedEncodingException, FilterParseException {
   
-    String encoded = FilterClient.builder().equalTo("name.givenName", "Bilbo").and(FilterClient.builder().equalTo("name.givenName", "Frodo").and().equalTo("name.familyName", "Baggins").filter()).build();
+    String encoded = FilterClient.builder().equalTo("name.givenName", "Bilbo").and(FilterClient.builder().equalTo("name.givenName", "Frodo").and().equalTo("name.familyName", "Baggins").filter()).toString();
   
     String decoded = decode(encoded);
     Filter filter = new Filter(decoded); 
@@ -95,7 +95,7 @@
   @Test
   public void testOrAndChainComplex() throws UnsupportedEncodingException, FilterParseException {
   
-    String encoded = FilterClient.builder().equalTo("name.givenName", "Bilbo").or(FilterClient.builder().equalTo("name.givenName", "Frodo").and().equalTo("name.familyName", "Baggins").filter()).build();
+    String encoded = FilterClient.builder().equalTo("name.givenName", "Bilbo").or(FilterClient.builder().equalTo("name.givenName", "Frodo").and().equalTo("name.familyName", "Baggins").filter()).toString();
   
     String decoded = decode(encoded);
     Filter filter = new Filter(decoded); 
@@ -107,7 +107,7 @@
     FilterClient.Builder b1 = FilterClient.builder().equalTo("name.givenName", "Bilbo").or().equalTo("name.givenName", "Frodo").and().equalTo("name.familyName", "Baggins");
     FilterClient.Builder b2 = FilterClient.builder().equalTo("address.streetAddress", "Underhill").or().equalTo("address.streetAddress", "Overhill").and().equalTo("address.postalCode", "16803");
     
-    String encoded = FilterClient.builder().and(b1.filter(), b2.filter()).build();
+    String encoded = FilterClient.builder().and(b1.filter(), b2.filter()).toString();
     
     String decoded = decode(encoded);
     Filter filter = new Filter(decoded); 
@@ -117,7 +117,7 @@
   public void testNot() throws UnsupportedEncodingException, FilterParseException {
     FilterClient.Builder b1 = FilterClient.builder().equalTo("name.givenName", "Bilbo").or().equalTo("name.givenName", "Frodo").and().equalTo("name.familyName", "Baggins");
 
-    String encoded = FilterClient.builder().not(b1.filter()).build();
+    String encoded = FilterClient.builder().not(b1.filter()).toString();
     
     String decoded = decode(encoded);
     Filter filter = new Filter(decoded); 
@@ -129,7 +129,7 @@
     FilterClient.Builder b1 = FilterClient.builder().equalTo("name.givenName", "Bilbo").or().equalTo("name.givenName", "Frodo").and().equalTo("name.familyName", "Baggins");
     FilterClient.Builder b2 = FilterClient.builder().attributeHas("address", b1.filter());
     
-    String encoded = b2.build();
+    String encoded = b2.toString();
     
     String decoded = decode(encoded);
     Filter filter = new Filter(decoded); 
@@ -144,7 +144,7 @@
     
     FilterClient.Builder b3 = FilterClient.builder().attributeHas("address", b2.filter());
    
-    String encoded = b3.build();
+    String encoded = b3.toString();
     
     String decoded = decode(encoded);
     Filter filter = new Filter(decoded); 
@@ -159,7 +159,7 @@
     FilterClient.Builder b3 = FilterClient.builder().equalTo("name.giveName", "Gandalf").and(b2.filter());
     FilterClient.Builder b4 = FilterClient.builder().attributeHas("address", b3.filter());
    
-    String encoded = b4.build();
+    String encoded = b4.toString();
     
     String decoded = decode(encoded);
     Filter filter = new Filter(decoded); 
@@ -167,7 +167,7 @@
   //@Test
 //  public void testNotSingleArg() throws UnsupportedEncodingException, FilterParseException {
 // 
-//     String encoded = filterBuilder.not(attributeComparisonExpression, LogicalOperator.AND, attributeComparisonExpression2).build();
+//     String encoded = filterBuilder.not(attributeComparisonExpression, LogicalOperator.AND, attributeComparisonExpression2).toString();
 // 
 //     String decoded = decode(encoded);
 //     Filter filter = new Filter(decoded);
@@ -176,7 +176,7 @@
 //  //@Test
 //  public void testAnd() throws UnsupportedEncodingException, FilterParseException {
 //
-//    String encoded = filterBuilder.and(attributeComparisonExpression, attributeComparisonExpression2).build();
+//    String encoded = filterBuilder.and(attributeComparisonExpression, attributeComparisonExpression2).toString();
 //    
 //    String decoded = decode(encoded);
 //    Filter filter = new Filter(decoded);
@@ -188,7 +188,7 @@
 //    String encoded = filterBuilder.equalTo("addresses.postalCode", "16801")
 //                                  .and()
 //                                  .or(attributeComparisonExpression, attributeComparisonExpression2)
-//                                  .build();
+//                                  .toString();
 //
 //    log.info(encoded);
 //    
diff --git a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTestEquals.java b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTestEquals.java
index be4d97c..6cbe829 100644
--- a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTestEquals.java
+++ b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTestEquals.java
@@ -20,65 +20,65 @@
   
   @Test
   public void testEqualToStringString() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().equalTo("address.streetAddress", "7714 Sassafrass Way").build();
+    String encoded = FilterClient.builder().equalTo("address.streetAddress", "7714 Sassafrass Way").toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testEqualToStringBoolean() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().equalTo("address.active", true).build();
+    String encoded = FilterClient.builder().equalTo("address.active", true).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testEqualToStringDate() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().equalTo("date.date", new Date()).build();
+    String encoded = FilterClient.builder().equalTo("date.date", new Date()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testEqualToStringLocalDate() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().equalTo("date.date", LocalDate.now()).build();
+    String encoded = FilterClient.builder().equalTo("date.date", LocalDate.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testEqualToStringLocalDateTime() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().equalTo("date.date", LocalDateTime.now()).build();
+    String encoded = FilterClient.builder().equalTo("date.date", LocalDateTime.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testEqualToStringInteger() throws UnsupportedEncodingException, FilterParseException {
     int i = 10;
-    String encoded = FilterClient.builder().equalTo("int.int", i).build();
+    String encoded = FilterClient.builder().equalTo("int.int", i).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testEqualToStringLong() throws UnsupportedEncodingException, FilterParseException {
     long i = 10l;
-    String encoded = FilterClient.builder().equalTo("long.long", i).build();
+    String encoded = FilterClient.builder().equalTo("long.long", i).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testEqualToStringFloat() throws UnsupportedEncodingException, FilterParseException {
     float i = 10.2f;
-    String encoded = FilterClient.builder().equalTo("long.long", i).build();
+    String encoded = FilterClient.builder().equalTo("long.long", i).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testEqualToStringDouble() throws UnsupportedEncodingException, FilterParseException {
     double i = 10.2;
-    String encoded = FilterClient.builder().equalTo("long.long", i).build();
+    String encoded = FilterClient.builder().equalTo("long.long", i).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testEqualNull() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().equalNull("null.null").build();
+    String encoded = FilterClient.builder().equalNull("null.null").toString();
     Filter filter = new Filter(decode(encoded));
   }
   
diff --git a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTestNotEquals.java b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTestNotEquals.java
index 9bba104..0c2bcf5 100644
--- a/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTestNotEquals.java
+++ b/scim-client/src/test/java/edu/psu/swe/scim/client/filter/FilterBuilderTestNotEquals.java
@@ -17,65 +17,65 @@
 
   @Test
   public void testNotnotEqualStringString() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().notEqual("address.streetAddress", "7714 Sassafrass Way").build();
+    String encoded = FilterClient.builder().notEqual("address.streetAddress", "7714 Sassafrass Way").toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testNotnotEqualStringBoolean() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().notEqual("address.active", true).build();
+    String encoded = FilterClient.builder().notEqual("address.active", true).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testNotnotEqualStringDate() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().notEqual("date.date", new Date()).build();
+    String encoded = FilterClient.builder().notEqual("date.date", new Date()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testNotnotEqualStringLocalDate() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().notEqual("date.date", LocalDate.now()).build();
+    String encoded = FilterClient.builder().notEqual("date.date", LocalDate.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testNotnotEqualStringLocalDateTime() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().notEqual("date.date", LocalDateTime.now()).build();
+    String encoded = FilterClient.builder().notEqual("date.date", LocalDateTime.now()).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testNotnotEqualStringInteger() throws UnsupportedEncodingException, FilterParseException {
     int i = 10;
-    String encoded = FilterClient.builder().notEqual("int.int", i).build();
+    String encoded = FilterClient.builder().notEqual("int.int", i).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testNotnotEqualStringLong() throws UnsupportedEncodingException, FilterParseException {
     long i = 10l;
-    String encoded = FilterClient.builder().notEqual("long.long", i).build();
+    String encoded = FilterClient.builder().notEqual("long.long", i).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testNotnotEqualStringFloat() throws UnsupportedEncodingException, FilterParseException {
     float i = 10.2f;
-    String encoded = FilterClient.builder().notEqual("long.long", i).build();
+    String encoded = FilterClient.builder().notEqual("long.long", i).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testNotnotEqualStringDouble() throws UnsupportedEncodingException, FilterParseException {
     double i = 10.2;
-    String encoded = FilterClient.builder().notEqual("long.long", i).build();
+    String encoded = FilterClient.builder().notEqual("long.long", i).toString();
     Filter filter = new Filter(decode(encoded));
   }
 
   @Test
   public void testNotEqualNull() throws UnsupportedEncodingException, FilterParseException {
-    String encoded = FilterClient.builder().equalNull("null.null").build();
+    String encoded = FilterClient.builder().equalNull("null.null").toString();
     Filter filter = new Filter(decode(encoded));
   }
   
diff --git a/scim-common/pom.xml b/scim-common/pom.xml
index 6862c92..67d8b44 100644
--- a/scim-common/pom.xml
+++ b/scim-common/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-parent</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-common</artifactId>
@@ -14,12 +14,12 @@
     <dependency>
       <groupId>edu.psu.swe.scim</groupId>
       <artifactId>scim-spec-protocol</artifactId>
-      <version>2.1</version>
+      <version>2.2</version>
     </dependency>
     <dependency>
       <groupId>edu.psu.swe.scim</groupId>
       <artifactId>scim-spec-schema</artifactId>
-      <version>2.1</version>
+      <version>2.2</version>
     </dependency>
   </dependencies>
 
diff --git a/scim-compliance/pom.xml b/scim-compliance/pom.xml
index 33d8e35..17e06ee 100644
--- a/scim-compliance/pom.xml
+++ b/scim-compliance/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-parent</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-compliance</artifactId>
diff --git a/scim-compliance/scim-compliance-client/pom.xml b/scim-compliance/scim-compliance-client/pom.xml
index d6b40b2..a55c0f0 100644
--- a/scim-compliance/scim-compliance-client/pom.xml
+++ b/scim-compliance/scim-compliance-client/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-compliance</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-compliance-client</artifactId>
diff --git a/scim-compliance/scim-compliance-server/pom.xml b/scim-compliance/scim-compliance-server/pom.xml
index 6a762df..2b05fee 100644
--- a/scim-compliance/scim-compliance-server/pom.xml
+++ b/scim-compliance/scim-compliance-server/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-compliance</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-compliance-server</artifactId>
diff --git a/scim-errai/pom.xml b/scim-errai/pom.xml
index 8ce2b12..2840416 100644
--- a/scim-errai/pom.xml
+++ b/scim-errai/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-parent</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
   
   <artifactId>scim-errai</artifactId>
diff --git a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/ScimErraiShowcase.java b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/ScimErraiShowcase.java
deleted file mode 100644
index f695fb5..0000000
--- a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/ScimErraiShowcase.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package edu.psu.swe.scim.errai.client;
-
-import org.jboss.errai.common.client.dom.Div;
-import org.jboss.errai.common.client.dom.Span;
-import org.jboss.errai.common.client.dom.Window;
-import org.jboss.errai.ioc.client.api.AfterInitialization;
-import org.jboss.errai.ioc.client.api.EntryPoint;
-
-@EntryPoint
-public class ScimErraiShowcase {
-  
-  @AfterInitialization
-  public void start() {
-    Span label = (Span) Window.getDocument().createElement("span");
-    label.setInnerHTML("This is a test");
-    Div root = (Div) Window.getDocument().getElementById("scimErraiShowcase");
-    root.appendChild(label);
-  }
-
-}
diff --git a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/Error.java b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/Error.java
index f4cc758..6810dd8 100644
--- a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/Error.java
+++ b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/Error.java
@@ -3,13 +3,20 @@
  */
 package edu.psu.swe.scim.errai.client.business.common;
 
+import org.jboss.errai.common.client.api.annotations.Portable;
+
 import lombok.Data;
 
 /**
- * @author smoyer1
- *
+ * A DTO that represents the SCIM error while on the wire.  See
+ * section 3.12 of the SCIM Protocol Specification at:
+ * 
+ * https://tools.ietf.org/html/rfc7644#section-3.12
+ * 
+ * @author Steve Moyer &lt;smoyer@psu.edu&gt;
  */
 @Data
+@Portable
 public class Error {
   
   public enum Type {
@@ -27,7 +34,7 @@
     
   }
   
-  int status = 200;
+  int status = 400;
   Type scimType;
   String detail;
 
diff --git a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/ListResponse.java b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/ListResponse.java
index 39dde7d..e8adb16 100644
--- a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/ListResponse.java
+++ b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/ListResponse.java
@@ -5,18 +5,26 @@
 
 import java.util.List;
 
+import org.jboss.errai.common.client.api.annotations.Portable;
+
 import lombok.Data;
 
 /**
- * @author smoyer1
- *
+ * A DTO that represents the result of a SCIM query on the wire.  See
+ * setcion 3.4.2 of the SCIM Protocol Specification at:
+ * 
+ * https://tools.ietf.org/html/rfc7644#section-3.4.2
+ * 
+ * @author Steve Moyer &lt;smoyer@psu.edu&gt;
  */
 @Data
+@Portable
 public class ListResponse<T> {
   
   int itemsPerPage = 0;
   List<T> Resources; 
   int startIndex = 0;
   int totalResults = 0;
+  List<String> schemas;
 
 }
diff --git a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/Meta.java b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/Meta.java
new file mode 100644
index 0000000..54334de
--- /dev/null
+++ b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/common/Meta.java
@@ -0,0 +1,28 @@
+/**
+ * 
+ */
+package edu.psu.swe.scim.errai.client.business.common;
+
+import org.jboss.errai.common.client.api.annotations.Portable;
+
+import lombok.Data;
+
+/**
+ * A DTO the provides the wire format of the "meta" section sent with each
+ * SCIM resource according to section 3.1 of the SCIM Schema Specification.
+ * 
+ * https://tools.ietf.org/html/rfc7643#section-3.1
+ * 
+ * @author Steve Moyer &lt;smoyer@psu.edu&gt;
+ */
+@Data
+@Portable
+public class Meta {
+	
+	String resourceType;
+	String created; // DateTime
+	String lastModified; // DateTime
+	String location;
+	String version;
+
+}
diff --git a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/resourcetype/ResourceType.java b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/resourcetype/ResourceType.java
new file mode 100644
index 0000000..5310824
--- /dev/null
+++ b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/resourcetype/ResourceType.java
@@ -0,0 +1,31 @@
+/**
+ * 
+ */
+package edu.psu.swe.scim.errai.client.business.resourcetype;
+
+import java.util.List;
+
+import org.jboss.errai.common.client.api.annotations.Portable;
+
+import lombok.Data;
+
+/**
+ * A DTO that represents the wire format of a SCIM ResourceType according
+ * to section 6 of the SCIM Protocol Specification.  See:
+ * 
+ * https://tools.ietf.org/html/rfc7643#section-6
+ * 
+ * @author Steve Moyer &lt;smoyer@psu.edu&gt;
+ */
+@Data
+@Portable
+public class ResourceType {
+	
+	String id;
+	String name;
+	String description;
+	String endpoint;
+	String schema;
+	List<SchemaExtension> schemaExtensions;
+
+}
diff --git a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/resourcetype/SchemaExtension.java b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/resourcetype/SchemaExtension.java
new file mode 100644
index 0000000..b9199d3
--- /dev/null
+++ b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/resourcetype/SchemaExtension.java
@@ -0,0 +1,22 @@
+package edu.psu.swe.scim.errai.client.business.resourcetype;
+
+import org.jboss.errai.common.client.api.annotations.Portable;
+
+import lombok.Data;
+
+/**
+ * A DTO that represents the wire format of a SCIM ResourceType's SchemaExtension
+ * according to section 6 of the SCIM Protocol Specification.  See:
+ * 
+ * https://tools.ietf.org/html/rfc7643#section-6
+ * 
+ * @author Steve Moyer &lt;smoyer@psu.edu&gt;
+ */
+@Data
+@Portable
+public class SchemaExtension {
+	
+	String schema;
+	boolean required;
+
+}
diff --git a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/schema/Attribute.java b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/schema/Attribute.java
index a7b1c3a..9fa6f25 100644
--- a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/schema/Attribute.java
+++ b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/schema/Attribute.java
@@ -3,13 +3,20 @@
  */
 package edu.psu.swe.scim.errai.client.business.schema;
 
+import org.jboss.errai.common.client.api.annotations.Portable;
+
 import lombok.Data;
 
 /**
- * @author smoyer1
- *
+ * A DTO representing the wire format of each of a SCIM Schema's
+ * attributes.  See section 7 of the SCIM Schema Specification at:
+ * 
+ * https://tools.ietf.org/html/rfc7643#section-7
+ * 
+ * @author Steve Moyer &lt;smoyer@psu.edu&gt;
  */
 @Data
+@Portable
 public class Attribute {
   
   public enum Mutability {
@@ -41,6 +48,7 @@
     DECIMAL,
     INTEGER,
     DATE_TIME,
+    BINARY,
     REFERENCE,
     COMPLEX,
     ;
diff --git a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/schema/Schema.java b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/schema/Schema.java
index 35d08ad..83d8041 100644
--- a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/schema/Schema.java
+++ b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/schema/Schema.java
@@ -3,13 +3,20 @@
  */
 package edu.psu.swe.scim.errai.client.business.schema;
 
+import org.jboss.errai.common.client.api.annotations.Portable;
+
 import lombok.Data;
 
 /**
- * @author smoyer1
- *
+ * A DTO representing the format of a SCIM Schema object on the wire.  See
+ * section 7 of the SCIM Schema Specification at:
+ * 
+ * https://tools.ietf.org/html/rfc7643#section-7
+ * 
+ * Steve Moyer &lt;smoyer@psu.edu&gt;
  */
 @Data
+@Portable
 public class Schema {
   
   String id;
diff --git a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/scim/ScimServiceProvider.java b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/scim/ScimServiceProvider.java
new file mode 100644
index 0000000..bdc5f23
--- /dev/null
+++ b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/client/business/scim/ScimServiceProvider.java
@@ -0,0 +1,34 @@
+/**
+ * 
+ */
+package edu.psu.swe.scim.errai.client.business.scim;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+import edu.psu.swe.scim.errai.client.business.common.ListResponse;
+import edu.psu.swe.scim.errai.client.business.resourcetype.ResourceType;
+import edu.psu.swe.scim.errai.client.business.schema.Schema;
+
+/**
+ * Defines the REST end-points needed to retrieve the SCIM ResourceTypes
+ * and SCIM Schemas from the server.  See sections 6 and 7 respectively
+ * in the SCIM Schema Specification at:
+ * 
+ * https://tools.ietf.org/html/rfc7643#section-6
+ * https://tools.ietf.org/html/rfc7643#section-7
+ *
+ * @author Steve Moyer &lt;smoyer@psu.edu&gt;
+ */
+@Path("/v2")
+public interface ScimServiceProvider {
+  
+  @Path("ResourceTypes")
+  @GET
+  ListResponse<ResourceType> getResourceTypes();
+  
+  @Path("Schemas")
+  @GET
+  ListResponse<Schema> getSchemas();
+
+}
diff --git a/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/showcase/ScimErraiShowcase.java b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/showcase/ScimErraiShowcase.java
new file mode 100644
index 0000000..c24e563
--- /dev/null
+++ b/scim-errai/src/main/lombok/edu/psu/swe/scim/errai/showcase/ScimErraiShowcase.java
@@ -0,0 +1,77 @@
+package edu.psu.swe.scim.errai.showcase;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.jboss.errai.common.client.api.RemoteCallback;
+import org.jboss.errai.common.client.dom.Div;
+import org.jboss.errai.common.client.dom.Span;
+import org.jboss.errai.common.client.dom.Window;
+import org.jboss.errai.enterprise.client.jaxrs.api.RestClient;
+import org.jboss.errai.ioc.client.api.AfterInitialization;
+import org.jboss.errai.ioc.client.api.EntryPoint;
+
+import edu.psu.swe.scim.errai.client.business.common.ListResponse;
+import edu.psu.swe.scim.errai.client.business.resourcetype.ResourceType;
+import edu.psu.swe.scim.errai.client.business.schema.Attribute;
+import edu.psu.swe.scim.errai.client.business.schema.Schema;
+import edu.psu.swe.scim.errai.client.business.scim.ScimServiceProvider;
+
+@EntryPoint
+public class ScimErraiShowcase {
+
+  RemoteCallback<ListResponse<ResourceType>> resourceTypesCallaback = r -> showResourceTypeList(r.getResources());
+  RemoteCallback<ListResponse<Schema>> schemasCallback = r -> showSchemaList(r.getResources());
+  
+  Div root;
+  
+  @AfterInitialization
+  public void start() {
+    Span label = (Span) Window.getDocument().createElement("span");
+    label.setInnerHTML("This is a test");
+    root = (Div) Window.getDocument().getElementById("scimErraiShowcase");
+    root.appendChild(label);
+    
+    RestClient.setJacksonMarshallingActive(true);
+
+    RestClient.create(ScimServiceProvider.class, schemasCallback, 200).getSchemas();
+    
+    RestClient.create(ScimServiceProvider.class, resourceTypesCallaback, 200).getResourceTypes();
+  }
+  
+  void showResourceTypeList(List<ResourceType> resourceTypes) {
+	  resourceTypes.forEach(s -> {
+		  Div resourceType = (Div) Window.getDocument().createElement("div");
+		  resourceType.setInnerHTML(s.toString());
+		  root.appendChild(resourceType);
+	  });
+  }
+  
+  void showSchemaList(List<Schema> schemas) {
+    schemas.forEach(s -> {
+      Div schema = (Div) Window.getDocument().createElement("div");
+      schema.setInnerHTML(s.getName() + " - " + s.getAttributes().length);
+      root.appendChild(schema);
+      Stream.of(s.getAttributes()).forEach(a -> root.appendChild(getAttribute(a, "")));
+    });
+  }
+  
+  Div getAttribute(Attribute a, String spacer) {
+    String adjustedSpacer = spacer + "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
+    Div attribute = (Div) Window.getDocument().createElement("div");
+    attribute.appendChild(getSpan(adjustedSpacer));
+    attribute.appendChild(getSpan("Name: " + a.getName()));
+    attribute.appendChild(getSpan("Type: " + a.getType().name()));
+    if(Attribute.Type.COMPLEX.equals(a.getType())) {
+      Stream.of(a.getSubAttributes()).forEach(sa -> attribute.appendChild(getAttribute(sa, adjustedSpacer)));
+    }
+    return attribute;
+  }
+  
+  Span getSpan(String innerHtml) {
+    Span spacer = (Span) Window.getDocument().createElement("span");
+    spacer.setInnerHTML(innerHtml);
+    return spacer;
+  }
+
+}
diff --git a/scim-errai/src/main/resources/ErraiApp.properties b/scim-errai/src/main/resources/ErraiApp.properties
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/scim-errai/src/main/resources/ErraiApp.properties
diff --git a/scim-errai/src/main/webapp/index.html b/scim-errai/src/main/webapp/index.html
index bfb819a..80ce820 100644
--- a/scim-errai/src/main/webapp/index.html
+++ b/scim-errai/src/main/webapp/index.html
@@ -32,6 +32,9 @@
   <script type="text/javascript">
     erraiBusRemoteCommunicationEnabled = false;
   </script>
+  <script type="text/javascript">
+    erraiJaxRsApplicationRoot = "https://scim.psu.edu/tier";
+  </script>
   
   <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
   <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
diff --git a/scim-errai/src/test/resources/resource-types.json b/scim-errai/src/test/resources/resource-types.json
new file mode 100644
index 0000000..2603d8e
--- /dev/null
+++ b/scim-errai/src/test/resources/resource-types.json
@@ -0,0 +1,48 @@
+{
+    "totalResults": 2,
+    "startIndex": 1,
+    "itemsPerPage": 2,
+    "schemas": [
+        "urn:ietf:params:scim:api:messages:2.0:ListResponse"
+    ],
+    "Resources": [
+        {
+            "meta": {
+                "resourceType": "ResourceType",
+                "location": "http://scim.psu.edu/tier/v2/ResourceTypes/Group"
+            },
+            "id": "Group",
+            "name": "Group",
+            "description": "Top level ScimGroup",
+            "endpoint": "/Groups",
+            "schemas": [
+                "urn:ietf:params:scim:schemas:core:2.0:ResourceType"
+            ],
+            "schema": "urn:ietf:params:scim:schemas:core:2.0:Group"
+        },
+        {
+            "meta": {
+                "resourceType": "ResourceType",
+                "location": "http://scim.psu.edu/tier/v2/ResourceTypes/User"
+            },
+            "id": "User",
+            "name": "User",
+            "description": "Top level ScimUser",
+            "endpoint": "/Users",
+            "schemaExtensions": [
+                {
+                    "required": false,
+                    "schema": "urn:internet2:params:scim:schemas:EduPersonExtension"
+                },
+                {
+                    "required": false,
+                    "schema": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
+                }
+            ],
+            "schemas": [
+                "urn:ietf:params:scim:schemas:core:2.0:ResourceType"
+            ],
+            "schema": "urn:ietf:params:scim:schemas:core:2.0:User"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/scim-errai/src/test/resources/schemas.json b/scim-errai/src/test/resources/schemas.json
new file mode 100644
index 0000000..8191c49
--- /dev/null
+++ b/scim-errai/src/test/resources/schemas.json
@@ -0,0 +1,1854 @@
+{
+	"totalResults": 4,
+	"startIndex": 1,
+	"itemsPerPage": 4,
+	"schemas": 
+	[
+		"urn:ietf:params:scim:api:messages:2.0:ListResponse"
+	],
+	"Resources": 
+	[
+		{
+			"id": "urn:ietf:params:scim:schemas:core:2.0:Group",
+			"name": "Group",
+			"description": "Top level ScimGroup",
+			"attributes": 
+			[
+				{
+					"name": "displayName",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "A human-readable name for the Group.",
+					"required": true,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "members",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "value",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "Reference Element Identifier",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "ref",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The URI of the corresponding resource ",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE",
+							"referenceTypes": 
+							[
+								"User",
+								"Group"
+							]
+						},
+						{
+							"name": "display",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A human readable name, primarily used for display purposes. READ-ONLY.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "type",
+							"type": "REFERENCE",
+							"multiValued": false,
+							"description": "A label indicating the attribute's function; e.g., 'direct' or 'indirect'.",
+							"required": false,
+							"canonicalValues": 
+							[
+								"indirect",
+								"direct"
+							],
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": true,
+					"description": "A list of members of the Group.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "meta",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": false,
+					"description": "",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "ALWAYS",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "id",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "",
+					"required": true,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "ALWAYS",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "externalId",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				}
+			],
+			"meta": 
+			{
+				"resourceType": "Schema",
+				"location": "http://scim.psu.edu/tier/v2/Schemas/urn:ietf:params:scim:schemas:core:2.0:Group"
+			}
+		},
+		{
+			"id": "urn:internet2:params:scim:schemas:EduPersonExtension",
+			"name": "EduPersonExtension",
+			"description": "Eduperson extension",
+			"attributes": 
+			[
+				{
+					"name": "eduPersonAffiliation",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Specifies the person's relationship(s) to the institution in broad categories such as student, faculty, staff, alum, etc. (See controlled vocabulary). Notes If there is a value in eduPersonPrimaryAffiliation, that value MUST be asserted here as well.",
+					"required": false,
+					"canonicalValues": 
+					[
+						"library-walk-in",
+						"student",
+						"member",
+						"staff",
+						"affiliate",
+						"employee",
+						"alum",
+						"faculty"
+					],
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonEntitlement",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "URI (either URN or URL) that indicates a set of rights to specific resources.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonNickname",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Person's nickname, or the informal name by which they are accustomed to be hailed.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonOrgDN",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "The distinguished name (DN) of the directory entry representing the institution with which the person is associated. LDAP example eduPersonOrgDN: o=Hogwarts, dc=hsww, dc=wiz",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonOrgUnitDN",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "The distinguished name(s) (DN) of the directory entries representing the person's Organizational Unit(s). May be multivalued, as for example, in the case of a faculty member with appointments in multiple departments or a person who is a student in one department and an employee in another. LDAP Example - eduPersonOrgUnitDN: ou=Potions, o=Hogwarts, dc=hsww, dc=wiz",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonPrimaryAffiliation",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Person's nickname, or the informal name by which they are accustomed to be hailed. LDAP Example - eduPersonPrimaryAffiliation: student",
+					"required": false,
+					"canonicalValues": 
+					[
+						"library-walk-in",
+						"student",
+						"member",
+						"staff",
+						"affiliate",
+						"employee",
+						"alum",
+						"faculty"
+					],
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonPrimaryOrgUnitDN",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "The distinguished name (DN) of the directory entry representing the person's primary Organizational Unit(s).  LDAP example - eduPersonPrimaryOrgUnitDN: ou=Music Department, o=Notre Dame, dc=nd, dc=edu",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonPrincipalName",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "A scoped identifier for a person. It should be represented in the form \"user@scope\" where 'user' is a name-based identifier for the person and where the \"scope\" portion MUST be the administrative domain of the identity system where the identifier was created and assigned. Each value of 'scope' defines a namespace within which the assigned identifiers MUST be unique. Given this rule, if two eduPersonPrincipalName (ePPN) values are the same at a given point in time, they refer to the same person. There must be one and only one \"@\" sign in valid values of eduPersonPrincipalName. LDAP example - eduPersonPrincipalName: hputter@hsww.wiz",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonPrincipalNamePrior",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Each value of this multi-valued attribute represents an ePPN (eduPersonPrincipalName) value that was previously associated with the entry. The values MUST NOT include the currently valid ePPN value. There is no implied or assumed order to the values. This attribute MUST NOT be populated if ePPN values are ever reassigned to a different entry (after, for example, a period of dormancy). That is, they MUST be unique in space and over time. LDAP example - eduPersonPrincipalNamePrior: foo@hsww.wiz",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonScopedAffiliation",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Specifies the person's affiliation within a particular security domain in broad categories such as student, faculty, staff, alum, etc. The values consist of a left and right component separated by an \"@\" sign. The left component is one of the values from the eduPersonAffiliation controlled vocabulary.This right-hand side syntax of eduPersonScopedAffiliation intentionally matches that used for the right-hand side values for eduPersonPrincipalName. The \"scope\" portion MUST be the administrative domain to which the affiliation applies. Multiple \"@\" signs are not recommended, but in any case, the first occurrence of the \"@\" sign starting from the left is to be taken as the delimiter between components. Thus, user identifier is to the left, security domain to the right of the first \"@\". This parsing rule conforms to the POSIX \"greedy\" disambiguation method in regular expression processing. LDAP exapmple - eduPersonScopedAffiliation: faculty@cs.berkeley.edu",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonTargetedID",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "A persistent, non-reassigned, opaque identifier for a principal.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonAssurance",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Set of URIs that assert compliance with specific standards for identity assurance. LDAP example - eduPersonAssurance: urn:mace:incommon:IAQ:sample",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonUniqueId",
+					"type": "STRING",
+					"multiValued": false,
+					"description": " A long-lived, non re-assignable, omnidirectional identifier suitable for use as a principal identifier by authentication providers or as a unique external key by applications. LDAP example - eduPersonUniqueId: 28c5353b8bb34984a8bd4169ba94c606@foo.edu",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "eduPersonOrcid",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "ORCID iDs are persistent digital identifiers for individual researchers. Their primary purpose is to unambiguously and definitively link them with their scholarly work products. ORCID iDs are assigned, managed and maintained by the ORCID organization. LDAP example - eduPersonOrcid: http://orcid.org/0000-0002-1825-0097",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "audio",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "RFC1274 notes that the proprietary format they recommend is \"interim\" only.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "cn",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Common name.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "description",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Open-ended; whatever the person or the directory manager puts here. According to RFC4519, \"The 'description' attribute type contains human-readable descriptive phrases about the object. Each description is one value of this multi-valued attribute.\" LDIF example - description: A jolly good felon",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "displayName",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "The name(s) that should appear in white-pages-like applications for this person. LDIF example - displayName: Jack Dougherty",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "facsimileTelephoneNumber",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "According to RFC4519: \"The 'facsimileTelephoneNumber' attribute type contains telephone numbers (and, optionally, the parameters) for facsimile terminals. Each telephone number is one value of this multi-valued attribute.\" LDIF example - facsimileTelephoneNumber: +44 71 123 4567",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "givenName",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4519 description:\"The 'givenName' attribute type contains name strings that are the part of a person's name that is not their surname. Each string is one value of this multi-valued attribute.\" LDIF example - givenName: Stephen",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "homePhone",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC1274 description: \"The [homePhone] attribute type specifies a home telephone number associated with a person.\" LDIF example - homePhone: +1 608 555 1212",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "homePostalAddress",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC1274 description: \"The Home postal address attribute type specifies a home postal address for an object. This should be limited to up to 6 lines of 30 characters each.\" LDIF example - homePostalAddress: 1212 Como Ave.$Midton, SD 45621$USA",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "initials",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4519 description: \"The 'initials' attribute type contains strings of initials of some or all of an individual's names, except the surname(s). Each string is one value of this multi-valued attribute.\" LDIF example - initials: f x",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "jpegPhoto",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Follow inetOrgPerson definition of RFC2798: \"Used to store one or more images of a person using the JPEG File Interchange Format [JFIF].\"",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "locality",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "locality name. LDIF example - l: Hudson Valley",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "labeledURI",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Follow inetOrgPerson definition of RFC2079: \"Uniform Resource Identifier with optional label.\"  LDIF example - labeledURI: http://www.hsww.wiz/%7Eputter Harry's home page",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "mail",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4524: The 'mail' (rfc822mailbox) attribute type holds Internet mail addresses in Mailbox [RFC2821] form (e.g., user@example.com). LDIF example - mail: dumbledore@hsww.wiz",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "manager",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4524: \"The 'manager' attribute specifies managers, by distinguished name, of the person (or entity).\" LDIF example - manager: uid=twilliams, ou=people, dc=hobart, dc=edu",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "mobile",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4524: \"The 'mobile' (mobileTelephoneNumber) attribute specifies mobile telephone numbers (e.g., \"+1 775 555 6789\") associated with a person (or entity).\" LDIF example - mobile: +47 22 44 66 88",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "o",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Standard name of the top-level organization (institution) with which this person is associated. LDIF example - o: St. Cloud State",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "ou",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Organizational unit(s). According to X.520(2000), \"The Organizational Unit Name attribute type specifies an organizational unit. When used as a component of a directory name it identifies an organizational unit with which the named object is affiliated. The designated organizational unit is understood to be part of an organization designated by an OrganizationName [o] attribute. It follows that if an Organizational Unit Name attribute is used in a directory name, it must be associated with an OrganizationName [o] attribute. An attribute value for Organizational Unit Name is a string chosen by the organization of which it is a part.\" LDIF example - ou: Faculty Senate",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "pager",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4524: \"The 'pager' (pagerTelephoneNumber) attribute specifies pager telephone numbers (e.g., \"+1 775 555 5555\") for an object.\" LDIF example - pager: +1 202 555 4321",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "postalAddress",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Campus or office address. inetOrgPerson has a homePostalAddress that complements this attribute. X.520(2000) reads: \"The Postal Address attribute type specifies the address information required for the physical postal delivery to an object.\" LDIF example - postalAddress: P.O. Box 333$Whoville, WH 99999$USA",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "postalCode",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Follow X.500(2001): \"The postal code attribute type specifies the postal code of the named object. If this attribute\" LDIF example - postalCode: 54321",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "postOfficeBox",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4519: \"The 'postOfficeBox' attribute type contains postal box identifiers that a Postal Service uses when a customer arranges to receive mail at a box on the premises of the Postal Service. Each postal box identifier is a single value of this multi-valued attribute.\" SCIM example - postOfficeBox: 109260",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "preferredLanguage",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Follow inetOrgPerson definition of RFC2798: \"preferred written or spoken language for a person.\" LDIF example - preferredLanguage: EO",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "seeAlso",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4519: The 'seeAlso' attribute type contains the distinguished names of objects that are related to the subject object. Each related object name is one value of this multi-valued attribute.\" LDIF example - seeAlso: cn=Department Chair, ou=physics, o=University of Technology, dc=utech, dc=ac, dc=uk",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "sn",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Surname or family name. From RFC4519: \"The 'sn' ('surname' in X.500) attribute type contains name strings for the family names of a person. Each string is one value of this multi-valued attribute.\" LDIF example - sn: Carson-Smith",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "st",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Abbreviation for state or province name. LDIF example - st: IL",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "street",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4519: \"The 'street' ('streetAddress' in X.500) attribute type contains site information from a postal address (i.e., the street name, place, avenue, and the house number). Each street is one value of this multi-valued attribute.\" LDIF example - street: 303 Mulberry St",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "telephoneNumber",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Office/campus phone number. Attribute values should comply with the international format specified in ITU Recommendation E.123: e.g., \"+44 71 123 4567.\" LDIF example - telephoneNumber: +1 212 555 1234",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "title",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4519: \"The 'title' attribute type contains the title of a person in their organizational context. Each title is one value of this multi-valued attribute.\" LDIF example - title: Assistant Vice-Deputy for Redundancy Reduction",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "uid",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4519: \"The 'uid' ('userid' in RFC1274) attribute type contains computer system login names associated with the object. Each name is one value of this multi-valued attribute.\" LDIF example - uid: gmettes",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "uniqueIdentifier",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "From RFC4524: \"The 'uniqueIdentifier' attribute specifies a unique identifier for an object represented in the Directory. The domain within which the identifier is unique and the exact semantics of the identifier are for local definition. For a person, this might be an institution- wide payroll number. For an organizational unit, it might be a department code.\"",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "userCertificate",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "A user's X.509 certificate.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "userPassword",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "This attribute identifies the entry's password and encryption method in the following format: {encryption method}encrypted password.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "NEVER",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "userSMIMECertificate",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "An X.509 certificate specifically for use in S/MIME applications (see RFCs 2632, 2633 and 2634).",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "x500uniqueIdentifier",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": true,
+					"description": "Defined originally in X.509(96) and included in RFC2256.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				}
+			],
+			"meta": 
+			{
+				"resourceType": "Schema",
+				"location": "http://scim.psu.edu/tier/v2/Schemas/urn:internet2:params:scim:schemas:EduPersonExtension"
+			}
+		},
+		{
+			"id": "urn:ietf:params:scim:schemas:core:2.0:User",
+			"name": "User",
+			"description": "Top level ScimUser",
+			"attributes": 
+			[
+				{
+					"name": "active",
+					"type": "BOOLEAN",
+					"multiValued": false,
+					"description": "A Boolean value indicating the User's administrative status.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "addresses",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "type",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A label indicating the attribute's function; e.g., 'aim', 'gtalk', 'mobile' etc.",
+							"required": false,
+							"canonicalValues": 
+							[
+								"other",
+								"work",
+								"home"
+							],
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "display",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A human readable name, primarily used for display purposes. READ-ONLY.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "primary",
+							"type": "BOOLEAN",
+							"multiValued": false,
+							"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g. the preferred mailing address or primary e-mail address. The primary attribute value 'true' MUST appear no more than once.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "country",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The two letter ISO 3166-1 alpha-2 country code",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "formatted",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The full mailing address, formatted for display or use with a mailing label. This attribute MAY contain newlines.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "locality",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The city or locality component.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "postalCode",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The zipcode or postal code component.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "region",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The state or region component.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "streetAddress",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The full street address component, which may include house number, street name, PO BOX, and multi-line extended street address information. This attribute MAY contain newlines.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": true,
+					"description": "A physical mailing address for this User, as described in (address Element). Canonical Type Values of work, home, and other. The value attribute is a complex type with the following sub-attributes.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "displayName",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "The name of the User, suitable for display to end-users. The name SHOULD be the full name of the User being described if known",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "emails",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "type",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A label indicating the attribute's function; e.g., 'work' or 'home'.",
+							"required": false,
+							"canonicalValues": 
+							[
+								"other",
+								"work",
+								"home"
+							],
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "value",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "E-mail addresses for the user. The value SHOULD be canonicalized by the Service Provider, e.g. bjensen@example.com instead of bjensen@EXAMPLE.COM. Canonical Type values of work, home, and other.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "display",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A human readable name, primarily used for display purposes. READ-ONLY.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "primary",
+							"type": "BOOLEAN",
+							"multiValued": false,
+							"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g. the preferred mailing address or primary e-mail address. The primary attribute value 'true' MUST appear no more than once.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": true,
+					"description": "E-mail addresses for the user. The value SHOULD be canonicalized by the Service Provider, e.g. bjensen@example.com instead of bjensen@EXAMPLE.COM. Canonical Type values of work, home, and other.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "entitlements",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "type",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A label indicating the attribute's function.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "value",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The value of an entitlement.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "display",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A human readable name, primarily used for display purposes. READ-ONLY.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "primary",
+							"type": "BOOLEAN",
+							"multiValued": false,
+							"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g. the preferred mailing address or primary e-mail address. The primary attribute value 'true' MUST appear no more than once.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": true,
+					"description": "Get the description",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "groups",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "value",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "Reference Element Identifier",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "ref",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The URI of the corresponding resource ",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE",
+							"referenceTypes": 
+							[
+								"User",
+								"Group"
+							]
+						},
+						{
+							"name": "display",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A human readable name, primarily used for display purposes. READ-ONLY.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "type",
+							"type": "REFERENCE",
+							"multiValued": false,
+							"description": "A label indicating the attribute's function; e.g., 'direct' or 'indirect'.",
+							"required": false,
+							"canonicalValues": 
+							[
+								"indirect",
+								"direct"
+							],
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": true,
+					"description": "A list of groups that the user belongs to, either thorough direct membership, nested groups, or dynamically calculated",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "ims",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "type",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A label indicating the attribute's function; e.g., 'aim', 'gtalk', 'mobile' etc.",
+							"required": false,
+							"canonicalValues": 
+							[
+								"qq",
+								"skype",
+								"qtalk",
+								"aim",
+								"icq",
+								"yahoo",
+								"msn",
+								"xmpp"
+							],
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "value",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "Instant messaging address for the User.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "display",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A human readable name, primarily used for display purposes. READ-ONLY.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "primary",
+							"type": "BOOLEAN",
+							"multiValued": false,
+							"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g. the preferred mailing address or primary e-mail address. The primary attribute value 'true' MUST appear no more than once.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": true,
+					"description": "Instant messaging address for the User.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "locale",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Used to indicate the User's default location for purposes of localizing items such as currency, date time format, numerical representations, etc.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "name",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "formatted",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The full name, including all middle names, titles, and suffixes as appropriate, formatted for display (e.g. Ms. Barbara J Jensen, III.).",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "familyName",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The family name of the User, or Last Name in most Western languages (e.g. Jensen given the full name Ms. Barbara J Jensen, III.).",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "givenName",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The given name of the User, or First Name in most Western languages (e.g. Barbara given the full name Ms. Barbara J Jensen, III.).",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "middleName",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The middle name(s) of the User (e.g. Robert given the full name Ms. Barbara J Jensen, III.).",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "honorificPrefix",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The honorific prefix(es) of the User, or Title in most Western languages (e.g. Ms. given the full name Ms. Barbara J Jensen, III.).",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "honorificSuffix",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The honorific suffix(es) of the User, or Suffix in most Western languages (e.g. III. given the full name Ms. Barbara J Jensen, III.).",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": false,
+					"description": "The components of the user's real name. Providers MAY return just the full name as a single string in the formatted sub-attribute, or they MAY return just the individual component attributes using the other sub-attributes, or they MAY return both. If both variants are returned, they SHOULD be describing the same name, with the formatted name indicating how the component attributes should be combined.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "nickName",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "The casual way to address the user in real life, e.g.'Bob' or 'Bobby' instead of 'Robert'. This attribute SHOULD NOT be used to represent a User's username (e.g. bjensen or mpepperidge)",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "password",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "The User's clear text password.  This attribute is intended to be used as a means to specify an initial password when creating a new User or to reset an existing User's password.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "NEVER",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "phoneNumbers",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "value",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "Phone number of the User",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "display",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A human readable name, primarily used for display purposes. READ-ONLY.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "type",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A label indicating the attribute's function; e.g., 'work' or 'home' or 'mobile' etc.",
+							"required": false,
+							"canonicalValues": 
+							[
+								"other",
+								"pager",
+								"work",
+								"mobile",
+								"fax",
+								"home"
+							],
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "primary",
+							"type": "BOOLEAN",
+							"multiValued": false,
+							"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g. the preferred phone number or primary phone number. The primary attribute value 'true' MUST appear no more than once.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": true,
+					"description": "Phone numbers for the User.  The value SHOULD be canonicalized by the Service Provider according to format in RFC3966 e.g. 'tel:+1-201-555-0123'.  Canonical Type values of work, home, mobile, fax, pager and other.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "photos",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "value",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "URL of a photo of the User.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE",
+							"referenceTypes": 
+							[
+								"external"
+							]
+						},
+						{
+							"name": "type",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A label indicating the attribute's function; e.g., 'photo' or 'thumbnail'.",
+							"required": false,
+							"canonicalValues": 
+							[
+								"thumbnail",
+								"photo"
+							],
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "display",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A human readable name, primarily used for display purposes. READ-ONLY.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "primary",
+							"type": "BOOLEAN",
+							"multiValued": false,
+							"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g. the preferred mailing address or primary e-mail address. The primary attribute value 'true' MUST appear no more than once.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": true,
+					"description": "URLs of photos of the User.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "profileUrl",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "A fully qualified URL to a page representing the User's online profile",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE",
+					"referenceTypes": 
+					[
+						"external"
+					]
+				},
+				{
+					"name": "preferredLanguage",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Indicates the User's preferred written or spoken language.  Generally used for selecting a localized User interface. e.g., 'en_US' specifies the language English and country US.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "roles",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "type",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A label indicating the attribute's function.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "value",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The value of a role.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "display",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A human readable name, primarily used for display purposes. READ-ONLY.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "primary",
+							"type": "BOOLEAN",
+							"multiValued": false,
+							"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g. the preferred mailing address or primary e-mail address. The primary attribute value 'true' MUST appear no more than once.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": true,
+					"description": "A list of roles for the User that collectively represent who the User is; e.g., 'Student', 'Faculty'.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "timezone",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "The User's time zone in the 'Olson' timezone database format; e.g.,'America/Los_Angeles'",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "title",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "The user's title, such as \"Vice President.\"",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "userName",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Unique identifier for the User typically used by the user to directly authenticate to the service provider. Each User MUST include a non-empty userName value.  This identifier MUST be unique across the Service Consumer's entire set of Users.  REQUIRED",
+					"required": true,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "SERVER"
+				},
+				{
+					"name": "userType",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Used to identify the organization to user relationship. Typical values used might be 'Contractor', 'Employee', 'Intern', 'Temp', 'External', and 'Unknown' but any value may be used.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "x509Certificates",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "type",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A label indicating the attribute's function.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "value",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The value of a X509 certificate.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "display",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "A human readable name, primarily used for display purposes. READ-ONLY.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "primary",
+							"type": "BOOLEAN",
+							"multiValued": false,
+							"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g. the preferred mailing address or primary e-mail address. The primary attribute value 'true' MUST appear no more than once.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": true,
+					"description": "A list of certificates issued to the User.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "meta",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						
+					],
+					"multiValued": false,
+					"description": "",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "ALWAYS",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "id",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "",
+					"required": true,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "ALWAYS",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "externalId",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				}
+			],
+			"meta": 
+			{
+				"resourceType": "Schema",
+				"location": "http://scim.psu.edu/tier/v2/Schemas/urn:ietf:params:scim:schemas:core:2.0:User"
+			}
+		},
+		{
+			"id": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
+			"name": "EnterpriseUser",
+			"description": "Attributes commonly used in representing users that belong to, or act on behalf of, a business or enterprise.",
+			"attributes": 
+			[
+				{
+					"name": "employeeNumber",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "A string identifier, typically numeric or alphanumeric, assigned to a person, typically based on order of hire or association with an organization.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "costCenter",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Identifies the name of a cost center.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "organization",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Identifies the name of an organization.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "division",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Identifies the name of a division.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "department",
+					"type": "STRING",
+					"multiValued": false,
+					"description": "Identifies the name of a department.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				},
+				{
+					"name": "manager",
+					"type": "COMPLEX",
+					"subAttributes": 
+					[
+						{
+							"name": "value",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The \"id\" of the SCIM resource representing the user's manager.  RECOMMENDED.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "ref",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "The URI of the SCIM resource representing the User's manager.  RECOMMENDED.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_WRITE",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						},
+						{
+							"name": "displayName",
+							"type": "STRING",
+							"multiValued": false,
+							"description": "he displayName of the user's manager.  This attribute is OPTIONAL.",
+							"required": false,
+							"caseExact": false,
+							"mutability": "READ_ONLY",
+							"returned": "DEFAULT",
+							"uniqueness": "NONE"
+						}
+					],
+					"multiValued": false,
+					"description": "The user's manager.  A complex type that optionally allows service providers to represent organizational hierarchy by referencing the \"id\" attribute of another User.",
+					"required": false,
+					"caseExact": false,
+					"mutability": "READ_WRITE",
+					"returned": "DEFAULT",
+					"uniqueness": "NONE"
+				}
+			],
+			"meta": 
+			{
+				"resourceType": "Schema",
+				"location": "http://scim.psu.edu/tier/v2/Schemas/urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
+			}
+		}
+	]
+}
\ No newline at end of file
diff --git a/scim-server/pom.xml b/scim-server/pom.xml
index b040322..451d68b 100644
--- a/scim-server/pom.xml
+++ b/scim-server/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-parent</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-server</artifactId>
diff --git a/scim-server/scim-server-common/pom.xml b/scim-server/scim-server-common/pom.xml
index cd8d2a4..db4117d 100644
--- a/scim-server/scim-server-common/pom.xml
+++ b/scim-server/scim-server-common/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-server</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-server-common</artifactId>
diff --git a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/ProviderRegistry.java b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/ProviderRegistry.java
index 0ac4d32..4f94282 100644
--- a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/ProviderRegistry.java
+++ b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/ProviderRegistry.java
@@ -92,15 +92,8 @@
 
     if (extensionList != null) {
       for (Class<? extends ScimExtension> scimExtension : extensionList) {
-        ScimExtension newScimExtensionInstance;
-        try {
-          newScimExtensionInstance = scimExtension.newInstance();
-          log.info("Registering a extension of type " + newScimExtensionInstance.getUrn());
-        } catch (InstantiationException | IllegalAccessException e) {
-          throw new InvalidProviderException(e.getMessage());
-        }
-
-        scimExtensionRegistry.registerExtension(clazz, newScimExtensionInstance);
+        log.info("Registering a extension of type " + scimExtension);
+        scimExtensionRegistry.registerExtension(clazz, scimExtension);
       }
 
       Iterator<Class<? extends ScimExtension>> iter = extensionList.iterator();
diff --git a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/BaseResourceTypeResourceImpl.java b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/BaseResourceTypeResourceImpl.java
index 39701fa..72bbe0c 100644
--- a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/BaseResourceTypeResourceImpl.java
+++ b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/BaseResourceTypeResourceImpl.java
@@ -90,7 +90,12 @@
 
     provider = getProvider();
     if (provider == null) {
-      return BaseResourceTypeResource.super.getById(id, attributes, excludedAttributes);
+      try {
+        // does not throw an exception server side
+        return BaseResourceTypeResource.super.getById(id, attributes, excludedAttributes);
+      } catch (Exception e) {
+        throw new RuntimeException();
+      }
     }
 
     endpointUtil.process(uriInfo);
@@ -184,7 +189,12 @@
 
     provider = getProvider();
     if (provider == null) {
-      return BaseResourceTypeResource.super.create(resource, attributes, excludedAttributes);
+      try {
+        // does not throw an exception server side
+        return BaseResourceTypeResource.super.create(resource, attributes, excludedAttributes);
+      } catch (Exception e) {
+        throw new RuntimeException();
+      }
     }
 
     Set<AttributeReference> attributeReferences = Optional.ofNullable(attributes).map(wrapper -> wrapper.getAttributeReferences()).orElse(Collections.emptySet());
@@ -257,7 +267,12 @@
 
     provider = getProvider();
     if (provider == null) {
-      return BaseResourceTypeResource.super.find(request);
+      try {
+        // does not throw an exception server side
+        return BaseResourceTypeResource.super.find(request);
+      } catch (Exception e) {
+        throw new RuntimeException();
+      }
     }
 
     Set<AttributeReference> attributeReferences = Optional.ofNullable(request.getAttributes()).orElse(Collections.emptySet());
@@ -270,7 +285,7 @@
     PageRequest pageRequest = request.getPageRequest();
     SortRequest sortRequest = request.getSortRequest();
 
-    ListResponse listResponse = new ListResponse();
+    ListResponse<T> listResponse = new ListResponse<>();
 
     endpointUtil.process(uriInfo);
     FilterResponse<T> filterResp = null;
@@ -292,7 +307,7 @@
       listResponse.setStartIndex(1);
       listResponse.setTotalResults(filterResp.getResources().size());
 
-      List<Object> results = new ArrayList<>();
+      List<T> results = new ArrayList<>();
 
       for (T resource : filterResp.getResources()) {
         EntityTag etag = null;
@@ -339,7 +354,12 @@
 
     provider = getProvider();
     if (provider == null) {
-      return BaseResourceTypeResource.super.update(resource, id, attributes, excludedAttributes);
+      try {
+        // does not throw an exception server side
+        return BaseResourceTypeResource.super.update(resource, id, attributes, excludedAttributes);
+      } catch (Exception e) {
+        throw new RuntimeException();
+      }
     }
 
     Set<AttributeReference> attributeReferences = Optional.ofNullable(attributes).map(wrapper -> wrapper.getAttributeReferences()).orElse(Collections.emptySet());
@@ -419,7 +439,12 @@
   @Override
   public Response patch(PatchRequest patchRequest) {
     // TODO Auto-generated method stub
-    return BaseResourceTypeResource.super.patch(patchRequest);
+    try {
+      // does not throw an exception server side
+      return BaseResourceTypeResource.super.patch(patchRequest);
+    } catch (Exception e) {
+      throw new RuntimeException();
+    }
   }
 
   @Override
@@ -429,7 +454,12 @@
       Provider<T> provider = getProvider();
 
       if (provider == null) {
-        response = BaseResourceTypeResource.super.delete(id);
+        try {
+          // does not throw an exception server side
+          response = BaseResourceTypeResource.super.delete(id);
+        } catch (Exception e) {
+          throw new RuntimeException();
+        }
       } else {
         endpointUtil.process(uriInfo);
         response = Response.noContent().build();
diff --git a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/ResourceTypesResourceImpl.java b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/ResourceTypesResourceImpl.java
index 10089f9..a350e7f 100644
--- a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/ResourceTypesResourceImpl.java
+++ b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/ResourceTypesResourceImpl.java
@@ -43,12 +43,12 @@
       resourceType.setMeta(meta);
     }
     
-    ListResponse listResponse = new ListResponse();
+    ListResponse<ResourceType> listResponse = new ListResponse<>();
     listResponse.setItemsPerPage(resourceTypes.size());
     listResponse.setStartIndex(1);
     listResponse.setTotalResults(resourceTypes.size());
     
-    List<Object> objectList = new ArrayList<>(resourceTypes);
+    List<ResourceType> objectList = new ArrayList<>(resourceTypes);
     listResponse.setResources(objectList);
     
     return Response.ok(listResponse).build();
diff --git a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/SchemaResourceImpl.java b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/SchemaResourceImpl.java
index 494db94..5fd4e27 100644
--- a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/SchemaResourceImpl.java
+++ b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/rest/SchemaResourceImpl.java
@@ -33,7 +33,7 @@
       return Response.status(Status.FORBIDDEN).build();
     }
     
-    ListResponse listResponse = new ListResponse();
+    ListResponse<Schema> listResponse = new ListResponse<>();
     Collection<Schema> schemas = registry.getAllSchemas();
     
     for (Schema schema : schemas) {
@@ -48,7 +48,7 @@
     listResponse.setStartIndex(1);
     listResponse.setTotalResults(schemas.size());
     
-    List<Object> objectList = new ArrayList<>(schemas);
+    List<Schema> objectList = new ArrayList<>(schemas);
     listResponse.setResources(objectList);
     
     return Response.ok(listResponse).build();
diff --git a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/utility/EndpointUtil.java b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/utility/EndpointUtil.java
index a980598..762a9a6 100644
--- a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/utility/EndpointUtil.java
+++ b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/utility/EndpointUtil.java
@@ -3,33 +3,35 @@
 import java.net.URI;
 
 import javax.enterprise.context.RequestScoped;
-import javax.inject.Inject;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 
-import edu.psu.swe.scim.server.provider.ProviderRegistry;
+import edu.psu.swe.scim.spec.annotation.ScimResourceType;
+import edu.psu.swe.scim.spec.exception.InvalidScimResourceException;
 import edu.psu.swe.scim.spec.resources.ScimResource;
-import lombok.Data;
 
 @RequestScoped
-@Data
 public class EndpointUtil {
-  private UriBuilder baseUri;
+  private URI baseUri;
   
-  @Inject
-  ProviderRegistry registry;
+  public UriBuilder getBaseUriBuilder() {
+    return UriBuilder.fromUri(baseUri);
+  }
   
-  public URI getEndpoint(Class<? extends ScimResource> resource) {
-    
-    URI uri = null;
-    if (registry.getProvider(resource) != null) {
-      uri = baseUri.path(resource.getSimpleName()).build();
+  public UriBuilder getEndpointUriBuilder(Class<? extends ScimResource> resource) {
+    ScimResourceType[] sr = resource.getAnnotationsByType(ScimResourceType.class);
+
+    if (sr.length == 0 || sr.length > 1) {
+      throw new InvalidScimResourceException("ScimResource class must have a ScimResourceType annotation");
     }
+
+    // yuck! TODO where to get REST endpoint from?
+    String resourceName = sr[0].name() + "s";  
     
-    return uri;
+    return UriBuilder.fromUri(baseUri).path(resourceName);
   }
   
   public void process(UriInfo uriInfo) {
-    baseUri = uriInfo.getBaseUriBuilder();
+    baseUri = uriInfo.getBaseUri();
   }
 }
diff --git a/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/utility/AttributeUtilTest.java b/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/utility/AttributeUtilTest.java
index 2dbe409..8eeb94c 100644
--- a/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/utility/AttributeUtilTest.java
+++ b/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/utility/AttributeUtilTest.java
@@ -220,7 +220,7 @@
     LOG.info(sw.toString());
   }
   
-  private ScimUser getScimUser() throws InvalidExtensionException {
+  private ScimUser getScimUser() {
     ScimUser user = new ScimUser();
 
     user.setActive(true);
diff --git a/scim-server/scim-server-example/pom.xml b/scim-server/scim-server-example/pom.xml
index c611b32..6af2ead 100644
--- a/scim-server/scim-server-example/pom.xml
+++ b/scim-server/scim-server-example/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-server</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-server-examples</artifactId>
diff --git a/scim-server/scim-server-example/scim-server-couchdb/pom.xml b/scim-server/scim-server-example/scim-server-couchdb/pom.xml
index 543a997..4c809a1 100644
--- a/scim-server/scim-server-example/scim-server-couchdb/pom.xml
+++ b/scim-server/scim-server-example/scim-server-couchdb/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-server-examples</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-server-couchdb</artifactId>
diff --git a/scim-server/scim-server-example/scim-server-memory/pom.xml b/scim-server/scim-server-example/scim-server-memory/pom.xml
index 13f5f31..ba7581d 100644
--- a/scim-server/scim-server-example/scim-server-memory/pom.xml
+++ b/scim-server/scim-server-example/scim-server-memory/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-server-examples</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-server-memory</artifactId>
diff --git a/scim-server/scim-server-example/scim-server-memory/src/main/java/edu/psu/swe/scim/memory/service/InMemoryUserService.java b/scim-server/scim-server-example/scim-server-memory/src/main/java/edu/psu/swe/scim/memory/service/InMemoryUserService.java
index ab14a7f..2a1ce13 100644
--- a/scim-server/scim-server-example/scim-server-memory/src/main/java/edu/psu/swe/scim/memory/service/InMemoryUserService.java
+++ b/scim-server/scim-server-example/scim-server-memory/src/main/java/edu/psu/swe/scim/memory/service/InMemoryUserService.java
@@ -57,12 +57,7 @@
     LuckyNumberExtension luckyNumberExtension = new LuckyNumberExtension();
     luckyNumberExtension.setLuckyNumber(DEFAULT_USER_LUCKY_NUMBER);
     
-    try {
-      user.addExtension(luckyNumberExtension);
-    } catch (InvalidExtensionException e) {
-      // TODO Auto-generated catch block
-      e.printStackTrace();
-    }
+    user.addExtension(luckyNumberExtension);
     
     users.put(user.getId(), user);
   }
diff --git a/scim-server/scim-server-example/scim-server-rdbms/pom.xml b/scim-server/scim-server-example/scim-server-rdbms/pom.xml
index 564e4ec..dd708d0 100644
--- a/scim-server/scim-server-example/scim-server-rdbms/pom.xml
+++ b/scim-server/scim-server-example/scim-server-rdbms/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-server-examples</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-server-rdbms</artifactId>
diff --git a/scim-spec/pom.xml b/scim-spec/pom.xml
index b8ded33..5b6ec6c 100644
--- a/scim-spec/pom.xml
+++ b/scim-spec/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-parent</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-spec</artifactId>
diff --git a/scim-spec/scim-spec-protocol/pom.xml b/scim-spec/scim-spec-protocol/pom.xml
index 92b6a2e..81ea925 100644
--- a/scim-spec/scim-spec-protocol/pom.xml
+++ b/scim-spec/scim-spec-protocol/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-spec</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-spec-protocol</artifactId>
diff --git a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/adapter/AttributeReferenceAdapter.java b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/adapter/AttributeReferenceAdapter.java
new file mode 100644
index 0000000..127e6bd
--- /dev/null
+++ b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/adapter/AttributeReferenceAdapter.java
@@ -0,0 +1,26 @@
+package edu.psu.swe.scim.spec.adapter;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+import edu.psu.swe.scim.spec.protocol.attribute.AttributeReference;
+
+public class AttributeReferenceAdapter extends XmlAdapter<String, AttributeReference> {
+
+  @Override
+  public AttributeReference unmarshal(String string) throws Exception {
+    if (string == null) {
+      return null;
+    }
+    return new AttributeReference(string);
+  }
+
+  @Override
+  public String marshal(AttributeReference attributeReference) throws Exception {
+    if (attributeReference == null) {
+      return null;
+    }
+    return attributeReference.getFullyQualifiedAttributeName();
+  }
+
+
+}
diff --git a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/adapter/FilterAdapter.java b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/adapter/FilterAdapter.java
new file mode 100644
index 0000000..0f42c8c
--- /dev/null
+++ b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/adapter/FilterAdapter.java
@@ -0,0 +1,26 @@
+package edu.psu.swe.scim.spec.adapter;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+import edu.psu.swe.scim.spec.protocol.search.Filter;
+
+public class FilterAdapter extends XmlAdapter<String, Filter> {
+
+  @Override
+  public Filter unmarshal(String string) throws Exception {
+    if (string == null) {
+      return null;
+    }
+    return new Filter(string);
+  }
+
+  @Override
+  public String marshal(Filter filter) throws Exception {
+    if (filter == null) {
+      return null;
+    }
+    return filter.getExpression().toFilter();
+  }
+
+
+}
diff --git a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/BaseResourceTypeResource.java b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/BaseResourceTypeResource.java
index c6cc158..cf44f21 100644
--- a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/BaseResourceTypeResource.java
+++ b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/BaseResourceTypeResource.java
@@ -1,12 +1,5 @@
 package edu.psu.swe.scim.spec.protocol;
 
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
-import io.swagger.jaxrs.PATCH;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -21,11 +14,18 @@
 
 import edu.psu.swe.scim.spec.protocol.attribute.AttributeReference;
 import edu.psu.swe.scim.spec.protocol.attribute.AttributeReferenceListWrapper;
+import edu.psu.swe.scim.spec.protocol.data.ListResponse;
 import edu.psu.swe.scim.spec.protocol.data.PatchRequest;
 import edu.psu.swe.scim.spec.protocol.data.SearchRequest;
 import edu.psu.swe.scim.spec.protocol.search.Filter;
 import edu.psu.swe.scim.spec.protocol.search.SortOrder;
 import edu.psu.swe.scim.spec.resources.ScimResource;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.jaxrs.PATCH;
 
 @Api(tags="SCIM", hidden=true)
 public interface BaseResourceTypeResource<T> {
@@ -48,7 +48,7 @@
                 })
     default Response getById(@ApiParam(value="id", required=true) @PathParam("id") String id, 
                              @ApiParam(value="attributes", required=false) @QueryParam("attributes") AttributeReferenceListWrapper attributes,
-                             @ApiParam(value="excludedAttributes", required=false) @QueryParam("excludedAttributes") AttributeReferenceListWrapper excludedAttributes) {
+                             @ApiParam(value="excludedAttributes", required=false) @QueryParam("excludedAttributes") AttributeReferenceListWrapper excludedAttributes) throws Exception {
     return Response.status(Status.NOT_IMPLEMENTED).build();
   }
 
@@ -59,7 +59,7 @@
    */
   @GET
   @Produces(Constants.SCIM_CONTENT_TYPE)
-  @ApiOperation(value="Find by a combination of query parameters", produces=Constants.SCIM_CONTENT_TYPE, response=ScimResource.class, responseContainer="List", code=200)
+  @ApiOperation(value="Find by a combination of query parameters", produces=Constants.SCIM_CONTENT_TYPE, response=ListResponse.class, code=200)
   @ApiResponses(value={
                   @ApiResponse(code=400, message="Bad Request"),
                   @ApiResponse(code=404, message="Not found"),
@@ -72,7 +72,7 @@
                                  @ApiParam(value="sortBy", required=false) @QueryParam("sortBy") AttributeReference sortBy,
                                  @ApiParam(value="sortOrder", required=false) @QueryParam("sortOrder") SortOrder sortOrder,
                                  @ApiParam(value="startIndex", required=false) @QueryParam("startIndex") Integer startIndex,
-                                 @ApiParam(value="count", required=false) @QueryParam("count") Integer count) {
+                                 @ApiParam(value="count", required=false) @QueryParam("count") Integer count) throws Exception {
     return Response.status(Status.NOT_IMPLEMENTED).build();
   }
 
@@ -88,7 +88,7 @@
   @ApiResponses(value = { @ApiResponse(code = 400, message = "Bad Request"), @ApiResponse(code = 409, message = ErrorMessageConstants.UNIQUENESS), @ApiResponse(code = 500, message = "Internal Server Error"), @ApiResponse(code = 501, message = "Not Implemented") })
   default Response create(T resource,
                           @ApiParam(value="attributes", required=false) @QueryParam("attributes") AttributeReferenceListWrapper attributes,
-                          @ApiParam(value="excludedAttributes", required=false) @QueryParam("excludedAttributes") AttributeReferenceListWrapper excludedAttributes) {
+                          @ApiParam(value="excludedAttributes", required=false) @QueryParam("excludedAttributes") AttributeReferenceListWrapper excludedAttributes) throws Exception {
     return Response.status(Status.NOT_IMPLEMENTED).build();
   }
 
@@ -100,9 +100,9 @@
   @POST
   @Path("/.search")
   @Produces(Constants.SCIM_CONTENT_TYPE)
-  @ApiOperation(value = "Search", produces=Constants.SCIM_CONTENT_TYPE, response = ScimResource.class, responseContainer = "List", code = 200)
+  @ApiOperation(value = "Search", produces=Constants.SCIM_CONTENT_TYPE, response = ListResponse.class, code = 200)
   @ApiResponses(value = { @ApiResponse(code = 400, message = "Bad Request"), @ApiResponse(code = 500, message = "Internal Server Error"), @ApiResponse(code = 501, message = "Not Implemented") })
-  default Response find(SearchRequest request) {
+  default Response find(SearchRequest request) throws Exception {
     return Response.status(Status.NOT_IMPLEMENTED).build();
   }
 
@@ -120,7 +120,7 @@
   default Response update(T resource, 
                           @PathParam("id") String id,
                           @ApiParam(value="attributes", required=false) @QueryParam("attributes") AttributeReferenceListWrapper attributes,
-                          @ApiParam(value="excludedAttributes", required=false) @QueryParam("excludedAttributes") AttributeReferenceListWrapper excludedAttributes) {
+                          @ApiParam(value="excludedAttributes", required=false) @QueryParam("excludedAttributes") AttributeReferenceListWrapper excludedAttributes) throws Exception {
     return Response.status(Status.NOT_IMPLEMENTED).build();
   }
 
@@ -129,7 +129,7 @@
   @Produces(Constants.SCIM_CONTENT_TYPE)
   @ApiOperation(value = "Patch a portion of the backing store", produces=Constants.SCIM_CONTENT_TYPE, consumes=Constants.SCIM_CONTENT_TYPE, code = 204)
   @ApiResponses(value = { @ApiResponse(code = 400, message = "Bad Request"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error"), @ApiResponse(code = 501, message = "Not Implemented") })
-  default Response patch(PatchRequest patchRequest) {
+  default Response patch(PatchRequest patchRequest) throws Exception {
     return Response.status(Status.NOT_IMPLEMENTED).build();
   }
 
@@ -137,7 +137,7 @@
   @Path("{id}")
   @ApiOperation(value = "Delete from the backing store", code = 204)
   @ApiResponses(value = { @ApiResponse(code = 400, message = "Bad Request"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error"), @ApiResponse(code = 501, message = "Not Implemented") })
-  default Response delete(@ApiParam(value = "id", required = true) @PathParam("id") String id) {
+  default Response delete(@ApiParam(value = "id", required = true) @PathParam("id") String id) throws Exception {
     return Response.status(Status.NOT_IMPLEMENTED).build();
   }
 }
diff --git a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/ResourceTypesResource.java b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/ResourceTypesResource.java
index b38f3b2..1685b91 100644
--- a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/ResourceTypesResource.java
+++ b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/ResourceTypesResource.java
@@ -45,7 +45,7 @@
   @GET
   @Produces(Constants.SCIM_CONTENT_TYPE)
   @ApiOperation(value = "Get All Resource Types", produces=Constants.SCIM_CONTENT_TYPE)
-  default Response getAllResourceTypes(@QueryParam("filter") String filter) {
+  default Response getAllResourceTypes(@QueryParam("filter") String filter) throws Exception {
 
     if (filter != null) {
       return Response.status(Status.FORBIDDEN).build();
@@ -58,7 +58,7 @@
   @Path("{name}")
   @Produces(Constants.SCIM_CONTENT_TYPE)
   @ApiOperation(value = "Get Resource Type by URN", produces=Constants.SCIM_CONTENT_TYPE)
-  default Response getResourceType(@PathParam("name") String name) {
+  default Response getResourceType(@PathParam("name") String name) throws Exception {
     return Response.status(Status.NOT_IMPLEMENTED).build();
   }
 }
diff --git a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/attribute/AttributeReference.java b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/attribute/AttributeReference.java
index f675d47..18ad259 100644
--- a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/attribute/AttributeReference.java
+++ b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/attribute/AttributeReference.java
@@ -1,12 +1,16 @@
 package edu.psu.swe.scim.spec.protocol.attribute;
 
+import java.io.Serializable;
+
 import org.apache.commons.lang3.StringUtils;
 
 import edu.psu.swe.scim.spec.validator.Urn;
 import lombok.Data;
 
 @Data
-public class AttributeReference {
+public class AttributeReference implements Serializable {
+
+  private static final long serialVersionUID = -3559538009692681470L;
 
   @Urn
   String urn;
diff --git a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/data/ListResponse.java b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/data/ListResponse.java
index 4bcefa1..d882928 100644
--- a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/data/ListResponse.java
+++ b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/data/ListResponse.java
@@ -15,7 +15,9 @@
 @EqualsAndHashCode(callSuper = true)
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.NONE)
-public class ListResponse extends BaseResource {
+public class ListResponse<T> extends BaseResource {
+
+  private static final long serialVersionUID = -2381780997440673136L;
 
   public static final String SCHEMA_URI = "urn:ietf:params:scim:api:messages:2.0:ListResponse";
   
@@ -29,7 +31,7 @@
   Integer itemsPerPage;
 
   @XmlElement(name = "Resources")
-  List<Object> resources;
+  List<T> resources;
 
   public ListResponse() {
     super(SCHEMA_URI);
diff --git a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/data/SearchRequest.java b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/data/SearchRequest.java
index 49d691b..1308dfd 100644
--- a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/data/SearchRequest.java
+++ b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/data/SearchRequest.java
@@ -6,9 +6,12 @@
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+import edu.psu.swe.scim.spec.adapter.AttributeReferenceAdapter;
+import edu.psu.swe.scim.spec.adapter.FilterAdapter;
 import edu.psu.swe.scim.spec.protocol.attribute.AttributeReference;
 import edu.psu.swe.scim.spec.protocol.search.Filter;
 import edu.psu.swe.scim.spec.protocol.search.PageRequest;
@@ -29,18 +32,24 @@
 @XmlAccessorType(XmlAccessType.NONE)
 public class SearchRequest extends BaseResource {
 
+  private static final long serialVersionUID = 8217513543318598565L;
+
   public static final String SCHEMA_URI = "urn:ietf:params:scim:api:messages:2.0:SearchRequest";
 
   @XmlElement
+  @XmlJavaTypeAdapter(AttributeReferenceAdapter.class)
   Set<AttributeReference> attributes;
 
   @XmlElement
+  @XmlJavaTypeAdapter(AttributeReferenceAdapter.class)
   Set<AttributeReference> excludedAttributes;
 
   @XmlElement
+  @XmlJavaTypeAdapter(FilterAdapter.class)
   Filter filter;
 
   @XmlElement
+  @XmlJavaTypeAdapter(AttributeReferenceAdapter.class)
   AttributeReference sortBy;
 
   @XmlElement
diff --git a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/search/Filter.java b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/search/Filter.java
index ecf1cd8..7551b58 100644
--- a/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/search/Filter.java
+++ b/scim-spec/scim-spec-protocol/src/main/java/edu/psu/swe/scim/spec/protocol/search/Filter.java
@@ -38,6 +38,12 @@
     setFilter(filter);
   }
   
+  public Filter(FilterExpression filterExpression) {
+    log.info("Creating a filter - " + filterExpression.toString());
+    expression = filterExpression;
+    this.filter = filterExpression.toString();
+  }
+  
   /**
    * @param filter the filter to set
    * @throws FilterParseException 
@@ -69,4 +75,9 @@
       throw new FilterParseException(e);
     }
   }
+  
+  @Override
+  public String toString() {
+    return expression.toFilter();
+  }
 }
diff --git a/scim-spec/scim-spec-schema/pom.xml b/scim-spec/scim-spec-schema/pom.xml
index f303d99..249bb4b 100644
--- a/scim-spec/scim-spec-schema/pom.xml
+++ b/scim-spec/scim-spec-schema/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-spec</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-spec-schema</artifactId>
diff --git a/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/exception/InvalidExtensionException.java b/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/exception/InvalidExtensionException.java
index eb68616..1d4844d 100644
--- a/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/exception/InvalidExtensionException.java
+++ b/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/exception/InvalidExtensionException.java
@@ -1,6 +1,6 @@
 package edu.psu.swe.scim.spec.exception;
 
-public class InvalidExtensionException extends Exception {
+public class InvalidExtensionException extends RuntimeException {
   
   private static final long serialVersionUID = -4113730866775103565L;
 
diff --git a/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/exception/InvalidScimResourceException.java b/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/exception/InvalidScimResourceException.java
new file mode 100644
index 0000000..1b9c84f
--- /dev/null
+++ b/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/exception/InvalidScimResourceException.java
@@ -0,0 +1,10 @@
+package edu.psu.swe.scim.spec.exception;
+
+public class InvalidScimResourceException extends RuntimeException {
+  
+  private static final long serialVersionUID = -3378968149599082798L;
+
+  public InvalidScimResourceException(String what) {
+    super(what);
+  }
+}
diff --git a/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/extension/ScimExtensionRegistry.java b/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/extension/ScimExtensionRegistry.java
index 34b5e6e..c240a5c 100644
--- a/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/extension/ScimExtensionRegistry.java
+++ b/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/extension/ScimExtensionRegistry.java
@@ -3,6 +3,8 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import edu.psu.swe.scim.spec.annotation.ScimExtensionType;
+import edu.psu.swe.scim.spec.exception.InvalidExtensionException;
 import edu.psu.swe.scim.spec.resources.ScimExtension;
 import edu.psu.swe.scim.spec.resources.ScimResource;
 import lombok.extern.slf4j.Slf4j;
@@ -33,9 +35,14 @@
     return INSTANCE;
   }
   
-  public void registerExtension(Class<? extends ScimResource> resourceClass, ScimExtension scimExtension) {
-    String urn = scimExtension.getUrn();
-    Class<? extends ScimExtension> extensionClass = scimExtension.getClass();
+  public void registerExtension(Class<? extends ScimResource> resourceClass, Class<? extends ScimExtension> extensionClass) {
+    ScimExtensionType[] se = extensionClass.getAnnotationsByType(ScimExtensionType.class);
+
+    if (se.length == 0 || se.length > 1) {
+      throw new InvalidExtensionException("Registered extensions must have an ScimExtensionType annotation");
+    }
+    
+    String urn = se[0].id();
     
     log.debug("Registering extension for URN: " + urn);
     log.debug("    (associated resource class: " + resourceClass.getSimpleName() + ")");
@@ -43,7 +50,7 @@
     
     Map<String, Class<? extends ScimExtension>> resourceMap = registry.get(resourceClass);
     if(resourceMap == null) {
-      resourceMap = new HashMap<String, Class<? extends ScimExtension>>();
+      resourceMap = new HashMap<>();
       registry.put(resourceClass, resourceMap);
     }
     
diff --git a/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/resources/ScimResource.java b/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/resources/ScimResource.java
index d36875d..b806121 100644
--- a/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/resources/ScimResource.java
+++ b/scim-spec/scim-spec-schema/src/main/java/edu/psu/swe/scim/spec/resources/ScimResource.java
@@ -71,7 +71,12 @@
     this.baseUrn = urn;
   }
 
-  public void addExtension(ScimExtension extension) throws InvalidExtensionException {
+  /**
+   * Add an extension to the ScimResource
+   * @param extension the scim extension
+   * @throws InvalidExtensionException if the ScimExtension passed in is improperly configured.  
+   */
+  public void addExtension(ScimExtension extension) {
     ScimExtensionType[] se = extension.getClass().getAnnotationsByType(ScimExtensionType.class);
 
     if (se.length == 0 || se.length > 1) {
@@ -88,8 +93,14 @@
     return extensions.get(urn);
   }
   
+  /**
+   * Returns the scim extension of a particular class
+   * @param extensionClass 
+   * @return
+   * @throws InvalidExtensionException if the ScimExtension passed in is improperly configured.  
+   */
   @SuppressWarnings("unchecked")
-  public <T> T getExtension(Class<T> extensionClass) throws InvalidExtensionException {
+  public <T> T getExtension(Class<T> extensionClass) {
     ScimExtensionType[] se = extensionClass.getAnnotationsByType(ScimExtensionType.class);
 
     if (se.length == 0 || se.length > 1) {
diff --git a/scim-tools/pom.xml b/scim-tools/pom.xml
index 910eca6..457e9a6 100644
--- a/scim-tools/pom.xml
+++ b/scim-tools/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-parent</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-tools</artifactId>
diff --git a/scim-tools/scim-tools-cli/pom.xml b/scim-tools/scim-tools-cli/pom.xml
index 9502f10..dbb9ebf 100644
--- a/scim-tools/scim-tools-cli/pom.xml
+++ b/scim-tools/scim-tools-cli/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-tools</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-tools-cli</artifactId>
diff --git a/scim-tools/scim-tools-common/pom.xml b/scim-tools/scim-tools-common/pom.xml
index 3ff3839..c78c05a 100644
--- a/scim-tools/scim-tools-common/pom.xml
+++ b/scim-tools/scim-tools-common/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-tools</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-tools-common</artifactId>
diff --git a/scim-tools/scim-tools-studio/pom.xml b/scim-tools/scim-tools-studio/pom.xml
index 2a00d7c..be83f3b 100644
--- a/scim-tools/scim-tools-studio/pom.xml
+++ b/scim-tools/scim-tools-studio/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>edu.psu.swe.scim</groupId>
     <artifactId>scim-tools</artifactId>
-    <version>2.1</version>
+    <version>2.2</version>
   </parent>
 
   <artifactId>scim-tools-studio</artifactId>