OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Compare Revisions

Regard whitespace Rev 143 → Rev 144

/trunk/OpenConcerto/src/org/openconcerto/record/Constraints.java
13,8 → 13,23
package org.openconcerto.record;
 
import org.openconcerto.record.spec.Type;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.NumberUtils;
import org.openconcerto.utils.checks.EmptyObjFromVO;
 
import java.math.BigDecimal;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public final class Constraints {
 
static private final Constraint NONE = new Constraint() {
58,4 → 73,182
public static final Constraint getDefaultEmpty() {
return EMPTY;
}
 
private static final Pattern quotePattern = Pattern.compile("\"", Pattern.LITERAL);
private static final String quoteReplacement = Matcher.quoteReplacement(""");
 
public static final String quote(final String s) {
return '"' + quotePattern.matcher(s).replaceAll(quoteReplacement) + '"';
}
 
public static final Constraint createFromProperties(final Map<String, Object> props, final Type type) {
if (props.isEmpty() || type == Type.BOOLEAN || type == Type.RECORD || type == Type.RECORD_LIST || type == Type.RECORD_REF || type == Type.RECORD_REF_LIST)
return none();
 
if (type == Type.STRING) {
return new PropsConstraintComparable<String>(props, String.class) {
 
private final Pattern regex;
 
{
final String regexp = (String) props.get(ConstraintProperties.REGEXP);
this.regex = regexp == null ? null : Pattern.compile(regexp);
}
 
@Override
protected void addDeclarativeChecks(List<String> res) {
super.addDeclarativeChecks(res);
final Number minSize = (Number) props.get(ConstraintProperties.MIN_SIZE);
if (minSize != null)
res.add("(string-length(.) >= " + minSize.intValue() + ")");
final Number maxSize = (Number) props.get(ConstraintProperties.MAX_SIZE);
if (maxSize != null)
res.add("(string-length(.) <= " + maxSize.intValue() + ")");
 
final String regexp = (String) props.get(ConstraintProperties.REGEXP);
if (regexp != null)
res.add("(matches(., " + quote(regexp) + "))");
}
 
@Override
public boolean checkCasted(String str) {
final Number minSize = (Number) props.get(ConstraintProperties.MIN_SIZE);
if (minSize != null && str.length() < minSize.intValue())
return false;
final Number maxSize = (Number) props.get(ConstraintProperties.MAX_SIZE);
if (maxSize != null && str.length() > maxSize.intValue())
return false;
 
if (this.regex != null && !this.regex.matcher(str).matches())
return false;
 
return super.checkCasted(str);
}
};
} else if (type == Type.DATETIME) {
return new PropsConstraintComparable<Date>(props, Date.class) {
@Override
protected String toString(Date v) {
return new java.sql.Timestamp(v.getTime()).toString();
}
};
} else if (type == Type.TIME) {
return new PropsConstraintComparable<Time>(props, Time.class);
} else if (type == Type.DECIMAL) {
return new PropsConstraintComparable<BigDecimal>(props, BigDecimal.class) {
 
@Override
protected String toString(BigDecimal v) {
return v.toPlainString();
}
 
@Override
public boolean checkCasted(BigDecimal n) {
final Number minSize = (Number) props.get(ConstraintProperties.MIN_SIZE);
if (minSize != null && DecimalUtils.intDigits(n) < minSize.intValue())
return false;
final Number maxSize = (Number) props.get(ConstraintProperties.MAX_SIZE);
if (maxSize != null && DecimalUtils.intDigits(n) > maxSize.intValue())
return false;
 
final Number decDigits = (Number) props.get(ConstraintProperties.DECIMAL_DIGITS);
if (decDigits != null && DecimalUtils.decimalDigits(n) > decDigits.intValue())
return false;
 
return super.checkCasted(n);
}
};
} else if (type == Type.INTEGER || type == Type.FLOAT) {
return new PropsConstraintNumber(props);
} else {
throw new IllegalArgumentException("Unknown type : " + type);
}
}
 
public static abstract class PropsConstraint<T> implements Constraint {
private final Map<String, Object> props;
private final Class<T> clazz;
 
private PropsConstraint(Map<String, Object> props, final Class<T> clazz) {
this.props = Collections.unmodifiableMap(new HashMap<>(props));
this.clazz = clazz;
}
 
public final Map<String, Object> getProps() {
return this.props;
}
 
protected final Class<T> getClazz() {
return this.clazz;
}
 
@Override
public final String getDeclarativeForm() {
final List<String> res = new ArrayList<>();
this.addDeclarativeChecks(res);
return CollectionUtils.join(res, " and ");
}
 
protected void addDeclarativeChecks(final List<String> res) {
this.addValueRangeChecks(res);
}
 
protected final void addValueRangeChecks(final List<String> res) {
final T minValue = this.clazz.cast(this.props.get(ConstraintProperties.MIN_VALUE));
if (minValue != null)
res.add("(. >= " + quote(toString(minValue)) + ")");
final T maxValue = this.clazz.cast(this.props.get(ConstraintProperties.MAX_VALUE));
if (maxValue != null)
res.add("(. <= " + quote(toString(maxValue)) + ")");
}
 
protected String toString(final T v) {
return v.toString();
}
 
@Override
public final boolean check(Object obj) {
return checkCasted(this.clazz.cast(obj));
}
 
protected boolean checkCasted(T obj) {
return checkValueRange(obj);
}
 
protected boolean checkValueRange(final T obj) {
final T minValue = this.clazz.cast(this.props.get(ConstraintProperties.MIN_VALUE));
if (minValue != null && compare(obj, minValue) < 0)
return false;
final T maxValue = this.clazz.cast(this.props.get(ConstraintProperties.MAX_VALUE));
if (maxValue != null && compare(obj, maxValue) > 0)
return false;
return true;
}
 
protected abstract int compare(final T obj1, final T obj2);
}
 
private static class PropsConstraintComparable<T extends Comparable<? super T>> extends PropsConstraint<T> {
 
private PropsConstraintComparable(Map<String, Object> props, final Class<T> clazz) {
super(props, clazz);
}
 
@Override
protected int compare(T obj1, T obj2) {
return obj1.compareTo(obj2);
}
}
 
private static class PropsConstraintNumber extends PropsConstraint<Number> {
 
private PropsConstraintNumber(Map<String, Object> props) {
super(props, Number.class);
}
 
@Override
protected int compare(Number obj1, Number obj2) {
return NumberUtils.compare(obj1, obj2);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/record/RecordManager.java
New file
0,0 → 1,67
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.record;
 
import org.openconcerto.utils.cc.ITransformer;
 
import java.io.IOException;
import java.util.Set;
 
public class RecordManager {
 
private ITransformer<String, RecordIO> ioProvider;
 
public RecordManager() {
}
 
public void setIOProvider(final ITransformer<String, RecordIO> ioProvider) {
this.ioProvider = ioProvider;
}
 
public RecordIO getIO(final String specName) {
return this.ioProvider.transformChecked(specName);
}
 
public final RecordIO getIO(final RecordRef ref) {
return this.getIO(ref.getSpec().getName());
}
 
public Record fetch(final RecordRef ref) {
return this.getIO(ref).fetch(ref.getKey());
}
 
public Record fetch(final RecordRef ref, final Set<String> items) {
return this.getIO(ref).fetch(ref.getKey(), items);
}
 
public Record insert(final Record r) throws IOException {
return this.getIO(r.getSpec()).insert(r);
}
 
public void update(final Record r) throws IOException {
this.getIO(r.getSpec()).update(r);
}
 
public Record copy(final RecordRef ref) throws IOException {
return this.getIO(ref).copy(ref.getKey());
}
 
public Record copy(final RecordRef ref, final boolean forceFull) throws IOException {
return this.getIO(ref).copy(ref.getKey(), forceFull);
}
 
public void delete(final RecordRef ref) throws IOException {
this.getIO(ref).delete(ref.getKey());
}
}
/trunk/OpenConcerto/src/org/openconcerto/record/spec/RecordItemSpec.java
14,6 → 14,7
package org.openconcerto.record.spec;
 
import org.openconcerto.record.Constraint;
import org.openconcerto.record.ConstraintProperties;
import org.openconcerto.record.Constraints;
import org.openconcerto.record.Record;
import org.openconcerto.record.RecordRef;
42,6 → 43,7
private final boolean required;
private final Constraint isValid, isEmpty;
private final Map<String, Object> validProps;
private final Constraint validPropsConstraint;
private final boolean userMustCheck, userMustModify;
 
public RecordItemSpec(final String name, final Type type) {
71,6 → 73,7
this.required = required;
this.isValid = isValid == null ? Constraints.none() : isValid;
this.validProps = validProps == null ? Collections.<String, Object> emptyMap() : Collections.unmodifiableMap(new HashMap<String, Object>(validProps));
this.validPropsConstraint = Constraints.createFromProperties(this.validProps, type);
this.isEmpty = isEmpty == null ? Constraints.getDefaultEmpty() : isEmpty;
this.userMustCheck = userMustCheck;
this.userMustModify = userMustModify;
109,6 → 112,16
return this.validProps;
}
 
/**
* The constraint checking keys from {@link ConstraintProperties} in
* {@link #getValidProperties()}.
*
* @return the constraint.
*/
public final Constraint getValidPropertiesConstraint() {
return this.validPropsConstraint;
}
 
public final Constraint getEmptyConstraint() {
return this.isEmpty;
}
140,6 → 153,8
return EnumSet.of(Problem.VALIDITY);
}
}
if (!this.getValidPropertiesConstraint().check(obj))
return EnumSet.of(Problem.VALIDITY);
}
if (!this.getValidConstraint().check(obj))
return EnumSet.of(Problem.VALIDITY);
/trunk/OpenConcerto/src/org/openconcerto/record/Record.java
52,17 → 52,30
return this.items;
}
 
/**
* Return the passed item as a list.
*
* @param name the wanted item.
* @param clazz the wanted type.
* @return an immutable list, <code>null</code> if no item with the passed name exists in this,
* an empty list if the item's value is <code>null</code> or an empty list.
*/
public final <T> List<T> getAsList(final String name, Class<T> clazz) {
final Object val = this.getItems().get(name);
if (val == null)
if (val == null) {
if (this.getItems().containsKey(name))
return Collections.emptyList();
else
return null;
}
if (val instanceof List) {
for (final Object o : (List<?>) val) {
clazz.cast(o);
}
// safe since we return an immutable view
@SuppressWarnings("unchecked")
final List<T> res = (List<T>) val;
return res;
return Collections.unmodifiableList(res);
} else {
return Collections.singletonList(clazz.cast(val));
}
/trunk/OpenConcerto/src/org/openconcerto/record/ConstraintCombiner.java
New file
0,0 → 1,93
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.record;
 
import java.util.Collection;
 
public abstract class ConstraintCombiner {
 
public final Constraint combine(Constraint w1, Constraint w2) {
if (w1 == null)
return w2;
else
return this.combineNotNull(w1, w2);
}
 
protected abstract Constraint combineNotNull(Constraint w1, Constraint w2);
 
private static ConstraintCombiner AndCombiner = new ConstraintCombiner() {
@Override
protected Constraint combineNotNull(final Constraint c1, final Constraint c2) {
return new Constraint() {
@Override
public String getDeclarativeForm() {
return "(" + c1.getDeclarativeForm() + ") and (" + c2.getDeclarativeForm() + ")";
}
 
@Override
public boolean check(Object obj) {
return c1.check(obj) && c2.check(obj);
}
};
}
};
 
private static ConstraintCombiner OrCombiner = new ConstraintCombiner() {
@Override
protected Constraint combineNotNull(final Constraint c1, final Constraint c2) {
return new Constraint() {
@Override
public String getDeclarativeForm() {
return "(" + c1.getDeclarativeForm() + ") or (" + c2.getDeclarativeForm() + ")";
}
 
@Override
public boolean check(Object obj) {
return c1.check(obj) || c2.check(obj);
}
};
}
};
 
static private Constraint combine(Collection<Constraint> wheres, ConstraintCombiner c) {
Constraint res = null;
for (final Constraint w : wheres) {
res = c.combine(res, w);
}
return res;
}
 
static public Constraint or(Collection<Constraint> constraints) {
return combine(constraints, OrCombiner);
}
 
static public Constraint and(Collection<Constraint> constraints) {
return combine(constraints, AndCombiner);
 
}
 
static public Constraint not(final Constraint c1) {
return new Constraint() {
@Override
public String getDeclarativeForm() {
return "not (" + c1.getDeclarativeForm() + ")";
}
 
@Override
public boolean check(Object obj) {
return !c1.check(obj);
}
};
}
}
/trunk/OpenConcerto/src/org/openconcerto/record/RecordIO.java
13,6 → 13,8
package org.openconcerto.record;
 
import org.openconcerto.record.spec.Type;
 
import java.io.IOException;
import java.util.Set;
 
20,6 → 22,16
 
public Record fetch(final RecordKey key);
 
/**
* Fetch the record for the passed key.
*
* @param key the key.
* @param items which items to fetch, <code>null</code> meaning all, for {@link Type#RECORD} or
* {@link Type#RECORD_LIST} items join sub-item with '.' and for item names not only
* composed of <code>[a-zA-Z_0-9]</code> wrap them in double quotes, e.g. "ite
* m"."sub-item".
* @return the fetched record, <code>null</code> if none match.
*/
public Record fetch(final RecordKey key, final Set<String> items);
 
public Record insert(final Record r) throws IOException;