001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.isis.core.metamodel.layout.memberorderfacet; 021 022import java.util.Comparator; 023import java.util.StringTokenizer; 024 025import org.apache.isis.core.metamodel.facets.members.order.MemberOrderFacet; 026 027public class MemberOrderFacetComparator implements Comparator<MemberOrderFacet> { 028 029 private boolean ensureInSameGroup; 030 public MemberOrderFacetComparator(boolean ensureInSameGroup) { 031 this.ensureInSameGroup = ensureInSameGroup; 032 } 033 034 @Override 035 public int compare(final MemberOrderFacet m1, final MemberOrderFacet m2) { 036 if (m1 == null && m2 == null) { 037 return 0; 038 } 039 040 if (m1 == null && m2 != null) { 041 return +1; // annotated before non-annotated 042 } 043 if (m1 != null && m2 == null) { 044 return -1; // annotated before non-annotated 045 } 046 047 if (ensureInSameGroup && !m1.name().equals(m2.name())) { 048 throw new IllegalArgumentException("Not in same group"); 049 } 050 051 final String sequence1 = m1.sequence(); 052 final String sequence2 = m2.sequence(); 053 054 final String[] components1 = componentsFor(sequence1); 055 final String[] components2 = componentsFor(sequence2); 056 057 final int length1 = components1.length; 058 final int length2 = components2.length; 059 060 // shouldn't happen but just in case. 061 if (length1 == 0 && length2 == 0) { 062 return 0; 063 } 064 065 // continue to loop until we run out of components. 066 int n = 0; 067 while (true) { 068 final int length = n + 1; 069 // check if run out of components in either side 070 if (length1 < length && length2 >= length) { 071 return -1; // o1 before o2 072 } 073 if (length2 < length && length1 >= length) { 074 return +1; // o2 before o1 075 } 076 if (length1 < length && length2 < length) { 077 // run out of components 078 return 0; 079 } 080 // we have this component on each side 081 082 int componentCompare = 0; 083 try { 084 final Integer c1 = Integer.valueOf(components1[n]); 085 final Integer c2 = Integer.valueOf(components2[n]); 086 componentCompare = c1.compareTo(c2); 087 } catch (final NumberFormatException nfe) { 088 // not integers compare as strings 089 componentCompare = components1[n].compareTo(components2[n]); 090 } 091 092 if (componentCompare != 0) { 093 return componentCompare; 094 } 095 // this component is the same; lets look at the next 096 n++; 097 } 098 } 099 100 private static String[] componentsFor(final String sequence) { 101 final StringTokenizer tokens = new StringTokenizer(sequence, ".", false); 102 final String[] components = new String[tokens.countTokens()]; 103 for (int i = 0; tokens.hasMoreTokens(); i++) { 104 components[i] = tokens.nextToken(); 105 } 106 return components; 107 } 108 109 110}