Remove dependencies

This commit is contained in:
serso 2016-03-02 08:25:41 +01:00
parent 62aad904d4
commit 4fa55d6bbc
33 changed files with 2321 additions and 111 deletions

View File

@ -60,7 +60,6 @@ android {
dependencies {
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:appcompat-v7:23.2.0'
compile 'com.android.support:cardview-v7:23.2.0'

View File

@ -48,9 +48,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import com.squareup.otto.Bus;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.floating.FloatingCalculatorService;
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.common.JPredicate;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nonnull;
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.
@ -262,18 +258,6 @@ public final class App {
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
public static String find(@Nonnull List<String> tokens, @Nonnull String text, int position) {
for (int i = 0; i < tokens.size(); i++) {

View File

@ -23,9 +23,9 @@
package org.solovyev.android.calculator;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import jscl.NumeralBase;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -60,7 +60,7 @@ public abstract class BaseNumberBuilder {
}
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) {

View File

@ -26,39 +26,8 @@ import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import com.squareup.otto.Bus;
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.MathEngine;
import jscl.NumeralBase;
@ -67,6 +36,28 @@ import jscl.math.Generic;
import jscl.math.function.Constants;
import jscl.math.function.IConstant;
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
public class Calculator implements SharedPreferences.OnSharedPreferenceChangeListener {
@ -166,7 +157,7 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis
@Nonnull String e,
@Nonnull MessageRegistry mr) {
e = e.trim();
if (Strings.isEmpty(e)) {
if (TextUtils.isEmpty(e)) {
bus.post(new CalculationFinishedEvent(o, e, sequence));
return;
}

View File

@ -23,13 +23,15 @@
package org.solovyev.android.calculator;
import android.content.SharedPreferences;
import android.text.TextUtils;
import com.squareup.otto.Bus;
import jscl.AngleUnit;
import jscl.JsclMathEngine;
import jscl.MathEngine;
import jscl.NumeralBase;
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.calculator.functions.FunctionsRegistry;
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.common.text.EnumMapper;
import org.solovyev.common.text.NumberMapper;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -104,7 +105,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene
}
public static boolean isValidName(@Nullable String name) {
if (!Strings.isEmpty(name)) {
if (!TextUtils.isEmpty(name)) {
try {
Identifier.parser.parse(Parser.Parameters.get(name), null);
return true;
@ -205,7 +206,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene
mathEngine.setRoundResult(Preferences.Output.round.getPreference(preferences));
final String groupingSeparator = Preferences.groupingSeparator.getPreference(preferences);
if (Strings.isEmpty(groupingSeparator)) {
if (TextUtils.isEmpty(groupingSeparator)) {
mathEngine.setUseGroupingSeparator(false);
} else {
mathEngine.setUseGroupingSeparator(true);

View File

@ -34,16 +34,14 @@ import org.solovyev.android.Check;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.entities.BaseEntitiesFragment;
import org.solovyev.android.calculator.entities.Category;
import org.solovyev.android.calculator.RemovalConfirmationDialog;
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 javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class VariablesFragment extends BaseEntitiesFragment<IConstant> {
@ -77,16 +75,17 @@ public class VariablesFragment extends BaseEntitiesFragment<IConstant> {
@Nonnull
@Override
protected List<IConstant> getEntities() {
final List<IConstant> result = new ArrayList<>(registry.getEntities());
Collections.removeAll(result, new JPredicate<IConstant>() {
@Override
public boolean apply(@Nullable IConstant var) {
return var != null && Collections.contains(var.getName(), MathType.INFINITY_JSCL, MathType.NAN);
final List<IConstant> entities = new ArrayList<>(registry.getEntities());
for (Iterator<IConstant> it = entities.iterator(); it.hasNext(); ) {
final IConstant constant = it.next();
switch (constant.getName()) {
case MathType.INFINITY_JSCL:
case MathType.NAN:
it.remove();
break;
}
});
return result;
}
return entities;
}
@Override

View File

@ -24,7 +24,6 @@ apply plugin: 'java'
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'org.solovyev:common-msg:1.0.7'
compile 'com.google.code.findbugs:annotations:2.0.1'
compile 'xerces:xercesImpl:2.8.0'

View File

@ -9,16 +9,16 @@ import jscl.math.operator.Percent;
import jscl.math.operator.Rand;
import jscl.math.operator.matrix.OperatorsRegistry;
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.msg.MessageRegistry;
import org.solovyev.common.msg.Messages;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.List;
import java.util.Locale;
public class JsclMathEngine implements MathEngine {
@ -165,20 +165,7 @@ public class JsclMathEngine implements MathEngine {
// decimal numeral base => do specific formatting
// detect if current number is precisely equals to constant in constants' registry (NOTE: ONLY FOR SYSTEM CONSTANTS)
final Double localValue = 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;
}
});
IConstant constant = findConstant(getConstantsRegistry().getSystemEntities(), value);
if (constant == null) {
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
public String convert(@Nonnull Double value, @Nonnull NumeralBase to) {
String ungroupedValue;

View File

@ -2,7 +2,6 @@ package jscl.math.function;
import org.solovyev.common.JBuilder;
import org.solovyev.common.math.MathEntity;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -50,7 +49,7 @@ public class ExtendedConstant implements Comparable<ExtendedConstant>, IConstant
final Double doubleValue = constant.getDoubleValue();
if (doubleValue == null) {
final String stringValue = constant.getValue();
if (!Strings.isEmpty(stringValue)) {
if (stringValue != null && stringValue.length() > 0) {
return constant.getName() + " = " + stringValue;
} else {
return constant.getName();

View 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);
}

View 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)));
}
}

View 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();
}
}

View 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();
}

View 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);
}

View 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);
}
}

View 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;
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();
}
}
}

View File

@ -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);
}
}

View 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.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;
}
}

View 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);
}

View File

@ -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;
}
}

View File

@ -23,7 +23,6 @@
package org.solovyev.common.math;
import org.solovyev.common.JBuilder;
import org.solovyev.common.collections.Collections;
import org.solovyev.common.collections.SortedList;
import javax.annotation.Nonnull;
@ -64,6 +63,22 @@ public abstract class AbstractMathRegistry<T extends MathEntity> implements Math
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
public List<T> getEntities() {
synchronized (this) {
@ -136,7 +151,7 @@ public abstract class AbstractMathRegistry<T extends MathEntity> implements Math
public void remove(@Nonnull T entity) {
synchronized (this) {
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) {
this.entityNames.clear();
}
@ -174,10 +189,6 @@ public abstract class AbstractMathRegistry<T extends MathEntity> implements Math
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) {
synchronized (this) {
for (T entity : entities) {

View File

@ -22,10 +22,8 @@
package org.solovyev.common.math;
import org.solovyev.common.JPredicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface MathEntity {
@ -42,18 +40,4 @@ public interface MathEntity {
boolean isIdDefined();
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());
}
}
}

View 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);
}

View File

@ -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();
}
}

View 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();
}

View 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();
}

View File

@ -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();
}

View 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;
}
}

View 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;
}
}
}

View File

@ -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();
}
}
}

View 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;
}
}

View File

@ -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;
}
}

View 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();
}
}