Merge branch 'release/2.15'
diff --git a/pom.xml b/pom.xml
index 070f245..71f9272 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
 
   <groupId>edu.psu.swe.scim</groupId>
   <artifactId>scim-parent</artifactId>
-  <version>2.14</version>
+  <version>2.15</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>
diff --git a/scim-client/pom.xml b/scim-client/pom.xml
index d643221..3156e13 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.14</version>
+    <version>2.15</version>
   </parent>
   <artifactId>scim-client</artifactId>
   <name>SCIM - Client</name>
diff --git a/scim-common/pom.xml b/scim-common/pom.xml
index b017709..64eef9a 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.14</version>
+    <version>2.15</version>
   </parent>
 
   <artifactId>scim-common</artifactId>
@@ -14,12 +14,12 @@
     <dependency>
       <groupId>edu.psu.swe.scim</groupId>
       <artifactId>scim-spec-protocol</artifactId>
-      <version>2.14</version>
+      <version>2.15</version>
     </dependency>
     <dependency>
       <groupId>edu.psu.swe.scim</groupId>
       <artifactId>scim-spec-schema</artifactId>
-      <version>2.14</version>
+      <version>2.15</version>
     </dependency>
   </dependencies>
 
diff --git a/scim-compliance/pom.xml b/scim-compliance/pom.xml
index 882dc53..e9f860d 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.14</version>
+    <version>2.15</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 23fc0a0..0499e8f 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.14</version>
+    <version>2.15</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 592c846..3af381b 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.14</version>
+    <version>2.15</version>
   </parent>
 
   <artifactId>scim-compliance-server</artifactId>
diff --git a/scim-errai/pom.xml b/scim-errai/pom.xml
index 4fc8798..a21753f 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.14</version>
+    <version>2.15</version>
   </parent>
 
   <artifactId>scim-errai</artifactId>
diff --git a/scim-server/pom.xml b/scim-server/pom.xml
index 9233849..7fe957e 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.14</version>
+    <version>2.15</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 01eb4a4..e9e27b6 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.14</version>
+    <version>2.15</version>
   </parent>
 
   <artifactId>scim-server-common</artifactId>
diff --git a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/PrioritySortingComparitor.java b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/PrioritySortingComparitor.java
new file mode 100644
index 0000000..04cc674
--- /dev/null
+++ b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/PrioritySortingComparitor.java
@@ -0,0 +1,49 @@
+package edu.psu.swe.scim.server.provider;
+
+import java.util.Comparator;
+import java.util.Set;
+
+import edu.psu.swe.scim.spec.resources.TypedAttribute;
+
+public class PrioritySortingComparitor implements Comparator<Object> {
+
+  private Set<Object> priorities;
+
+  public PrioritySortingComparitor(Set<Object> priorities) {
+    this.priorities = priorities;
+  }
+
+  @Override
+  public int compare(Object o1, Object o2) {
+    if (o1 == null) {
+      return -1;
+    }
+    if (o2 == null) {
+      return 1;
+    }
+
+    Comparable c1 = getComparableValue(o1);
+    Comparable c2 = getComparableValue(o2);
+    
+    boolean o1Priority = priorities.contains(c1);
+    boolean o2Priority = priorities.contains(c2);
+
+    if (o1Priority == o2Priority) {
+      return c1.compareTo(c2);
+    } else {
+      return o1Priority ? -1 : 1;
+    }
+
+  }
+
+  public static Comparable getComparableValue(Object obj) {
+    if (obj instanceof TypedAttribute) {
+      TypedAttribute typed = (TypedAttribute) obj;
+      return typed.getType();
+    } else if (obj instanceof Comparable) {
+      return (Comparable) obj;
+    } else {
+      return obj.toString();
+    }
+  }
+}
\ No newline at end of file
diff --git a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/UpdateRequest.java b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/UpdateRequest.java
index de80ce2..6b7a21c 100644
--- a/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/UpdateRequest.java
+++ b/scim-server/scim-server-common/src/main/java/edu/psu/swe/scim/server/provider/UpdateRequest.java
@@ -5,10 +5,13 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 import javax.inject.Inject;
@@ -132,43 +135,47 @@
     return patchOperations;
   }
 
-  private void sortMultiValuedCollections(Object t, AttributeContainer ac) throws IllegalArgumentException, IllegalAccessException {
-    if (t != null) {
-      for (Attribute attribute : ac.getAttributes()) {
-        Field field = attribute.getField();
-        if (attribute.isMultiValued()) {
-          @SuppressWarnings("unchecked")
-          List<Object> collection = (List<Object>) field.get(t);
-          if (collection != null) {
-            Collections.sort(collection, (o1, o2) -> {
-              if (o1 == null) {
-                return -1;
-              }
-              if (o2 == null) {
-                return 1;
-              }
-              if (o1 instanceof TypedAttribute && o2 instanceof TypedAttribute) {
-                TypedAttribute t1 = (TypedAttribute) o1;
-                TypedAttribute t2 = (TypedAttribute) o2;
-                String type1 = t1.getType();
-                String type2 = t2.getType();
-                return type1.compareTo(type2);
-              }
-              if (o1 instanceof Comparable<?>) {
-                Comparable c1 = (Comparable)o1;
-                Comparable c2 = (Comparable)o2;
-                return c1.compareTo(c2);
-              }
-              return 0;
-            });
-          }
-        } else if (attribute.getType() == Attribute.Type.COMPLEX) {
-          sortMultiValuedCollections(field.get(t), attribute);
+  private void sortMultiValuedCollections(Object obj1, Object obj2, AttributeContainer ac) throws IllegalArgumentException, IllegalAccessException {
+    for (Attribute attribute : ac.getAttributes()) {
+      Field field = attribute.getField();
+      if (attribute.isMultiValued()) {
+        @SuppressWarnings("unchecked")
+        List<Object> collection1 = obj1 != null ? (List<Object>) field.get(obj1) : null;
+        @SuppressWarnings("unchecked")
+        List<Object> collection2 = obj2 != null ? (List<Object>) field.get(obj2) : null;
+        
+        Set<Object> priorities = findCommonElements(collection1, collection2);
+        PrioritySortingComparitor prioritySortingComparitor = new PrioritySortingComparitor(priorities);
+        if (collection1 != null) {
+          Collections.sort(collection1, prioritySortingComparitor);
         }
+        
+        if (collection2 != null) {
+          Collections.sort(collection2, prioritySortingComparitor);
+        }
+      } else if (attribute.getType() == Attribute.Type.COMPLEX) {
+        Object nextObj1 = obj1 != null ? field.get(obj1) : null;
+        Object nextObj2 = obj2 != null ? field.get(obj2) : null;
+        sortMultiValuedCollections(nextObj1, nextObj2, attribute);
       }
     }
   }
 
+  private Set<Object> findCommonElements(List<Object> list1, List<Object> list2) {
+    if (list1 == null || list2 == null) {
+      return Collections.emptySet();
+    }
+    
+    Set<Object> set1 = new HashSet<>(list1);
+    Set<Object> set2 = new HashSet<>(list2);
+    
+    set1 = set1.stream().map(PrioritySortingComparitor::getComparableValue).collect(Collectors.toSet());
+    set2 = set2.stream().map(PrioritySortingComparitor::getComparableValue).collect(Collectors.toSet());
+    
+    set1.retainAll(set2);
+    return set1;
+  }
+
   private T applyPatchOperations() {
     // TODO Auto-generated method stub
     return resource;
@@ -216,17 +223,18 @@
 
   private List<PatchOperation> createPatchOperations() throws IllegalArgumentException, IllegalAccessException, JsonProcessingException {
 
-    sortMultiValuedCollections(this.original, schema);
-    Map<String, ScimExtension> extensions = this.original.getExtensions();
-    for(Map.Entry<String, ScimExtension> entry : extensions.entrySet()) {
-      Schema extSchema = registry.getSchema(entry.getKey());
-      sortMultiValuedCollections(entry.getValue(), extSchema);
-    }
-    sortMultiValuedCollections(this.resource, schema);
-    extensions = this.resource.getExtensions();
-    for(Map.Entry<String, ScimExtension> entry : extensions.entrySet()) {
-      Schema extSchema = registry.getSchema(entry.getKey());
-      sortMultiValuedCollections(entry.getValue(), extSchema);
+    sortMultiValuedCollections(this.original, this.resource, schema);
+    Map<String, ScimExtension> originalExtensions = this.original.getExtensions();
+    Map<String, ScimExtension> resourceExtensions = this.resource.getExtensions();
+    Set<String> keys = new HashSet<>();
+    keys.addAll(originalExtensions.keySet());
+    keys.addAll(resourceExtensions.keySet());
+    
+    for(String key: keys) {
+      Schema extSchema = registry.getSchema(key);
+      ScimExtension originalExtension = originalExtensions.get(key);
+      ScimExtension resourceExtension = resourceExtensions.get(key);
+      sortMultiValuedCollections(originalExtension, resourceExtension, extSchema);
     }
 
     //Create a Jackson ObjectMapper that reads JaxB annotations
diff --git a/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/provider/PrioritySortingComparitorTest.java b/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/provider/PrioritySortingComparitorTest.java
new file mode 100644
index 0000000..7db82f4
--- /dev/null
+++ b/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/provider/PrioritySortingComparitorTest.java
@@ -0,0 +1,40 @@
+package edu.psu.swe.scim.server.provider;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+
+public class PrioritySortingComparitorTest {
+
+  @Test
+  public void testSorting() throws Exception {
+    Set<Object> priorities = new HashSet<>();
+    priorities.add("1P");
+    priorities.add("2P");
+    PrioritySortingComparitor comparitor = new PrioritySortingComparitor(priorities);
+    List<String> list = Arrays.asList("1", "2", "1P", "2P", "3", "4");
+    Collections.sort(list, comparitor);
+    System.out.println(list);
+    
+    Assertions.assertThat(list).hasSameElementsAs(Arrays.asList("1P", "2P", "1", "2", "3", "4"));
+  }
+
+  @Test
+  public void testSorting2() throws Exception {
+    Set<Object> priorities = new HashSet<>();
+    priorities.add("home");
+    priorities.add("work");
+    PrioritySortingComparitor comparitor = new PrioritySortingComparitor(priorities);
+    List<String> list = Arrays.asList("work", "local", "home");
+    Collections.sort(list, comparitor);
+    System.out.println(list);
+    
+    Assertions.assertThat(list).hasSameElementsAs(Arrays.asList("home", "work", "local"));
+  }
+  
+}
diff --git a/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/provider/UpdateRequestTest.java b/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/provider/UpdateRequestTest.java
index 8d61843..8b5fc58 100644
--- a/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/provider/UpdateRequestTest.java
+++ b/scim-server/scim-server-common/src/test/java/edu/psu/swe/scim/server/provider/UpdateRequestTest.java
@@ -1,5 +1,7 @@
 package edu.psu.swe.scim.server.provider;
 
+import static org.junit.Assert.assertEquals;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -8,8 +10,6 @@
 
 import javax.enterprise.inject.Instance;
 
-import lombok.extern.slf4j.Slf4j;
-
 import org.assertj.core.api.Assertions;
 import org.junit.Assert;
 import org.junit.Before;
@@ -42,6 +42,7 @@
 import edu.psu.swe.scim.spec.resources.PhoneNumber.GlobalPhoneNumberBuilder;
 import edu.psu.swe.scim.spec.resources.Photo;
 import edu.psu.swe.scim.spec.resources.ScimUser;
+import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
 public class UpdateRequestTest {
@@ -336,6 +337,55 @@
   }
   
   @Test
+  public void testRemoveMultiValuedAttributeWithSorting() throws Exception {
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
+
+    ScimUser user1 = createUser1();
+    ScimUser user2 = copy(user1);
+    
+    Address localAddress = new Address();
+    localAddress.setStreetAddress("123 Main Street");
+    localAddress.setLocality("State College");
+    localAddress.setRegion("PA");
+    localAddress.setCountry("USA");
+    localAddress.setType("local");
+    
+    user1.getAddresses().add(localAddress);
+    
+    updateRequest.initWithResource("1234", user1, user2);
+    List<PatchOperation> result = updateRequest.getPatchOperations();
+
+    PatchOperation actual = assertSingleResult(result);
+
+    checkAssertions(actual, Type.REMOVE, "addresses[type EQ \"local\"]", null);
+  }
+  
+  @Test
+  public void testAddMultiValuedAttributeWithSorting() throws Exception {
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
+
+    ScimUser user1 = createUser1();
+    ScimUser user2 = copy(user1);
+    
+    Address localAddress = new Address();
+    localAddress.setStreetAddress("123 Main Street");
+    localAddress.setLocality("State College");
+    localAddress.setRegion("PA");
+    localAddress.setCountry("USA");
+    localAddress.setType("local");
+    
+    user2.getAddresses().add(localAddress);
+    user1.getAddresses().get(0).setKey("asdf");
+    
+    updateRequest.initWithResource("1234", user1, user2);
+    List<PatchOperation> result = updateRequest.getPatchOperations();
+
+    assertEquals(2, result.size());
+
+    checkAssertions(result.get(1), Type.ADD, "addresses", localAddress);
+  }
+  
+  @Test
   public void verifyEmptyArraysDoNotCauseMove() throws Exception {
     UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
 
diff --git a/scim-server/scim-server-example/pom.xml b/scim-server/scim-server-example/pom.xml
index b327ea9..38a987d 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.14</version>
+    <version>2.15</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 4e376a6..4e62664 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.14</version>
+    <version>2.15</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 28da7e9..a3c1800 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.14</version>
+    <version>2.15</version>
   </parent>
 
   <artifactId>scim-server-memory</artifactId>
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 701eeb9..b5ccd33 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.14</version>
+    <version>2.15</version>
   </parent>
 
   <artifactId>scim-server-rdbms</artifactId>
diff --git a/scim-spec/pom.xml b/scim-spec/pom.xml
index 3bfc170..559ab76 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.14</version>
+    <version>2.15</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 3ee7855..f507c57 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.14</version>
+    <version>2.15</version>
   </parent>
 
   <artifactId>scim-spec-protocol</artifactId>
diff --git a/scim-spec/scim-spec-schema/pom.xml b/scim-spec/scim-spec-schema/pom.xml
index bfa5fbf..68ee275 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.14</version>
+		<version>2.15</version>
 	</parent>
 
 	<artifactId>scim-spec-schema</artifactId>
diff --git a/scim-tools/pom.xml b/scim-tools/pom.xml
index ca2b1f6..f84ad0b 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.14</version>
+    <version>2.15</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 ddae179..9264b2c 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.14</version>
+    <version>2.15</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 29dcd84..645cdbc 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.14</version>
+    <version>2.15</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 720174b..dfcdae6 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.14</version>
+    <version>2.15</version>
   </parent>
 
   <artifactId>scim-tools-studio</artifactId>