Skip to content
Snippets Groups Projects
Verified Commit 0537ceb7 authored by Timm Fitschen's avatar Timm Fitschen
Browse files

BUG: handling of empty text values and null values

parent 39b6d02d
No related branches found
No related tags found
No related merge requests found
Showing
with 206 additions and 219 deletions
......@@ -24,7 +24,6 @@ package caosdb.datetime;
import caosdb.server.datatype.AbstractDatatype.Table;
import java.util.TimeZone;
import org.jdom2.Attribute;
import org.jdom2.Element;
public class SemiCompleteDateTime extends FragmentDateTime implements Interval {
......@@ -47,11 +46,6 @@ public class SemiCompleteDateTime extends FragmentDateTime implements Interval {
throw new UnsupportedOperationException("This DateTime cannot be stored to the database.");
}
@Override
public void addToAttribute(final Attribute a) {
throw new UnsupportedOperationException("This DateTime cannot be added to an xml attribute.");
}
@Override
public String toDateTimeString(final TimeZone tz) {
final StringBuilder sb = new StringBuilder();
......
......@@ -27,7 +27,6 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.jdom2.Attribute;
import org.jdom2.Element;
public class UTCDateTime implements Interval {
......@@ -292,11 +291,6 @@ public class UTCDateTime implements Interval {
return sb.toString();
}
@Override
public void addToAttribute(final Attribute a) {
a.setValue(toDateTimeString(TimeZone.getDefault()));
}
@Override
public String toString() {
throw new NullPointerException("toString method!!!");
......
......@@ -30,6 +30,7 @@ import caosdb.server.database.proto.FlatProperty;
import caosdb.server.datatype.AbstractCollectionDatatype;
import caosdb.server.datatype.AbstractDatatype.Table;
import caosdb.server.datatype.CollectionValue;
import caosdb.server.datatype.IndexedSingleValue;
import caosdb.server.datatype.SingleValue;
import caosdb.server.entity.EntityInterface;
import caosdb.server.entity.Role;
......@@ -37,6 +38,7 @@ import caosdb.server.entity.StatementStatus;
import caosdb.server.entity.wrapper.Property;
import java.util.ArrayList;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
public class InsertEntityProperties extends BackendTransaction {
......@@ -111,22 +113,33 @@ public class InsertEntityProperties extends BackendTransaction {
if (property.getValue() instanceof CollectionValue) {
// insert collection of values
final CollectionValue v = (CollectionValue) property.getValue();
Iterator<IndexedSingleValue> iterator = v.iterator();
final SingleValue firstValue = iterator.next();
// insert 2nd to nth item
for (int i = 1; i < v.size(); i++) {
final SingleValue vi = v.get(i);
table = (vi != null ? vi.getTable() : Table.null_data);
final SingleValue vi = iterator.next();
fp.idx = i;
fp.value = (vi != null ? vi.toDatabaseString() : null);
if (vi == null) {
fp.value = null;
table = Table.null_data;
} else {
fp.value = vi.toDatabaseString();
table = vi.getTable();
}
t.execute(
domain, (entity != null ? entity : property.getDomain()), fp, table, unit_sig);
}
// insert first item
final SingleValue vi = v.get(0);
fp.idx = 0;
fp.value = vi.toDatabaseString();
table = (vi != null ? vi.getTable() : Table.null_data);
if (firstValue == null) {
fp.value = null;
table = Table.null_data;
} else {
fp.value = firstValue.toDatabaseString();
table = firstValue.getTable();
}
} else {
// insert single value
......
......@@ -24,7 +24,6 @@ package caosdb.server.datatype;
import caosdb.server.datatype.AbstractDatatype.Table;
import com.google.common.base.Objects;
import org.jdom2.Attribute;
import org.jdom2.Element;
public abstract class AbstractEnumValue implements SingleValue {
......@@ -50,11 +49,6 @@ public abstract class AbstractEnumValue implements SingleValue {
return this.value.toString();
}
@Override
public final void addToAttribute(final Attribute a) {
a.setValue(this.value.toString());
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof AbstractEnumValue) {
......
......@@ -22,30 +22,30 @@
*/
package caosdb.server.datatype;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.jdom2.Element;
public class CollectionValue extends LinkedList<IndexedSingleValue> implements Value {
public class CollectionValue implements Value, Iterable<IndexedSingleValue> {
private static final long serialVersionUID = 1L;
private List<IndexedSingleValue> list = new ArrayList<>();
@Override
public void addToElement(final Element e) {
for (final SingleValue v : this) {
final Element valueElem = new Element("Value");
if (v != null) {
v.addToElement(valueElem);
}
v.addToElement(valueElem);
e.addContent(valueElem);
}
}
@Override
public boolean add(final IndexedSingleValue e) {
if (e == null) {
return super.add(new IndexedSingleValue(null));
return list.add(new IndexedSingleValue(null));
}
return super.add(e);
return list.add(e);
}
public void add(final SingleValue v) {
......@@ -67,4 +67,17 @@ public class CollectionValue extends LinkedList<IndexedSingleValue> implements V
throw new IllegalArgumentException("Expected a SingleValue.");
}
}
@Override
public Iterator<IndexedSingleValue> iterator() {
return list.iterator();
}
public void sort() {
Collections.sort(list);
}
public int size() {
return list.size();
}
}
......@@ -24,7 +24,6 @@ package caosdb.server.datatype;
import caosdb.server.datatype.AbstractDatatype.Table;
import com.google.common.base.Objects;
import org.jdom2.Attribute;
import org.jdom2.Element;
public class GenericValue implements SingleValue {
......@@ -61,7 +60,12 @@ public class GenericValue implements SingleValue {
@Override
public void addToElement(final Element e) {
e.addContent(this.value.toString());
if (this.value instanceof String && ((String) this.value).isEmpty()) {
Element empty = new Element("EmptyString");
e.addContent(empty);
} else {
e.addContent(this.value.toString());
}
}
@Override
......@@ -74,11 +78,6 @@ public class GenericValue implements SingleValue {
return this.value.toString();
}
@Override
public void addToAttribute(final Attribute a) {
a.setValue(this.value.toString());
}
@Override
public String toString() {
return toDatabaseString();
......
......@@ -23,7 +23,6 @@
package caosdb.server.datatype;
import caosdb.server.datatype.AbstractDatatype.Table;
import org.jdom2.Attribute;
import org.jdom2.Element;
public class IndexedSingleValue implements SingleValue, Comparable<IndexedSingleValue> {
......@@ -63,13 +62,6 @@ public class IndexedSingleValue implements SingleValue, Comparable<IndexedSingle
return this.wrapped.toDatabaseString();
}
@Override
public void addToAttribute(final Attribute a) {
if (this.wrapped != null) {
this.wrapped.addToAttribute(a);
}
}
public void setIndex(final int i) {
this.index = i;
}
......
......@@ -23,7 +23,6 @@
package caosdb.server.datatype;
import caosdb.server.entity.Message;
import java.util.Collections;
public class ListDatatype extends AbstractCollectionDatatype {
......@@ -38,9 +37,13 @@ public class ListDatatype extends AbstractCollectionDatatype {
final CollectionValue ret = new CollectionValue();
if (value instanceof CollectionValue) {
final CollectionValue colValue = (CollectionValue) value;
Collections.sort(colValue);
colValue.sort();
for (final IndexedSingleValue singleValue : colValue) {
ret.add(singleValue.getIndex(), getDatatype().parseValue(singleValue.getWrapped()));
if (singleValue.getWrapped() == null) {
ret.add(singleValue.getIndex(), null);
} else {
ret.add(singleValue.getIndex(), getDatatype().parseValue(singleValue.getWrapped()));
}
}
} else {
ret.add(getDatatype().parseValue(value));
......
......@@ -26,7 +26,6 @@ import caosdb.server.datatype.AbstractDatatype.Table;
import caosdb.server.entity.EntityInterface;
import caosdb.server.entity.Message;
import caosdb.server.utils.ServerMessages;
import org.jdom2.Attribute;
import org.jdom2.Element;
public class ReferenceValue implements SingleValue {
......@@ -122,11 +121,6 @@ public class ReferenceValue implements SingleValue {
return toString();
}
@Override
public void addToAttribute(final Attribute a) {
a.setValue(toString());
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof ReferenceValue) {
......
......@@ -22,13 +22,9 @@
*/
package caosdb.server.datatype;
import org.jdom2.Attribute;
public interface SingleValue extends Value {
public AbstractDatatype.Table getTable();
public String toDatabaseString();
public void addToAttribute(Attribute a);
}
/*
* ** header v3.0
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2018 Research Group Biomedical Physics,
* Max-Planck-Institute for Dynamics and Self-Organization Göttingen
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ** end header
*/
package caosdb.server.datatype;
import caosdb.server.datatype.AbstractDatatype.Table;
import caosdb.server.entity.Message;
import org.jdom2.Attribute;
import org.jdom2.Element;
@DatatypeDefinition(name = "Timespan")
public class TimespanDatatype extends AbstractDatatype {
public static final Message TIMESPAN_NOT_PARSABLE = new Message(219, "Timespan not parsable.");
@Override
public Timespan parseValue(final Object value) throws Message {
Timespan ret = null;
try {
ret = Timespan.parse(value.toString());
} catch (final NumberFormatException e) {
// TODO define correct error message
throw TIMESPAN_NOT_PARSABLE;
}
return ret;
}
}
class Timespan implements SingleValue {
public enum Unit {
YEARS,
MONTHS,
WEEKS,
DAYS,
HOURS,
MINUTES,
SECONDS,
USERDEFINED
};
static Timespan parse(final String str) throws NumberFormatException {
final Timespan ts = new Timespan();
String[] parts;
if (str.matches("^\\s*[0-9]+(\\.[0-9]+)?([eE]-?[0-9]+)?\\s*[A-Za-z]+\\s*$")) {
parts = new String[2];
parts[0] = str.split("\\s*?[A-Za-z]*$")[0];
parts[1] = str.split("^[0-9]+(\\.[0-9]+)?([eE]-?[0-9]+)?\\s*")[1];
if (parts[1].equalsIgnoreCase(Unit.YEARS.toString()) || parts[1].equalsIgnoreCase("y")) {
ts.setUnit(Unit.YEARS);
ts.factor = 31556925.261;
} else if (parts[1].equalsIgnoreCase(Unit.MONTHS.toString()) || parts[1].equals("M")) {
ts.setUnit(Unit.MONTHS);
ts.factor = 31556925.261 / 12;
} else if (parts[1].equalsIgnoreCase(Unit.WEEKS.toString())
|| parts[1].equalsIgnoreCase("w")) {
ts.setUnit(Unit.WEEKS);
ts.factor = 7 * 86400.0;
} else if (parts[1].equalsIgnoreCase(Unit.DAYS.toString())
|| parts[1].equalsIgnoreCase("d")) {
ts.setUnit(Unit.DAYS);
ts.factor = 86400.0;
} else if (parts[1].equalsIgnoreCase(Unit.HOURS.toString())
|| parts[1].equalsIgnoreCase("h")) {
ts.setUnit(Unit.HOURS);
ts.factor = 3600.0;
} else if (parts[1].equalsIgnoreCase(Unit.MINUTES.toString()) || parts[1].equals("m")) {
ts.setUnit(Unit.MINUTES);
ts.factor = 60.0;
} else if (parts[1].equalsIgnoreCase(Unit.SECONDS.toString())
|| parts[1].equalsIgnoreCase("s")) {
ts.setUnit(Unit.SECONDS);
} else {
ts.setUnit(Unit.USERDEFINED);
}
ts.value = Double.parseDouble(parts[0]);
} else if (str.matches("^\\s*[0-9]+(\\.[0-9]+)?([eE]-?[0-9]+)?\\s*$")) {
ts.setUnit(null);
ts.value = Double.parseDouble(str);
} else {
throw new NumberFormatException("Couldn't parse String to Timespan.");
}
return ts;
}
private double value = 0;
private double factor = 1;
private Unit unit = null;
public double toSeconds() {
return value * factor;
}
@Override
public String toString() {
return Double.toString(value);
}
public String getUnit() {
return unit.toString();
}
private void setUnit(final Unit unit) {
this.unit = unit;
}
@Override
public void addToElement(Element e) {
e.addContent(toString());
}
@Override
public Table getTable() {
return Table.double_data;
}
@Override
public String toDatabaseString() {
return toString();
}
@Override
public void addToAttribute(Attribute a) {
a.setValue(toString());
}
}
/// *
// * ** header v3.0
// * This file is a part of the CaosDB Project.
// *
// * Copyright (C) 2018 Research Group Biomedical Physics,
// * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
// *
// * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU Affero General Public License as
// * published by the Free Software Foundation, either version 3 of the
// * License, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU Affero General Public License for more details.
// *
// * You should have received a copy of the GNU Affero General Public License
// * along with this program. If not, see <https://www.gnu.org/licenses/>.
// *
// * ** end header
// */
// package caosdb.server.datatype;
//
// import org.jdom2.Element;
// import caosdb.server.datatype.AbstractDatatype.Table;
// import caosdb.server.entity.Message;
//
// @DatatypeDefinition(name = "Timespan")
// public class TimespanDatatype extends AbstractDatatype {
//
// public static final Message TIMESPAN_NOT_PARSABLE = new Message(219, "Timespan not parsable.");
//
// @Override
// public Timespan parseValue(final Object value) throws Message {
// Timespan ret = null;
// try {
// ret = Timespan.parse(value.toString());
// } catch (final NumberFormatException e) {
// // TODO define correct error message
// throw TIMESPAN_NOT_PARSABLE;
// }
// return ret;
// }
// }
//
// class Timespan implements SingleValue {
// public enum Unit {
// YEARS,
// MONTHS,
// WEEKS,
// DAYS,
// HOURS,
// MINUTES,
// SECONDS,
// USERDEFINED
// };
//
// static Timespan parse(final String str) throws NumberFormatException {
//
// final Timespan ts = new Timespan();
// String[] parts;
// if (str.matches("^\\s*[0-9]+(\\.[0-9]+)?([eE]-?[0-9]+)?\\s*[A-Za-z]+\\s*$")) {
// parts = new String[2];
// parts[0] = str.split("\\s*?[A-Za-z]*$")[0];
// parts[1] = str.split("^[0-9]+(\\.[0-9]+)?([eE]-?[0-9]+)?\\s*")[1];
//
// if (parts[1].equalsIgnoreCase(Unit.YEARS.toString()) || parts[1].equalsIgnoreCase("y")) {
// ts.setUnit(Unit.YEARS);
// ts.factor = 31556925.261;
// } else if (parts[1].equalsIgnoreCase(Unit.MONTHS.toString()) || parts[1].equals("M")) {
// ts.setUnit(Unit.MONTHS);
// ts.factor = 31556925.261 / 12;
// } else if (parts[1].equalsIgnoreCase(Unit.WEEKS.toString())
// || parts[1].equalsIgnoreCase("w")) {
// ts.setUnit(Unit.WEEKS);
// ts.factor = 7 * 86400.0;
// } else if (parts[1].equalsIgnoreCase(Unit.DAYS.toString())
// || parts[1].equalsIgnoreCase("d")) {
// ts.setUnit(Unit.DAYS);
// ts.factor = 86400.0;
// } else if (parts[1].equalsIgnoreCase(Unit.HOURS.toString())
// || parts[1].equalsIgnoreCase("h")) {
// ts.setUnit(Unit.HOURS);
// ts.factor = 3600.0;
// } else if (parts[1].equalsIgnoreCase(Unit.MINUTES.toString()) || parts[1].equals("m")) {
// ts.setUnit(Unit.MINUTES);
// ts.factor = 60.0;
// } else if (parts[1].equalsIgnoreCase(Unit.SECONDS.toString())
// || parts[1].equalsIgnoreCase("s")) {
// ts.setUnit(Unit.SECONDS);
// } else {
// ts.setUnit(Unit.USERDEFINED);
// }
// ts.value = Double.parseDouble(parts[0]);
// } else if (str.matches("^\\s*[0-9]+(\\.[0-9]+)?([eE]-?[0-9]+)?\\s*$")) {
// ts.setUnit(null);
// ts.value = Double.parseDouble(str);
//
// } else {
// throw new NumberFormatException("Couldn't parse String to Timespan.");
// }
// return ts;
// }
//
// private double value = 0;
// private double factor = 1;
//
// private Unit unit = null;
//
// public double toSeconds() {
// return value * factor;
// }
//
// @Override
// public String toString() {
// return Double.toString(value);
// }
//
// public String getUnit() {
// return unit.toString();
// }
//
// private void setUnit(final Unit unit) {
// this.unit = unit;
// }
//
// @Override
// public void addToElement(Element e) {
// e.addContent(toString());
// }
//
// @Override
// public Table getTable() {
// return Table.double_data;
// }
//
// @Override
// public String toDatabaseString() {
// return toString();
// }
//
// }
......@@ -794,15 +794,18 @@ public class Entity extends AbstractObservable implements EntityInterface {
final CollectionValue vals = new CollectionValue();
int pidx = 0;
for (final Element pe : element.getChildren()) {
if (pe.getName().equalsIgnoreCase("Value")) {
if (pe.getName().equalsIgnoreCase("EmptyString")) {
// special case: empty string which cannot be distinguished from null
// values otherwise.
setValue(new GenericValue(""));
} else if (pe.getName().equalsIgnoreCase("Value")) {
// Parse sub-elements which represent VALUES of this entity.
if (pe.getText() != null && pe.getTextTrim() != "") {
if (pe.getChild("EmptyString") != null) {
vals.add(new GenericValue(""));
} else if (pe.getText() != null && pe.getTextTrim() != "") {
vals.add(new GenericValue(pe.getTextTrim()));
} else if (pe.getAttribute("null") != null) {
vals.add(null);
} else {
vals.add(new GenericValue(""));
vals.add(null);
}
} else if (pe.getName().equalsIgnoreCase("Property")) {
// Parse sub elements which represent PROPERTIES of this
......@@ -866,8 +869,6 @@ public class Entity extends AbstractObservable implements EntityInterface {
// Parse VALUE.
if (vals.size() != 0) {
setValue(vals);
} else if (element.getAttribute("null") != null) {
setValue(null);
} else if (element.getTextTrim() != null && !element.getTextTrim().equals("")) {
setValue(new GenericValue(element.getTextTrim()));
}
......
......@@ -47,9 +47,8 @@ public class PropertyToElementStrategy extends EntityToElementStrategy {
switch (MagicTypes.getType(entity.getId())) {
case UNIT:
if (setFieldStrategy.isToBeSet("unit") && v != null) {
final Attribute a = new Attribute("unit", "");
final Attribute a = new Attribute("unit", ((SingleValue) v).toDatabaseString());
element.setAttribute(a);
((SingleValue) v).addToAttribute(a);
}
return element;
default:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment