Remove dependencies
This commit is contained in:
parent
62aad904d4
commit
4fa55d6bbc
@ -60,7 +60,6 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
compile 'org.solovyev:common-msg:1.0.7'
|
|
||||||
compile 'com.android.support:support-v4:23.2.0'
|
compile 'com.android.support:support-v4:23.2.0'
|
||||||
compile 'com.android.support:appcompat-v7:23.2.0'
|
compile 'com.android.support:appcompat-v7:23.2.0'
|
||||||
compile 'com.android.support:cardview-v7:23.2.0'
|
compile 'com.android.support:cardview-v7:23.2.0'
|
||||||
|
@ -48,9 +48,7 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.squareup.otto.Bus;
|
import com.squareup.otto.Bus;
|
||||||
|
|
||||||
import org.solovyev.android.Check;
|
import org.solovyev.android.Check;
|
||||||
import org.solovyev.android.calculator.floating.FloatingCalculatorService;
|
import org.solovyev.android.calculator.floating.FloatingCalculatorService;
|
||||||
import org.solovyev.android.calculator.ga.Ga;
|
import org.solovyev.android.calculator.ga.Ga;
|
||||||
@ -60,12 +58,10 @@ import org.solovyev.android.calculator.wizard.CalculatorWizards;
|
|||||||
import org.solovyev.android.wizard.Wizards;
|
import org.solovyev.android.wizard.Wizards;
|
||||||
import org.solovyev.common.JPredicate;
|
import org.solovyev.common.JPredicate;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class aggregates several useful in any Android application interfaces and provides access to {@link android.app.Application} object from a static context.
|
* This class aggregates several useful in any Android application interfaces and provides access to {@link android.app.Application} object from a static context.
|
||||||
@ -262,18 +258,6 @@ public final class App {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T find(@Nullable Collection<T> collection, @Nonnull JPredicate<T> finder) {
|
|
||||||
if (collection == null || collection.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (T t : collection) {
|
|
||||||
if (finder.apply(t)) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String find(@Nonnull List<String> tokens, @Nonnull String text, int position) {
|
public static String find(@Nonnull List<String> tokens, @Nonnull String text, int position) {
|
||||||
for (int i = 0; i < tokens.size(); i++) {
|
for (int i = 0; i < tokens.size(); i++) {
|
||||||
|
@ -23,9 +23,9 @@
|
|||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.TextUtils;
|
||||||
import jscl.NumeralBase;
|
import jscl.NumeralBase;
|
||||||
import org.solovyev.android.calculator.math.MathType;
|
import org.solovyev.android.calculator.math.MathType;
|
||||||
import org.solovyev.common.text.Strings;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -60,7 +60,7 @@ public abstract class BaseNumberBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean spaceBefore(@Nonnull MathType.Result mathTypeResult) {
|
private boolean spaceBefore(@Nonnull MathType.Result mathTypeResult) {
|
||||||
return numberBuilder == null && Strings.isEmpty(mathTypeResult.match.trim());
|
return numberBuilder == null && TextUtils.isEmpty(mathTypeResult.match.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean numeralBaseInTheStart(@Nonnull MathType mathType) {
|
private boolean numeralBaseInTheStart(@Nonnull MathType mathType) {
|
||||||
|
@ -26,39 +26,8 @@ import android.content.SharedPreferences;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.squareup.otto.Bus;
|
import com.squareup.otto.Bus;
|
||||||
import com.squareup.otto.Subscribe;
|
import com.squareup.otto.Subscribe;
|
||||||
|
|
||||||
import org.solovyev.android.Check;
|
|
||||||
import org.solovyev.android.calculator.calculations.CalculationCancelledEvent;
|
|
||||||
import org.solovyev.android.calculator.calculations.CalculationFailedEvent;
|
|
||||||
import org.solovyev.android.calculator.calculations.CalculationFinishedEvent;
|
|
||||||
import org.solovyev.android.calculator.calculations.ConversionFailedEvent;
|
|
||||||
import org.solovyev.android.calculator.calculations.ConversionFinishedEvent;
|
|
||||||
import org.solovyev.android.calculator.functions.FunctionsRegistry;
|
|
||||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
|
||||||
import org.solovyev.android.calculator.variables.CppVariable;
|
|
||||||
import org.solovyev.common.msg.ListMessageRegistry;
|
|
||||||
import org.solovyev.common.msg.Message;
|
|
||||||
import org.solovyev.common.msg.MessageRegistry;
|
|
||||||
import org.solovyev.common.msg.MessageType;
|
|
||||||
import org.solovyev.common.text.Strings;
|
|
||||||
import org.solovyev.common.units.ConversionException;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import jscl.JsclArithmeticException;
|
import jscl.JsclArithmeticException;
|
||||||
import jscl.MathEngine;
|
import jscl.MathEngine;
|
||||||
import jscl.NumeralBase;
|
import jscl.NumeralBase;
|
||||||
@ -67,6 +36,28 @@ import jscl.math.Generic;
|
|||||||
import jscl.math.function.Constants;
|
import jscl.math.function.Constants;
|
||||||
import jscl.math.function.IConstant;
|
import jscl.math.function.IConstant;
|
||||||
import jscl.text.ParseInterruptedException;
|
import jscl.text.ParseInterruptedException;
|
||||||
|
import org.solovyev.android.Check;
|
||||||
|
import org.solovyev.android.calculator.calculations.*;
|
||||||
|
import org.solovyev.android.calculator.functions.FunctionsRegistry;
|
||||||
|
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||||
|
import org.solovyev.android.calculator.variables.CppVariable;
|
||||||
|
import org.solovyev.common.msg.ListMessageRegistry;
|
||||||
|
import org.solovyev.common.msg.Message;
|
||||||
|
import org.solovyev.common.msg.MessageRegistry;
|
||||||
|
import org.solovyev.common.msg.MessageType;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import javax.measure.converter.ConversionException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class Calculator implements SharedPreferences.OnSharedPreferenceChangeListener {
|
public class Calculator implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
@ -166,7 +157,7 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis
|
|||||||
@Nonnull String e,
|
@Nonnull String e,
|
||||||
@Nonnull MessageRegistry mr) {
|
@Nonnull MessageRegistry mr) {
|
||||||
e = e.trim();
|
e = e.trim();
|
||||||
if (Strings.isEmpty(e)) {
|
if (TextUtils.isEmpty(e)) {
|
||||||
bus.post(new CalculationFinishedEvent(o, e, sequence));
|
bus.post(new CalculationFinishedEvent(o, e, sequence));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,15 @@
|
|||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.text.TextUtils;
|
||||||
import com.squareup.otto.Bus;
|
import com.squareup.otto.Bus;
|
||||||
import jscl.AngleUnit;
|
import jscl.AngleUnit;
|
||||||
import jscl.JsclMathEngine;
|
import jscl.JsclMathEngine;
|
||||||
import jscl.MathEngine;
|
import jscl.MathEngine;
|
||||||
import jscl.NumeralBase;
|
import jscl.NumeralBase;
|
||||||
import jscl.math.operator.Operator;
|
import jscl.math.operator.Operator;
|
||||||
import jscl.text.*;
|
import jscl.text.Identifier;
|
||||||
|
import jscl.text.Parser;
|
||||||
import org.solovyev.android.Check;
|
import org.solovyev.android.Check;
|
||||||
import org.solovyev.android.calculator.functions.FunctionsRegistry;
|
import org.solovyev.android.calculator.functions.FunctionsRegistry;
|
||||||
import org.solovyev.android.calculator.operators.OperatorsRegistry;
|
import org.solovyev.android.calculator.operators.OperatorsRegistry;
|
||||||
@ -40,7 +42,6 @@ import org.solovyev.android.prefs.Preference;
|
|||||||
import org.solovyev.android.prefs.StringPreference;
|
import org.solovyev.android.prefs.StringPreference;
|
||||||
import org.solovyev.common.text.EnumMapper;
|
import org.solovyev.common.text.EnumMapper;
|
||||||
import org.solovyev.common.text.NumberMapper;
|
import org.solovyev.common.text.NumberMapper;
|
||||||
import org.solovyev.common.text.Strings;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -104,7 +105,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isValidName(@Nullable String name) {
|
public static boolean isValidName(@Nullable String name) {
|
||||||
if (!Strings.isEmpty(name)) {
|
if (!TextUtils.isEmpty(name)) {
|
||||||
try {
|
try {
|
||||||
Identifier.parser.parse(Parser.Parameters.get(name), null);
|
Identifier.parser.parse(Parser.Parameters.get(name), null);
|
||||||
return true;
|
return true;
|
||||||
@ -205,7 +206,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene
|
|||||||
mathEngine.setRoundResult(Preferences.Output.round.getPreference(preferences));
|
mathEngine.setRoundResult(Preferences.Output.round.getPreference(preferences));
|
||||||
|
|
||||||
final String groupingSeparator = Preferences.groupingSeparator.getPreference(preferences);
|
final String groupingSeparator = Preferences.groupingSeparator.getPreference(preferences);
|
||||||
if (Strings.isEmpty(groupingSeparator)) {
|
if (TextUtils.isEmpty(groupingSeparator)) {
|
||||||
mathEngine.setUseGroupingSeparator(false);
|
mathEngine.setUseGroupingSeparator(false);
|
||||||
} else {
|
} else {
|
||||||
mathEngine.setUseGroupingSeparator(true);
|
mathEngine.setUseGroupingSeparator(true);
|
||||||
|
@ -34,16 +34,14 @@ import org.solovyev.android.Check;
|
|||||||
import org.solovyev.android.calculator.*;
|
import org.solovyev.android.calculator.*;
|
||||||
import org.solovyev.android.calculator.entities.BaseEntitiesFragment;
|
import org.solovyev.android.calculator.entities.BaseEntitiesFragment;
|
||||||
import org.solovyev.android.calculator.entities.Category;
|
import org.solovyev.android.calculator.entities.Category;
|
||||||
import org.solovyev.android.calculator.RemovalConfirmationDialog;
|
|
||||||
import org.solovyev.android.calculator.math.MathType;
|
import org.solovyev.android.calculator.math.MathType;
|
||||||
import org.solovyev.common.JPredicate;
|
|
||||||
import org.solovyev.common.collections.Collections;
|
|
||||||
import org.solovyev.common.text.Strings;
|
import org.solovyev.common.text.Strings;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class VariablesFragment extends BaseEntitiesFragment<IConstant> {
|
public class VariablesFragment extends BaseEntitiesFragment<IConstant> {
|
||||||
@ -77,16 +75,17 @@ public class VariablesFragment extends BaseEntitiesFragment<IConstant> {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
protected List<IConstant> getEntities() {
|
protected List<IConstant> getEntities() {
|
||||||
final List<IConstant> result = new ArrayList<>(registry.getEntities());
|
final List<IConstant> entities = new ArrayList<>(registry.getEntities());
|
||||||
|
for (Iterator<IConstant> it = entities.iterator(); it.hasNext(); ) {
|
||||||
Collections.removeAll(result, new JPredicate<IConstant>() {
|
final IConstant constant = it.next();
|
||||||
@Override
|
switch (constant.getName()) {
|
||||||
public boolean apply(@Nullable IConstant var) {
|
case MathType.INFINITY_JSCL:
|
||||||
return var != null && Collections.contains(var.getName(), MathType.INFINITY_JSCL, MathType.NAN);
|
case MathType.NAN:
|
||||||
|
it.remove();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
return entities;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -24,7 +24,6 @@ apply plugin: 'java'
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
compile 'org.solovyev:common-msg:1.0.7'
|
|
||||||
compile 'com.google.code.findbugs:annotations:2.0.1'
|
compile 'com.google.code.findbugs:annotations:2.0.1'
|
||||||
compile 'xerces:xercesImpl:2.8.0'
|
compile 'xerces:xercesImpl:2.8.0'
|
||||||
|
|
||||||
|
@ -9,16 +9,16 @@ import jscl.math.operator.Percent;
|
|||||||
import jscl.math.operator.Rand;
|
import jscl.math.operator.Rand;
|
||||||
import jscl.math.operator.matrix.OperatorsRegistry;
|
import jscl.math.operator.matrix.OperatorsRegistry;
|
||||||
import jscl.text.ParseException;
|
import jscl.text.ParseException;
|
||||||
import org.solovyev.common.JPredicate;
|
|
||||||
import org.solovyev.common.collections.Collections;
|
|
||||||
import org.solovyev.common.math.MathRegistry;
|
import org.solovyev.common.math.MathRegistry;
|
||||||
import org.solovyev.common.msg.MessageRegistry;
|
import org.solovyev.common.msg.MessageRegistry;
|
||||||
import org.solovyev.common.msg.Messages;
|
import org.solovyev.common.msg.Messages;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.DecimalFormatSymbols;
|
import java.text.DecimalFormatSymbols;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class JsclMathEngine implements MathEngine {
|
public class JsclMathEngine implements MathEngine {
|
||||||
@ -165,20 +165,7 @@ public class JsclMathEngine implements MathEngine {
|
|||||||
// decimal numeral base => do specific formatting
|
// decimal numeral base => do specific formatting
|
||||||
|
|
||||||
// detect if current number is precisely equals to constant in constants' registry (NOTE: ONLY FOR SYSTEM CONSTANTS)
|
// detect if current number is precisely equals to constant in constants' registry (NOTE: ONLY FOR SYSTEM CONSTANTS)
|
||||||
final Double localValue = value;
|
IConstant constant = findConstant(getConstantsRegistry().getSystemEntities(), value);
|
||||||
IConstant constant = Collections.find(getConstantsRegistry().getSystemEntities(), new JPredicate<IConstant>() {
|
|
||||||
public boolean apply(@Nonnull IConstant constant) {
|
|
||||||
if (!localValue.equals(constant.getDoubleValue())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final String name = constant.getName();
|
|
||||||
if (name.equals(Constants.PI_INV.getName()) || name.equals(Constants.ANS)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !name.equals(Constants.PI.getName()) || getAngleUnits() == AngleUnit.rad;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
if (constant == null) {
|
if (constant == null) {
|
||||||
final IConstant piInv = this.getConstantsRegistry().get(Constants.PI_INV.getName());
|
final IConstant piInv = this.getConstantsRegistry().get(Constants.PI_INV.getName());
|
||||||
@ -231,6 +218,24 @@ public class JsclMathEngine implements MathEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private IConstant findConstant(@Nonnull List<IConstant> constants, @Nonnull Double value) {
|
||||||
|
for (int i = 0; i < constants.size(); i++) {
|
||||||
|
final IConstant constant = constants.get(i);
|
||||||
|
if (!value.equals(constant.getDoubleValue())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final String name = constant.getName();
|
||||||
|
if (name.equals(Constants.PI_INV.getName()) || name.equals(Constants.ANS)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!name.equals(Constants.PI.getName()) || getAngleUnits() == AngleUnit.rad) {
|
||||||
|
return constant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public String convert(@Nonnull Double value, @Nonnull NumeralBase to) {
|
public String convert(@Nonnull Double value, @Nonnull NumeralBase to) {
|
||||||
String ungroupedValue;
|
String ungroupedValue;
|
||||||
|
@ -2,7 +2,6 @@ package jscl.math.function;
|
|||||||
|
|
||||||
import org.solovyev.common.JBuilder;
|
import org.solovyev.common.JBuilder;
|
||||||
import org.solovyev.common.math.MathEntity;
|
import org.solovyev.common.math.MathEntity;
|
||||||
import org.solovyev.common.text.Strings;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -50,7 +49,7 @@ public class ExtendedConstant implements Comparable<ExtendedConstant>, IConstant
|
|||||||
final Double doubleValue = constant.getDoubleValue();
|
final Double doubleValue = constant.getDoubleValue();
|
||||||
if (doubleValue == null) {
|
if (doubleValue == null) {
|
||||||
final String stringValue = constant.getValue();
|
final String stringValue = constant.getValue();
|
||||||
if (!Strings.isEmpty(stringValue)) {
|
if (stringValue != null && stringValue.length() > 0) {
|
||||||
return constant.getName() + " = " + stringValue;
|
return constant.getName() + " = " + stringValue;
|
||||||
} else {
|
} else {
|
||||||
return constant.getName();
|
return constant.getName();
|
||||||
|
38
jscl/src/main/java/org/solovyev/common/Converter.java
Normal file
38
jscl/src/main/java/org/solovyev/common/Converter.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface converts one object to another
|
||||||
|
*
|
||||||
|
* @param <FROM> type of object to be converted
|
||||||
|
* @param <TO> type of result object (converted object)
|
||||||
|
*/
|
||||||
|
public interface Converter<FROM, TO> {
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
TO convert(@Nonnull FROM from);
|
||||||
|
}
|
||||||
|
|
79
jscl/src/main/java/org/solovyev/common/EqualsResult.java
Normal file
79
jscl/src/main/java/org/solovyev/common/EqualsResult.java
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common;
|
||||||
|
|
||||||
|
import org.solovyev.common.equals.Equalizer;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class EqualsResult<T> {
|
||||||
|
|
||||||
|
public static final Integer BOTH_NULLS_CONST = 0;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Integer result;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final T o1;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final T o2;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Equalizer<? super T> equalizer;
|
||||||
|
|
||||||
|
EqualsResult(@Nullable T o1, @Nullable T o2, @Nullable Equalizer<? super T> equalizer) {
|
||||||
|
this.equalizer = equalizer;
|
||||||
|
if (o1 == null && o2 == null) {
|
||||||
|
result = EqualsResult.BOTH_NULLS_CONST;
|
||||||
|
} else if (o1 == null) {
|
||||||
|
result = -1;
|
||||||
|
} else if (o2 == null) {
|
||||||
|
result = 1;
|
||||||
|
} else {
|
||||||
|
//both not nulls
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
this.o1 = o1;
|
||||||
|
this.o2 = o2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Integer getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean areBothNotNulls() {
|
||||||
|
return result == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean areBothNulls() {
|
||||||
|
return result != null && result.equals(BOTH_NULLS_CONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean areEqual() {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
boolean areSame = o1 == o2;
|
||||||
|
return areBothNulls() || areSame || (areBothNotNulls() && (equalizer == null ? o1.equals(o2) : equalizer.areEqual(o1, o2)));
|
||||||
|
}
|
||||||
|
}
|
550
jscl/src/main/java/org/solovyev/common/HashCodeBuilder.java
Normal file
550
jscl/src/main/java/org/solovyev/common/HashCodeBuilder.java
Normal file
@ -0,0 +1,550 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Assists in implementing {@link Object#hashCode()} methods.
|
||||||
|
* </p>
|
||||||
|
* <p/>
|
||||||
|
* <p>
|
||||||
|
* This class enables a good <code>hashCode</code> method to be built for any class. It follows the rules laid out in
|
||||||
|
* the book <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a> by Joshua Bloch. Writing a
|
||||||
|
* good <code>hashCode</code> method is actually quite difficult. This class aims to simplify the process.
|
||||||
|
* </p>
|
||||||
|
* <p/>
|
||||||
|
* <p>
|
||||||
|
* All relevant fields from the object should be included in the <code>hashCode</code> method. Derived fields may be
|
||||||
|
* excluded. In general, any field used in the <code>equals</code> method must be used in the <code>hashCode</code>
|
||||||
|
* method.
|
||||||
|
* </p>
|
||||||
|
* <p/>
|
||||||
|
* <p>
|
||||||
|
* To use this class write code as follows:
|
||||||
|
* </p>
|
||||||
|
* <p/>
|
||||||
|
* <pre>
|
||||||
|
* public class Person {
|
||||||
|
* String name;
|
||||||
|
* int age;
|
||||||
|
* boolean smoker;
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* public int hashCode() {
|
||||||
|
* // you pick a hard-coded, randomly chosen, non-zero, odd number
|
||||||
|
* // ideally different for each class
|
||||||
|
* return new HashCodeBuilder(17, 37).
|
||||||
|
* append(name).
|
||||||
|
* append(age).
|
||||||
|
* append(smoker).
|
||||||
|
* toHashCode();
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
* <p/>
|
||||||
|
* <p>
|
||||||
|
* If required, the superclass <code>hashCode()</code> can be added using {@link #appendSuper}.
|
||||||
|
* </p>
|
||||||
|
* <p/>
|
||||||
|
* <p>
|
||||||
|
* Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are
|
||||||
|
* usually private, the method, <code>reflectionHashCode</code>, uses <code>AccessibleObject.setAccessible</code>
|
||||||
|
* to change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions
|
||||||
|
* are set up correctly. It is also slower than testing explicitly.
|
||||||
|
* </p>
|
||||||
|
* <p/>
|
||||||
|
* <p>
|
||||||
|
* A typical invocation for this method would look like:
|
||||||
|
* </p>
|
||||||
|
* <p/>
|
||||||
|
* <pre>
|
||||||
|
* public int hashCode() {
|
||||||
|
* return HashCodeBuilder.reflectionHashCode(this);
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author Apache Software Foundation
|
||||||
|
* @author Gary Gregory
|
||||||
|
* @author Pete Gieser
|
||||||
|
* @author Sergey Solovyev
|
||||||
|
* @version $Id: HashCodeBuilder.java 907376 2010-02-07 03:43:02Z mbenson $
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public class HashCodeBuilder {
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* FIELDS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant to use in building the hashCode.
|
||||||
|
*/
|
||||||
|
private final int constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Running total of the hashCode.
|
||||||
|
*/
|
||||||
|
private int total = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* CONSTRUCTORS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Uses two hard coded choices for the constants needed to build a <code>hashCode</code>.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
private HashCodeBuilder() {
|
||||||
|
constant = 37;
|
||||||
|
total = 17;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
|
||||||
|
* however this is not vital.
|
||||||
|
* </p>
|
||||||
|
* <p/>
|
||||||
|
* <p>
|
||||||
|
* Prime numbers are preferred, especially for the multiplier.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param initialNonZeroOddNumber a non-zero, odd number used as the initial value
|
||||||
|
* @param multiplierNonZeroOddNumber a non-zero, odd number used as the multiplier
|
||||||
|
* @throws IllegalArgumentException if the number is zero or even
|
||||||
|
*/
|
||||||
|
private HashCodeBuilder(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber) {
|
||||||
|
if (initialNonZeroOddNumber == 0) {
|
||||||
|
throw new IllegalArgumentException("HashCodeBuilder requires a non zero initial value");
|
||||||
|
}
|
||||||
|
if (initialNonZeroOddNumber % 2 == 0) {
|
||||||
|
throw new IllegalArgumentException("HashCodeBuilder requires an odd initial value");
|
||||||
|
}
|
||||||
|
if (multiplierNonZeroOddNumber == 0) {
|
||||||
|
throw new IllegalArgumentException("HashCodeBuilder requires a non zero multiplier");
|
||||||
|
}
|
||||||
|
if (multiplierNonZeroOddNumber % 2 == 0) {
|
||||||
|
throw new IllegalArgumentException("HashCodeBuilder requires an odd multiplier");
|
||||||
|
}
|
||||||
|
constant = multiplierNonZeroOddNumber;
|
||||||
|
total = initialNonZeroOddNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static HashCodeBuilder newInstance() {
|
||||||
|
return new HashCodeBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static HashCodeBuilder newInstance(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber) {
|
||||||
|
return new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* METHODS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>boolean</code>.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* This adds <code>constant * 1</code> to the <code>hashCode</code> and not a <code>1231</code> or
|
||||||
|
* <code>1237</code> as done in java.lang.Boolean. This is in accordance with the <quote>Effective Java</quote>
|
||||||
|
* design.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value the boolean to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(boolean value) {
|
||||||
|
total = total * constant + (value ? 0 : 1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>boolean</code> array.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param array the array to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(boolean[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
total = total * constant;
|
||||||
|
} else {
|
||||||
|
for (boolean element : array) {
|
||||||
|
append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>byte</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value the byte to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(byte value) {
|
||||||
|
total = total * constant + value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>byte</code> array.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param array the array to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(byte[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
total = total * constant;
|
||||||
|
} else {
|
||||||
|
for (byte element : array) {
|
||||||
|
append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>char</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value the char to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(char value) {
|
||||||
|
total = total * constant + value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>char</code> array.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param array the array to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(char[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
total = total * constant;
|
||||||
|
} else {
|
||||||
|
for (char element : array) {
|
||||||
|
append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>double</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value the double to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(double value) {
|
||||||
|
return append(Double.doubleToLongBits(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>double</code> array.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param array the array to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(double[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
total = total * constant;
|
||||||
|
} else {
|
||||||
|
for (double element : array) {
|
||||||
|
append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>float</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value the float to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(float value) {
|
||||||
|
total = total * constant + Float.floatToIntBits(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>float</code> array.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param array the array to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(float[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
total = total * constant;
|
||||||
|
} else {
|
||||||
|
for (float element : array) {
|
||||||
|
append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for an <code>int</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value the int to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(int value) {
|
||||||
|
total = total * constant + value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for an <code>int</code> array.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param array the array to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(int[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
total = total * constant;
|
||||||
|
} else {
|
||||||
|
for (int element : array) {
|
||||||
|
append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>long</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value the long to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
// NOTE: This method uses >> and not >>> as Effective Java and
|
||||||
|
// Long.hashCode do. Ideally we should switch to >>> at
|
||||||
|
// some stage. There are backwards compat issues, so
|
||||||
|
// that will have to wait for the time being. cf LANG-342.
|
||||||
|
public HashCodeBuilder append(long value) {
|
||||||
|
total = total * constant + ((int) (value ^ (value >> 32)));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>long</code> array.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param array the array to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(long[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
total = total * constant;
|
||||||
|
} else {
|
||||||
|
for (long element : array) {
|
||||||
|
append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for an <code>Object</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param object the Object to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(Object object) {
|
||||||
|
if (object == null) {
|
||||||
|
total = total * constant;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (object.getClass().isArray()) {
|
||||||
|
// 'Switch' on type of array, to dispatch to the correct handler
|
||||||
|
// This handles multi dimensional arrays
|
||||||
|
if (object instanceof long[]) {
|
||||||
|
append((long[]) object);
|
||||||
|
} else if (object instanceof int[]) {
|
||||||
|
append((int[]) object);
|
||||||
|
} else if (object instanceof short[]) {
|
||||||
|
append((short[]) object);
|
||||||
|
} else if (object instanceof char[]) {
|
||||||
|
append((char[]) object);
|
||||||
|
} else if (object instanceof byte[]) {
|
||||||
|
append((byte[]) object);
|
||||||
|
} else if (object instanceof double[]) {
|
||||||
|
append((double[]) object);
|
||||||
|
} else if (object instanceof float[]) {
|
||||||
|
append((float[]) object);
|
||||||
|
} else if (object instanceof boolean[]) {
|
||||||
|
append((boolean[]) object);
|
||||||
|
} else {
|
||||||
|
// Not an array of primitives
|
||||||
|
append((Object[]) object);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
total = total * constant + object.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for an <code>Object</code> array.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param array the array to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(Object[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
total = total * constant;
|
||||||
|
} else {
|
||||||
|
for (Object element : array) {
|
||||||
|
append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>short</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value the short to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(short value) {
|
||||||
|
total = total * constant + value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Append a <code>hashCode</code> for a <code>short</code> array.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param array the array to add to the <code>hashCode</code>
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder append(short[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
total = total * constant;
|
||||||
|
} else {
|
||||||
|
for (short element : array) {
|
||||||
|
append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Adds the result of super.hashCode() to this builder.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param superHashCode the result of calling <code>super.hashCode()</code>
|
||||||
|
* @return this HashCodeBuilder, used to chain calls.
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
public HashCodeBuilder appendSuper(int superHashCode) {
|
||||||
|
total = total * constant + superHashCode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Return the computed <code>hashCode</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return <code>hashCode</code> based on the fields appended
|
||||||
|
*/
|
||||||
|
public int toHashCode() {
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p/>
|
||||||
|
* The computed <code>hashCode</code> from toHashCode() is returned due to the likelyhood
|
||||||
|
* of bugs in mis-calling toHashCode() and the unlikelyness of it mattering what the hashCode for
|
||||||
|
* HashCodeBuilder itself is.
|
||||||
|
*
|
||||||
|
* @return <code>hashCode</code> based on the fields appended
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return toHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
jscl/src/main/java/org/solovyev/common/JBuilder.java
Normal file
31
jscl/src/main/java/org/solovyev/common/JBuilder.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public interface JBuilder<T> {
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
T create();
|
||||||
|
}
|
33
jscl/src/main/java/org/solovyev/common/JPredicate.java
Normal file
33
jscl/src/main/java/org/solovyev/common/JPredicate.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate, copy of Guava's {@link com.google.common.base.Predicate}
|
||||||
|
*/
|
||||||
|
public interface JPredicate<T> {
|
||||||
|
|
||||||
|
boolean apply(@Nullable T t);
|
||||||
|
}
|
213
jscl/src/main/java/org/solovyev/common/Objects.java
Normal file
213
jscl/src/main/java/org/solovyev/common/Objects.java
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 5/18/11
|
||||||
|
* Time: 11:18 AM
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.solovyev.common.equals.Equalizer;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Objects {
|
||||||
|
|
||||||
|
protected Objects() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* EQUALS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static EqualsResult getEqualsResult(@Nullable Object o1, @Nullable Object o2) {
|
||||||
|
return new EqualsResult<Object>(o1, o2, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> boolean areEqual(@Nullable T o1, @Nullable T o2) {
|
||||||
|
return new EqualsResult<T>(o1, o2, null).areEqual();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> boolean areEqual(@Nullable T o1, @Nullable T o2, @Nullable Equalizer<? super T> equalizer) {
|
||||||
|
return new EqualsResult<T>(o1, o2, equalizer).areEqual();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* COMPARE
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static int compare(Object value1, Object value2) {
|
||||||
|
Integer result = compareOnNullness(value1, value2);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
if (value1 instanceof Comparable && value2 instanceof Comparable) {
|
||||||
|
//noinspection unchecked
|
||||||
|
result = ((Comparable) value1).compareTo(value2);
|
||||||
|
} else {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends Comparable<T>> int compare(@Nullable T l,
|
||||||
|
@Nullable T r) {
|
||||||
|
Integer result = compareOnNullness(l, r);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
assert l != null;
|
||||||
|
result = l.compareTo(r);
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(List list1, List list2) {
|
||||||
|
Integer result = compareOnNullness(list1, list2);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
result = list1.size() - list2.size();
|
||||||
|
if (result == 0) {
|
||||||
|
for (int i = 0; i < list1.size(); i++) {
|
||||||
|
result = compare(list1.get(i), list2.get(i));
|
||||||
|
if (result != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(Number value1, Number value2) {
|
||||||
|
Integer result = compareOnNullness(value1, value2);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
if (value1 instanceof Comparable && value2 instanceof Comparable) {
|
||||||
|
//noinspection unchecked
|
||||||
|
result = ((Comparable) value1).compareTo(value2);
|
||||||
|
} else {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(Date value1, Date value2) {
|
||||||
|
Integer result = compareOnNullness(value1, value2);
|
||||||
|
if (result == null) {
|
||||||
|
if (value1.before(value2)) {
|
||||||
|
result = -1;
|
||||||
|
} else if (value1.after(value2)) {
|
||||||
|
result = 1;
|
||||||
|
} else {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(int value1, int value2) {
|
||||||
|
if (value1 > value2) {
|
||||||
|
return 1;
|
||||||
|
} else if (value1 == value2) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(String value1, String value2, boolean ignoreCase) {
|
||||||
|
Integer result = compareOnNullness(value1, value2);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
if (ignoreCase) {
|
||||||
|
result = value1.toLowerCase().compareTo(value2.toLowerCase());
|
||||||
|
} else {
|
||||||
|
result = value1.compareTo(value2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(Boolean value1, Boolean value2) {
|
||||||
|
Integer result = compareOnNullness(value1, value2);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
result = value1.compareTo(value2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method compares objects according their nullness property
|
||||||
|
*
|
||||||
|
* @param o1 first compared object
|
||||||
|
* @param o2 second compared object
|
||||||
|
* @return if both objects are nulls then 0 (they are equal), if first is null then -1, if second is null then 1, otherwise - null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static Integer compareOnNullness(Object o1, Object o2) {
|
||||||
|
Integer result;
|
||||||
|
|
||||||
|
if (o1 == null && o2 == null) {
|
||||||
|
result = EqualsResult.BOTH_NULLS_CONST;
|
||||||
|
} else if (o1 == null) {
|
||||||
|
result = -1;
|
||||||
|
} else if (o2 == null) {
|
||||||
|
result = 1;
|
||||||
|
} else {
|
||||||
|
//both not nulls
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method compares objects according their nullness property
|
||||||
|
*
|
||||||
|
* @param o1 first compared object
|
||||||
|
* @param o2 second compared object
|
||||||
|
* @return if both objects are nulls then 0 (they are equal), if first is null then -1, if second is null then 1, otherwise - null
|
||||||
|
*/
|
||||||
|
public static EqualsResult compareOnNullnessWithResult(Object o1, Object o2) {
|
||||||
|
return getEqualsResult(o1, o2);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
|
||||||
|
public abstract class SynchronizedObject<D> {
|
||||||
|
|
||||||
|
@GuardedBy("mutex")
|
||||||
|
@Nonnull
|
||||||
|
protected final D delegate;
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
protected final Object mutex;
|
||||||
|
|
||||||
|
protected SynchronizedObject(@Nonnull D delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.mutex = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SynchronizedObject(@Nonnull D delegate, @Nonnull Object mutex) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.mutex = mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for manually synchronization it is allows to use mutex
|
||||||
|
@Nonnull
|
||||||
|
public Object getMutex() {
|
||||||
|
return mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof SynchronizedObject)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final SynchronizedObject that = (SynchronizedObject) o;
|
||||||
|
|
||||||
|
synchronized (mutex) {
|
||||||
|
if (!delegate.equals(that.delegate)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
synchronized (mutex) {
|
||||||
|
return delegate.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
synchronized (mutex) {
|
||||||
|
return delegate.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,262 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.collections;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class SortedList<T> implements List<T> {
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final Comparator<? super T> comparator;
|
||||||
|
@Nonnull
|
||||||
|
private List<T> list = new ArrayList<T>();
|
||||||
|
|
||||||
|
private SortedList(@Nonnull Comparator<? super T> comparator) {
|
||||||
|
this.comparator = comparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SortedList(@Nonnull List<T> list, @Nonnull Comparator<? super T> comparator) {
|
||||||
|
this.list = list;
|
||||||
|
this.comparator = comparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static <T> SortedList<T> newInstance(@Nonnull Comparator<? super T> comparator) {
|
||||||
|
return new SortedList<T>(comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static <T> SortedList<T> newInstance(@Nonnull List<T> list, @Nonnull Comparator<? super T> comparator) {
|
||||||
|
return new SortedList<T>(list, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return list.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return list.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object o) {
|
||||||
|
return list.contains(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Iterator<T> iterator() {
|
||||||
|
final Iterator<T> it = list.iterator();
|
||||||
|
return new Iterator<T>() {
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T next() {
|
||||||
|
return it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
it.remove();
|
||||||
|
// todo serso: think
|
||||||
|
sort();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Object[] toArray() {
|
||||||
|
return list.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public <T> T[] toArray(@Nonnull T[] a) {
|
||||||
|
return list.toArray(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(T t) {
|
||||||
|
boolean result = list.add(t);
|
||||||
|
sort();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object o) {
|
||||||
|
boolean result = list.remove(o);
|
||||||
|
sort();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsAll(@Nonnull Collection<?> c) {
|
||||||
|
return this.list.containsAll(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addAll(@Nonnull Collection<? extends T> c) {
|
||||||
|
boolean result = this.list.addAll(c);
|
||||||
|
sort();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addAll(int index, @Nonnull Collection<? extends T> c) {
|
||||||
|
boolean result = this.list.addAll(index, c);
|
||||||
|
sort();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeAll(@Nonnull Collection<?> c) {
|
||||||
|
boolean result = this.list.removeAll(c);
|
||||||
|
sort();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean retainAll(@Nonnull Collection<?> c) {
|
||||||
|
boolean result = this.list.retainAll(c);
|
||||||
|
sort();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
this.list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T get(int index) {
|
||||||
|
return this.list.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T set(int index, T element) {
|
||||||
|
T result = this.list.set(index, element);
|
||||||
|
sort();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(int index, T element) {
|
||||||
|
this.list.add(index, element);
|
||||||
|
sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T remove(int index) {
|
||||||
|
T result = this.list.remove(index);
|
||||||
|
sort();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object o) {
|
||||||
|
return this.list.indexOf(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object o) {
|
||||||
|
return this.list.lastIndexOf(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public ListIterator<T> listIterator() {
|
||||||
|
return listIterator(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public ListIterator<T> listIterator(int index) {
|
||||||
|
final ListIterator<T> it = this.list.listIterator(index);
|
||||||
|
return new ListIterator<T>() {
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T next() {
|
||||||
|
return it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPrevious() {
|
||||||
|
return it.hasPrevious();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T previous() {
|
||||||
|
return it.previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int nextIndex() {
|
||||||
|
return it.nextIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int previousIndex() {
|
||||||
|
return it.previousIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
it.remove();
|
||||||
|
sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(T t) {
|
||||||
|
it.set(t);
|
||||||
|
sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(T t) {
|
||||||
|
it.add(t);
|
||||||
|
sort();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sort() {
|
||||||
|
Collections.sort(list, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public List<T> subList(int fromIndex, int toIndex) {
|
||||||
|
return this.list.subList(fromIndex, toIndex);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.equals;
|
||||||
|
|
||||||
|
import org.solovyev.common.Objects;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class CollectionEqualizer<T> implements Equalizer<Collection<T>> {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected final Equalizer<T> nestedEqualizer;
|
||||||
|
|
||||||
|
public CollectionEqualizer(@Nullable Equalizer<T> nestedEqualizer) {
|
||||||
|
this.nestedEqualizer = nestedEqualizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areEqual(@Nonnull Collection<T> first, @Nonnull Collection<T> second) {
|
||||||
|
boolean result = false;
|
||||||
|
|
||||||
|
if (first.size() == second.size()) {
|
||||||
|
result = true;
|
||||||
|
|
||||||
|
for (T el1 : first) {
|
||||||
|
boolean found = false;
|
||||||
|
|
||||||
|
for (T el2 : second) {
|
||||||
|
if (Objects.areEqual(el1, el2, nestedEqualizer)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
jscl/src/main/java/org/solovyev/common/equals/Equalizer.java
Normal file
30
jscl/src/main/java/org/solovyev/common/equals/Equalizer.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.equals;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public interface Equalizer<T> {
|
||||||
|
|
||||||
|
boolean areEqual(@Nonnull T first, @Nonnull T second);
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.equals;
|
||||||
|
|
||||||
|
import org.solovyev.common.Objects;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ListEqualizer<T> implements Equalizer<List<T>> {
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static final Equalizer<List<Object>> instanceWithOrder = new ListEqualizer<>(true, null);
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static final Equalizer<List<Object>> instanceWithoutOrder = new ListEqualizer<>(false, null);
|
||||||
|
|
||||||
|
private final boolean checkOrder;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected final Equalizer<T> nestedEqualizer;
|
||||||
|
|
||||||
|
private ListEqualizer(boolean checkOrder, @Nullable Equalizer<T> nestedEqualizer) {
|
||||||
|
this.checkOrder = checkOrder;
|
||||||
|
this.nestedEqualizer = nestedEqualizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static <T> ListEqualizer<T> newWithNestedEqualizer(boolean checkOrder, @Nullable Equalizer<T> nestedEqualizer) {
|
||||||
|
return new ListEqualizer<>(checkOrder, nestedEqualizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static <T> ListEqualizer<T> newWithNaturalEquals(boolean checkOrder) {
|
||||||
|
if (checkOrder) {
|
||||||
|
return (ListEqualizer<T>) instanceWithOrder;
|
||||||
|
} else {
|
||||||
|
return (ListEqualizer<T>) instanceWithoutOrder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areEqual(@Nonnull List<T> first, @Nonnull List<T> second) {
|
||||||
|
boolean result = false;
|
||||||
|
|
||||||
|
if (first.size() == second.size()) {
|
||||||
|
if (checkOrder) {
|
||||||
|
result = true;
|
||||||
|
for (int i = 0; i < first.size(); i++) {
|
||||||
|
final T el1 = first.get(i);
|
||||||
|
final T el2 = second.get(i);
|
||||||
|
|
||||||
|
if (!Objects.areEqual(el1, el2, nestedEqualizer)) {
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = Objects.areEqual(first, second, new CollectionEqualizer<>(nestedEqualizer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,6 @@
|
|||||||
package org.solovyev.common.math;
|
package org.solovyev.common.math;
|
||||||
|
|
||||||
import org.solovyev.common.JBuilder;
|
import org.solovyev.common.JBuilder;
|
||||||
import org.solovyev.common.collections.Collections;
|
|
||||||
import org.solovyev.common.collections.SortedList;
|
import org.solovyev.common.collections.SortedList;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -64,6 +63,22 @@ public abstract class AbstractMathRegistry<T extends MathEntity> implements Math
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static <E extends MathEntity> E removeByName(@Nonnull List<E> entities, @Nonnull String name) {
|
||||||
|
for (int i = 0; i < entities.size(); i++) {
|
||||||
|
final E entity = entities.get(i);
|
||||||
|
if (entity.getName().equals(name)) {
|
||||||
|
entities.remove(i);
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean areEqual(@Nullable Object l, @Nullable Object r) {
|
||||||
|
return l != null ? l.equals(r) : r == null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public List<T> getEntities() {
|
public List<T> getEntities() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@ -136,8 +151,8 @@ public abstract class AbstractMathRegistry<T extends MathEntity> implements Math
|
|||||||
public void remove(@Nonnull T entity) {
|
public void remove(@Nonnull T entity) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (!entity.isSystem()) {
|
if (!entity.isSystem()) {
|
||||||
final T removed = Collections.removeFirst(this.entities, new MathEntity.Finder<T>(entity.getName()));
|
final T removed = removeByName(entities, entity.getName());
|
||||||
if(removed != null) {
|
if (removed != null) {
|
||||||
this.entityNames.clear();
|
this.entityNames.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,10 +189,6 @@ public abstract class AbstractMathRegistry<T extends MathEntity> implements Math
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean areEqual(@Nullable Object l, @Nullable Object r) {
|
|
||||||
return l != null ? l.equals(r) : r == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getById(@Nonnull final Integer id) {
|
public T getById(@Nonnull final Integer id) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
for (T entity : entities) {
|
for (T entity : entities) {
|
||||||
|
@ -22,10 +22,8 @@
|
|||||||
|
|
||||||
package org.solovyev.common.math;
|
package org.solovyev.common.math;
|
||||||
|
|
||||||
import org.solovyev.common.JPredicate;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public interface MathEntity {
|
public interface MathEntity {
|
||||||
|
|
||||||
@ -42,18 +40,4 @@ public interface MathEntity {
|
|||||||
boolean isIdDefined();
|
boolean isIdDefined();
|
||||||
|
|
||||||
void copy(@Nonnull MathEntity that);
|
void copy(@Nonnull MathEntity that);
|
||||||
|
|
||||||
class Finder<T extends MathEntity> implements JPredicate<T> {
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
public Finder(@Nonnull String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean apply(@Nullable T entity) {
|
|
||||||
return entity != null && name.equals(entity.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
134
jscl/src/main/java/org/solovyev/common/msg/AbstractMessage.java
Normal file
134
jscl/src/main/java/org/solovyev/common/msg/AbstractMessage.java
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.msg;
|
||||||
|
|
||||||
|
import org.solovyev.common.HashCodeBuilder;
|
||||||
|
import org.solovyev.common.Objects;
|
||||||
|
import org.solovyev.common.equals.ListEqualizer;
|
||||||
|
import org.solovyev.common.text.Strings;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public abstract class AbstractMessage implements Message {
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final String messageCode;
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final List<Object> parameters;
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final MessageLevel messageLevel;
|
||||||
|
|
||||||
|
protected AbstractMessage(@Nonnull String messageCode, @Nonnull MessageLevel messageType, @Nullable Object... parameters) {
|
||||||
|
this(messageCode, messageType, parameters == null ? Collections.emptyList() : Arrays.asList(parameters));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractMessage(@Nonnull String messageCode, @Nonnull MessageLevel messageType, @Nonnull List<?> parameters) {
|
||||||
|
this.messageCode = messageCode;
|
||||||
|
this.parameters = new ArrayList<>(parameters);
|
||||||
|
this.messageLevel = messageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public String getMessageCode() {
|
||||||
|
return this.messageCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public List<Object> getParameters() {
|
||||||
|
return java.util.Collections.unmodifiableList(this.parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public MessageLevel getMessageLevel() {
|
||||||
|
return this.messageLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final AbstractMessage that = (AbstractMessage) o;
|
||||||
|
|
||||||
|
if (!Objects.areEqual(parameters, that.parameters, ListEqualizer.newWithNaturalEquals(true))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!messageCode.equals(that.messageCode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!messageLevel.equals(that.messageLevel)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final HashCodeBuilder hcb = HashCodeBuilder.newInstance();
|
||||||
|
|
||||||
|
hcb.append(messageCode);
|
||||||
|
hcb.append(messageLevel);
|
||||||
|
hcb.append(parameters);
|
||||||
|
|
||||||
|
return hcb.toHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method converts message to string setting passed message parameters and translating some of them.
|
||||||
|
*
|
||||||
|
* @param locale language to which parameters should be translated (if possible)
|
||||||
|
* @return message as string with properly translated and set parameters
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public String getLocalizedMessage(@Nonnull Locale locale) {
|
||||||
|
String result = null;
|
||||||
|
|
||||||
|
final String messagePattern = getMessagePattern(locale);
|
||||||
|
if (!Strings.isEmpty(messagePattern)) {
|
||||||
|
result = Messages.prepareMessage(locale, messagePattern, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Strings.getNotEmpty(result, messageLevel.getName() + ": message code = " + messageCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getLocalizedMessage() {
|
||||||
|
return this.getLocalizedMessage(Locale.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected abstract String getMessagePattern(@Nonnull Locale locale);
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.msg;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ListMessageRegistry implements MessageRegistry {
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final List<Message> messages = new ArrayList<Message>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addMessage(@Nonnull Message message) {
|
||||||
|
if (!messages.contains(message)) {
|
||||||
|
messages.add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Message getMessage() {
|
||||||
|
return this.messages.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMessage() {
|
||||||
|
return !this.messages.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
67
jscl/src/main/java/org/solovyev/common/msg/Message.java
Normal file
67
jscl/src/main/java/org/solovyev/common/msg/Message.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.msg;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface represents translatable user message.
|
||||||
|
* Implementation of this class will likely contains
|
||||||
|
* some logic for translation message according to
|
||||||
|
* it's message code and list of parameters.
|
||||||
|
*/
|
||||||
|
public interface Message {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return message code
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public String getMessageCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list of message parameters
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public List<Object> getParameters();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return message level
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public MessageLevel getMessageLevel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param locale locate to which current message should be translated
|
||||||
|
* @return message string translated to specified locale
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public String getLocalizedMessage(@Nonnull Locale locale);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return message string translated to deault locale (Locale.getDefault())
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public String getLocalizedMessage();
|
||||||
|
}
|
32
jscl/src/main/java/org/solovyev/common/msg/MessageLevel.java
Normal file
32
jscl/src/main/java/org/solovyev/common/msg/MessageLevel.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package org.solovyev.common.msg;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See {@link MessageType} as default implementation of this class
|
||||||
|
*/
|
||||||
|
public interface MessageLevel {
|
||||||
|
|
||||||
|
public static final int INFO_LEVEL = 100;
|
||||||
|
public static final int WARNING_LEVEL = 500;
|
||||||
|
public static final int ERROR_LEVEL = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position of current message level in some message level hierarchy.
|
||||||
|
* By default, one can use {@link MessageType} implementation which uses next levels:
|
||||||
|
* 100 500 1000 level
|
||||||
|
* --------|-----------|--------------|------------->
|
||||||
|
* Info Warning Error
|
||||||
|
*
|
||||||
|
* @return int message level
|
||||||
|
*/
|
||||||
|
int getMessageLevel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some string id for level (might be used in logs)
|
||||||
|
*
|
||||||
|
* @return string level identifier
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
String getName();
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.msg;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container for messages
|
||||||
|
*/
|
||||||
|
public interface MessageRegistry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds message to the registry.
|
||||||
|
* Note: according to the implementation this method doesn't guarantee that new message will be added
|
||||||
|
* in underlying container (e.g. if such message already exists)
|
||||||
|
*
|
||||||
|
* @param message message to be added
|
||||||
|
*/
|
||||||
|
void addMessage(@Nonnull Message message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if there is any message available in the registry
|
||||||
|
*/
|
||||||
|
boolean hasMessage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method returns message from registry and removes it from underlying container
|
||||||
|
* Note: this method must be called after {@link MessageRegistry#hasMessage()}
|
||||||
|
*
|
||||||
|
* @return message from the registry
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
Message getMessage();
|
||||||
|
}
|
65
jscl/src/main/java/org/solovyev/common/msg/MessageType.java
Normal file
65
jscl/src/main/java/org/solovyev/common/msg/MessageType.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.msg;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public enum MessageType implements MessageLevel {
|
||||||
|
|
||||||
|
error(ERROR_LEVEL, "ERROR"),
|
||||||
|
|
||||||
|
warning(WARNING_LEVEL, "WARNING"),
|
||||||
|
|
||||||
|
info(INFO_LEVEL, "INFO");
|
||||||
|
|
||||||
|
private final int messageLevel;
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final String stringValue;
|
||||||
|
|
||||||
|
MessageType(int messageLevel, @Nonnull String stringValue) {
|
||||||
|
this.messageLevel = messageLevel;
|
||||||
|
this.stringValue = stringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static MessageType getLowestMessageType() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public String getStringValue() {
|
||||||
|
return stringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMessageLevel() {
|
||||||
|
return messageLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return stringValue;
|
||||||
|
}
|
||||||
|
}
|
86
jscl/src/main/java/org/solovyev/common/msg/Messages.java
Normal file
86
jscl/src/main/java/org/solovyev/common/msg/Messages.java
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.msg;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public final class Messages {
|
||||||
|
|
||||||
|
private Messages() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static MessageRegistry synchronizedMessageRegistry(@Nonnull MessageRegistry messageRegistry) {
|
||||||
|
return SynchronizedMessageRegistry.wrap(messageRegistry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param locale locale for which default formatting will be applied
|
||||||
|
* @param messagePattern message pattern which will be used for {@link MessageFormat}
|
||||||
|
* @param parameters message parameters which will be used for {@link MessageFormat}
|
||||||
|
* @return formatted message string according to default locale formatting, nested messages are processed properly
|
||||||
|
* (for each message from parameter method {@link Message#getLocalizedMessage(Locale)} is called)
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public static String prepareMessage(@Nonnull Locale locale, @Nonnull String messagePattern, @Nonnull List<?> parameters) {
|
||||||
|
String result;
|
||||||
|
|
||||||
|
if (parameters.isEmpty()) {
|
||||||
|
result = messagePattern;
|
||||||
|
} else {
|
||||||
|
final MessageFormat format = new MessageFormat(messagePattern);
|
||||||
|
|
||||||
|
format.setLocale(locale);
|
||||||
|
format.applyPattern(messagePattern);
|
||||||
|
|
||||||
|
result = format.format(prepareParameters(parameters, locale));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static Object[] prepareParameters(@Nonnull List<?> parameters, @Nonnull Locale locale) {
|
||||||
|
final Object[] result = new Object[parameters.size()];
|
||||||
|
|
||||||
|
for (int i = 0; i < parameters.size(); i++) {
|
||||||
|
result[i] = substituteParameter(parameters.get(i), locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static Object substituteParameter(@Nullable Object object, @Nonnull Locale locale) {
|
||||||
|
if (object instanceof Message) {
|
||||||
|
return ((Message) object).getLocalizedMessage(locale);
|
||||||
|
} else {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.msg;
|
||||||
|
|
||||||
|
import org.solovyev.common.SynchronizedObject;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
class SynchronizedMessageRegistry extends SynchronizedObject<MessageRegistry> implements MessageRegistry {
|
||||||
|
|
||||||
|
private SynchronizedMessageRegistry(@Nonnull MessageRegistry delegate) {
|
||||||
|
super(delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SynchronizedMessageRegistry(@Nonnull MessageRegistry delegate, @Nonnull Object mutex) {
|
||||||
|
super(delegate, mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static MessageRegistry wrap(@Nonnull MessageRegistry delegate) {
|
||||||
|
return new SynchronizedMessageRegistry(delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static MessageRegistry wrap(@Nonnull MessageRegistry delegate, @Nonnull Object mutex) {
|
||||||
|
return new SynchronizedMessageRegistry(delegate, mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addMessage(@Nonnull Message message) {
|
||||||
|
synchronized (this.mutex) {
|
||||||
|
delegate.addMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMessage() {
|
||||||
|
synchronized (this.mutex) {
|
||||||
|
return delegate.hasMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Message getMessage() {
|
||||||
|
synchronized (this.mutex) {
|
||||||
|
return delegate.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
jscl/src/main/java/org/solovyev/common/msg/Utf8Control.java
Normal file
60
jscl/src/main/java/org/solovyev/common/msg/Utf8Control.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package org.solovyev.common.msg;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.PropertyResourceBundle;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
class Utf8Control extends ResourceBundle.Control {
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static final ResourceBundle.Control instance = new Utf8Control();
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static ResourceBundle.Control getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Utf8Control() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException {
|
||||||
|
final ResourceBundle result;
|
||||||
|
|
||||||
|
// The below is a copy of the default implementation.
|
||||||
|
final String bundleName = toBundleName(baseName, locale);
|
||||||
|
final String resourceName = toResourceName(bundleName, "properties");
|
||||||
|
|
||||||
|
InputStream stream = null;
|
||||||
|
if (reload) {
|
||||||
|
final URL url = loader.getResource(resourceName);
|
||||||
|
if (url != null) {
|
||||||
|
final URLConnection connection = url.openConnection();
|
||||||
|
if (connection != null) {
|
||||||
|
connection.setUseCaches(false);
|
||||||
|
stream = connection.getInputStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stream = loader.getResourceAsStream(resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream != null) {
|
||||||
|
try {
|
||||||
|
// Only this line is changed to make it to read properties files as UTF-8.
|
||||||
|
result = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
|
||||||
|
} finally {
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.search;
|
||||||
|
|
||||||
|
import org.solovyev.common.JPredicate;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class StartsWithFinder implements JPredicate<String> {
|
||||||
|
|
||||||
|
private int i;
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final String targetString;
|
||||||
|
|
||||||
|
private StartsWithFinder(@Nonnull String targetString, int i) {
|
||||||
|
this.targetString = targetString;
|
||||||
|
this.i = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static StartsWithFinder newFrom(@Nonnull String targetString, int i) {
|
||||||
|
return new StartsWithFinder(targetString, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static StartsWithFinder newInstance(@Nonnull String targetString) {
|
||||||
|
return newFrom(targetString, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(@Nullable String s) {
|
||||||
|
return s != null && targetString.startsWith(s, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setI(int i) {
|
||||||
|
this.i = i;
|
||||||
|
}
|
||||||
|
}
|
83
jscl/src/main/java/org/solovyev/common/text/Strings.java
Normal file
83
jscl/src/main/java/org/solovyev/common/text/Strings.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 serso aka se.solovyev
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Contact details
|
||||||
|
*
|
||||||
|
* Email: se.solovyev@gmail.com
|
||||||
|
* Site: http://se.solovyev.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.common.text;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class Strings {
|
||||||
|
|
||||||
|
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||||
|
public static final Character[] EMPTY_CHARACTER_OBJECT_ARRAY = new Character[0];
|
||||||
|
// random variable: must be synchronized in usage
|
||||||
|
private static final Random RANDOM = new Random(new Date().getTime());
|
||||||
|
|
||||||
|
// not intended for instantiation
|
||||||
|
protected Strings() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEmpty(@Nullable CharSequence s) {
|
||||||
|
return s == null || s.length() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static String getNotEmpty(@Nullable CharSequence s, @Nonnull String defaultValue) {
|
||||||
|
return isEmpty(s) ? defaultValue : s.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static Character[] toObjects(char[] array) {
|
||||||
|
if (array == null || array.length == 0) {
|
||||||
|
return EMPTY_CHARACTER_OBJECT_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Character[] result = new Character[array.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
result[i] = array[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static String generateRandomString(int length) {
|
||||||
|
|
||||||
|
final StringBuilder result = new StringBuilder(length);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
final char ch;
|
||||||
|
|
||||||
|
synchronized (RANDOM) {
|
||||||
|
// 'A' = 65
|
||||||
|
ch = (char) (RANDOM.nextInt(52) + 65);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.append(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user