/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.asakusafw.testdriver.core;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
/**
* The normal-form of property names.
* @since 0.2.0
* @version 0.9.1
*/
public final class PropertyName implements Comparable<PropertyName>, Serializable {
private static final long serialVersionUID = -362878710044414915L;
/**
* The system property key of property name segment separator.
* @since 0.7.0
*/
public static final String KEY_SEGMENT_SEPARATOR =
"com.asakusafw.testdriver.property.segmentSeparator"; //$NON-NLS-1$
static final String DEFAULT_SEGMENT_SEPARATOR = "-"; //$NON-NLS-1$
static final String SEGMENT_SEPARATOR;
static {
String separator = null;
try {
separator = System.getProperty(KEY_SEGMENT_SEPARATOR, DEFAULT_SEGMENT_SEPARATOR);
} catch (RuntimeException e) {
e.printStackTrace();
}
if (separator == null || separator.isEmpty()) {
separator = DEFAULT_SEGMENT_SEPARATOR;
}
SEGMENT_SEPARATOR = separator;
}
private final List<String> originalWords;
private final List<String> normalized;
/**
* Creates a new instance.
* @param words the words which consists this name
* @throws IllegalArgumentException if some parameters were {@code null}
*/
private PropertyName(List<String> words) {
this.originalWords = words;
this.normalized = normalize(words);
}
private static List<String> normalize(List<String> words) {
assert words != null;
List<String> results = new ArrayList<>(words.size());
Iterator<String> iter = words.iterator();
assert iter.hasNext();
String last = iter.next();
while (iter.hasNext()) {
String next = iter.next();
assert next.isEmpty() == false;
char c = next.charAt(0);
if ('0' <= c && c <= '9') {
last += next;
} else {
results.add(last);
last = next;
}
}
results.add(last);
return Collections.unmodifiableList(results);
}
/**
* Creates a new instance.
* @param words the words which consists this name
* @return the created instance
* @throws IllegalArgumentException if some parameters were {@code null}
*/
public static PropertyName newInstance(List<String> words) {
if (words == null) {
throw new IllegalArgumentException("words must not be null"); //$NON-NLS-1$
}
if (words.isEmpty()) {
throw new IllegalArgumentException("words must not be empty"); //$NON-NLS-1$
}
List<String> work = new ArrayList<>(words.size());
for (String w : words) {
work.add(normalize(w));
}
return new PropertyName(work);
}
/**
* Creates a new instance.
* @param words the words which consists this name
* @return the created instance
* @throws IllegalArgumentException if some parameters were {@code null}
*/
public static PropertyName newInstance(String... words) {
if (words == null) {
throw new IllegalArgumentException("words must not be null"); //$NON-NLS-1$
}
return newInstance(Arrays.asList(words));
}
/**
* Parses a property name term and creates a new instance.
* @param term the property name term
* @return the created instance
* @since 0.9.1
*/
public static PropertyName parse(String term) {
Objects.requireNonNull(term);
if (term.isEmpty()) {
throw new IllegalArgumentException();
} else if (term.indexOf('_') >= 0 || term.toUpperCase(Locale.ENGLISH).equals(term)) {
String[] segments = term.split("_"); //$NON-NLS-1$
return newInstance(segments);
} else {
List<String> segments = new ArrayList<>();
int start = 0;
for (int i = 1, n = term.length(); i < n; i++) {
if (Character.isUpperCase(term.charAt(i))) {
segments.add(term.substring(start, i));
start = i;
}
}
segments.add(term.substring(start));
return newInstance(segments);
}
}
private static String normalize(String word) {
if (word == null) {
throw new IllegalArgumentException("word must not be null"); //$NON-NLS-1$
}
return word.toLowerCase();
}
/**
* Returns the words which consists this property name.
* @return the words in this property name
*/
public List<String> getWords() {
return originalWords;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + normalized.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PropertyName other = (PropertyName) obj;
if (!normalized.equals(other.normalized)) {
return false;
}
return true;
}
@Override
public int compareTo(PropertyName o) {
Iterator<String> left = normalized.iterator();
Iterator<String> right = o.normalized.iterator();
while (true) {
if (left.hasNext() == false) {
if (right.hasNext() == false) {
break;
}
return -1;
}
if (right.hasNext() == false) {
return +1;
}
int diff = left.next().compareTo(right.next());
if (diff != 0) {
return diff;
}
}
return 0;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
Iterator<String> iter = originalWords.iterator();
assert iter.hasNext();
buf.append(iter.next());
while (iter.hasNext()) {
buf.append(SEGMENT_SEPARATOR);
buf.append(iter.next());
}
return buf.toString();
}
}