# HG changeset patch # User Sascha L. Teichmann # Date 1326980166 0 # Node ID c5791de0c49569635a2e6d1638407cdab7fdbb02 # Parent aa777d1aba385d616ae6dd78c6ebf8a2289f0b3c Added meachnism to backend to fetch all annotation related data in one go. flys-backend/trunk@3722 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r aa777d1aba38 -r c5791de0c495 flys-backend/ChangeLog --- a/flys-backend/ChangeLog Wed Jan 18 09:26:54 2012 +0000 +++ b/flys-backend/ChangeLog Thu Jan 19 13:36:06 2012 +0000 @@ -1,3 +1,9 @@ +2012-01-18 Sascha L. Teichmann + + * src/main/java/de/intevation/flys/model/FastAnnotations.java: + New. Fetches all informations of annotations in one go for + a river. Useful to speed up annotation handling. + 2012-01-18 Ingo Weinzierl * src/main/java/de/intevation/flys/model/Gauge.java: Added a function that diff -r aa777d1aba38 -r c5791de0c495 flys-backend/src/main/java/de/intevation/flys/model/FastAnnotations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-backend/src/main/java/de/intevation/flys/model/FastAnnotations.java Thu Jan 19 13:36:06 2012 +0000 @@ -0,0 +1,313 @@ +package de.intevation.flys.model; + +import java.util.Comparator; +import java.util.ArrayList; +import java.util.List; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import java.io.Serializable; + +import org.hibernate.Session; +import org.hibernate.SQLQuery; + +import org.hibernate.type.StandardBasicTypes; + +import de.intevation.flys.backend.SessionHolder; + +public class FastAnnotations +implements Serializable +{ + public static final String SQL_BY_RIVER_NAME = + "SELECT r.a AS a, r.b AS b, p.value AS position, " + + "at.value AS attribute, ant.name AS name, " + + "e.top AS top, e.bottom AS bottom " + + "FROM annotations an " + + "JOIN ranges r " + + "ON an.range_id = r.id " + + "JOIN attributes at " + + "ON an.attribute_id = at.id " + + "JOIN positions p " + + "ON an.position_id = p.id " + + "JOIN rivers riv " + + "ON r.river_id = riv.id " + + "LEFT JOIN annotation_types ant " + + "ON an.type_id = ant.id " + + "LEFT JOIN edges e " + + "ON an.edge_id = e.id " + + "WHERE riv.name = :river_name " + + "ORDER BY r.a"; + + public static final String SQL_BY_RIVER_ID = + "SELECT r.a AS a, r.b AS b, p.value AS position, " + + "at.value AS attribute, ant.name AS name, " + + "e.top AS top, e.bottom AS bottom " + + "FROM annotations an " + + "JOIN ranges r " + + "ON an.range_id = r.id " + + "JOIN attributes at " + + "ON an.attribute_id = at.id " + + "JOIN positions p " + + "ON an.position_id = p.id " + + "LEFT JOIN annotation_types ant " + + "ON an.type_id = ant.id " + + "LEFT JOIN edges e " + + "ON an.edge_id = e.id " + + "WHERE r.id = :river_id " + + "ORDER BY r.a"; + + public static final double EPSILON = 1e-5; + + public static final Comparator KM_CMP = + new Comparator() { + @Override + public int compare(Annotation a, Annotation b) { + double diff = a.a - b.a; + if (diff < -EPSILON) return -1; + if (diff > +EPSILON) return +1; + return 0; + } + }; + + public static final class Annotation + implements Serializable + { + private double a; + private double b; + private String position; + private String attribute; + private String name; + private double top; + private double bottom; + + public Annotation() { + } + + public Annotation(double a) { + this.a = a; + } + + public Annotation( + double a, + double b, + String position, + String attribute, + String name, + double top, + double bottom + ) { + this.a = a; + this.b = b; + this.position = position; + this.attribute = attribute; + this.name = name; + this.top = top; + this.bottom = bottom; + } + + public double getA() { + return a; + } + + public double getB() { + return b; + } + + public String getPosition() { + return position; + } + + public String getAttribute() { + return attribute; + } + + public String getName() { + return name; + } + + public double getTop() { + return top; + } + + public double getBottom() { + return bottom; + } + } // class Serializable + + public interface Filter { + + boolean accept(Annotation annotation); + + } // interface Filter + + public static final Filter ALL = new Filter() { + @Override + public boolean accept(Annotation annotation) { + return true; + } + }; + + public static final Filter IS_POINT = new Filter() { + @Override + public boolean accept(Annotation annotation) { + return Double.isNaN(annotation.getB()); + } + }; + + public static final Filter IS_RANGE = new Filter() { + @Override + public boolean accept(Annotation annotation) { + return !Double.isNaN(annotation.getB()); + } + }; + + private Annotation [] annotations; + + public FastAnnotations() { + } + + public FastAnnotations(Annotation [] annotations) { + this.annotations = annotations; + } + + public FastAnnotations(String riverName) { + this(loadByRiverName(riverName)); + } + + public FastAnnotations(int riverId) { + this(loadByRiverId(riverId)); + } + + public FastAnnotations(Iterator iter) { + this(toArray(iter)); + } + + public int size() { + return annotations.length; + } + + public Iterator filter(final Filter filter) { + return new Iterator() { + + private int idx; + private Annotation current = findNext(); + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public Annotation next() { + if (current == null) { + throw new NoSuchElementException(); + } + Annotation result = current; + current = findNext(); + return result; + } + + private Annotation findNext() { + + while (idx < annotations.length) { + Annotation annotation = annotations[idx++]; + if (filter.accept(annotation)) { + return annotation; + } + } + + return null; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + public static Annotation [] toArray(Iterator iter) { + + ArrayList list = new ArrayList(); + + while (iter.hasNext()) { + list.add(iter.next()); + } + + return list.toArray(new Annotation[list.size()]); + } + + public Annotation findByKm(double km) { + Annotation key = new Annotation(km); + int idx = Arrays.binarySearch(annotations, key, KM_CMP); + return idx < 0 ? null : annotations[idx]; + } + + private static SQLQuery createQuery(String query) { + Session session = SessionHolder.HOLDER.get(); + + return session.createSQLQuery(query) + .addScalar("a", StandardBasicTypes.DOUBLE) + .addScalar("b", StandardBasicTypes.DOUBLE) + .addScalar("position", StandardBasicTypes.STRING) + .addScalar("attribute", StandardBasicTypes.STRING) + .addScalar("name", StandardBasicTypes.STRING) + .addScalar("top", StandardBasicTypes.DOUBLE) + .addScalar("bottom", StandardBasicTypes.DOUBLE); + } + + private static Annotation [] buildAnnotations(List list) { + Annotation [] anns = new Annotation[list.size()]; + + // Names are likely the same because they are a type + // like 'Pegel' or 'Hafen'. + HashMap names = new HashMap(); + + for (int i = 0; i < anns.length; ++i) { + Object [] data = list.get(i); + double a = ((Double)data[0]); + double b = data[1] != null ? (Double)data[1] : Double.NaN; + String position = (String)data[2]; + String attribute = (String)data[3]; + String name = (String)data[4]; + double top = data[5] != null ? (Double)data[5] : Double.NaN; + double bottom = data[6] != null ? (Double)data[6] : Double.NaN; + + if (name != null) { + String old = names.get(name); + if (old != null) { + name = old; + } + else { + names.put(name, name); + } + } + + anns[i] = new Annotation( + a, b, position, attribute, name, top, bottom); + } + + return anns; + } + + public static Annotation [] loadByRiverName(String riverName) { + + SQLQuery query = createQuery(SQL_BY_RIVER_NAME); + + query.setString("river_name", riverName); + + return buildAnnotations(query.list()); + } + + public static Annotation [] loadByRiverId(int riverId) { + + SQLQuery query = createQuery(SQL_BY_RIVER_ID); + + query.setInteger("river_id", riverId); + + return buildAnnotations(query.list()); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :