Repository: graphhopper/graphhopper
Pull request #2168 (2020-10-27 11:06:59)

TransportationMode refactoring
Should avoid new methods to FlagEncoder like in #2159


Patch:
diff --git a/core/files/changelog.txt b/core/files/changelog.txt
index b80fb06b3..eb692e84f 100644
--- a/core/files/changelog.txt
+++ b/core/files/changelog.txt
@@ -1,4 +1,5 @@
 3.0
+    refactored TransportationMode to better reflect the usage in source data parsing only
     CustomWeighting requires LinkedHashMap throw exception if this is not provided
     removed Dockerfile
     the second argument of the VirtualEdgeIteratorState constructor is now an edge key (was an edge id before)
diff --git a/core/src/main/java/com/graphhopper/GraphHopper.java b/core/src/main/java/com/graphhopper/GraphHopper.java
index 740ec14d6..2bb510c54 100644
--- a/core/src/main/java/com/graphhopper/GraphHopper.java
+++ b/core/src/main/java/com/graphhopper/GraphHopper.java
@@ -1189,6 +1189,10 @@ public class GraphHopper implements GraphHopperAPI {
         fullyLoaded = true;
     }
 
+    public boolean getFullyLoaded(){
+        return fullyLoaded;
+    }
+
     public RouterConfig getRouterConfig() {
         return routerConfig;
     }
diff --git a/core/src/main/java/com/graphhopper/routing/InstructionsFromEdges.java b/core/src/main/java/com/graphhopper/routing/InstructionsFromEdges.java
index 4cec4b5ba..c466b07f1 100644
--- a/core/src/main/java/com/graphhopper/routing/InstructionsFromEdges.java
+++ b/core/src/main/java/com/graphhopper/routing/InstructionsFromEdges.java
@@ -20,7 +20,7 @@ package com.graphhopper.routing;
 import com.graphhopper.routing.ev.*;
 import com.graphhopper.routing.util.DefaultEdgeFilter;
 import com.graphhopper.routing.util.FlagEncoder;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
+import com.graphhopper.routing.util.TransportationMode;
 import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Graph;
 import com.graphhopper.storage.NodeAccess;
@@ -102,7 +102,7 @@ public class InstructionsFromEdges implements Path.EdgeVisitor {
         // both EncodedValues are optional; And return annotation only when instructions for bike encoder is requested
         String key = RouteNetwork.key("bike");
         this.bikeRouteEnc = evLookup.hasEncodedValue(key) ? evLookup.getEnumEncodedValue(key, RouteNetwork.class) : null;
-        this.getOffBikeEnc = encoder.getTransportationMode() == TransportationMode.BICYCLE && evLookup.hasEncodedValue(GetOffBike.KEY)
+        this.getOffBikeEnc = encoder.getTransportationMode() == TransportationMode.BIKE && evLookup.hasEncodedValue(GetOffBike.KEY)
                 ? evLookup.getBooleanEncodedValue(GetOffBike.KEY) : null;
         this.tollEnc = evLookup.hasEncodedValue(Toll.KEY) ? evLookup.getEnumEncodedValue(Toll.KEY, Toll.class) : null;
 
diff --git a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
index 22df25242..c67fb142e 100644
--- a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
@@ -23,6 +23,7 @@ import com.graphhopper.reader.ReaderWay;
 import com.graphhopper.reader.osm.conditional.ConditionalOSMTagInspector;
 import com.graphhopper.reader.osm.conditional.DateRangeParser;
 import com.graphhopper.routing.ev.*;
+import com.graphhopper.routing.util.parsers.OSMRoadAccessParser;
 import com.graphhopper.routing.util.parsers.helpers.OSMValueExtractor;
 import com.graphhopper.storage.IntsRef;
 import com.graphhopper.util.*;
@@ -42,9 +43,9 @@ import java.util.*;
  */
 public abstract class AbstractFlagEncoder implements FlagEncoder {
     private final static Logger logger = LoggerFactory.getLogger(AbstractFlagEncoder.class);
-    /* restriction definitions where order is important */
-    protected final List<String> restrictions = new ArrayList<>(5);
     protected final Set<String> intendedValues = new HashSet<>(5);
+    // order is important
+    protected final List<String> restrictions = new ArrayList<>(5);
     protected final Set<String> restrictedValues = new HashSet<>(5);
     protected final Set<String> ferries = new HashSet<>(5);
     protected final Set<String> oneways = new HashSet<>(5);
@@ -92,6 +93,7 @@ public abstract class AbstractFlagEncoder implements FlagEncoder {
 
         ferries.add("shuttle_train");
         ferries.add("ferry");
+        restrictions.addAll(OSMRoadAccessParser.toOSMRestrictions(getTransportationMode()));
     }
 
     protected void init(DateRangeParser dateRangeParser) {
diff --git a/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java
index 31b9e1d8e..de1c684e3 100644
--- a/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java
@@ -19,7 +19,6 @@ package com.graphhopper.routing.util;
 
 import com.graphhopper.reader.ReaderWay;
 import com.graphhopper.routing.ev.*;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
 import com.graphhopper.routing.weighting.PriorityWeighting;
 import com.graphhopper.storage.IntsRef;
 import com.graphhopper.util.Helper;
@@ -61,8 +60,6 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
 
     protected BikeCommonFlagEncoder(int speedBits, double speedFactor, int maxTurnCosts) {
         super(speedBits, speedFactor, maxTurnCosts);
-        // strict set, usually vehicle and agricultural/forestry are ignored by cyclists
-        restrictions.addAll(Arrays.asList("bicycle", "vehicle", "access"));
 
         restrictedValues.add("no");
         restrictedValues.add("restricted");
@@ -186,7 +183,7 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
 
     @Override
     public TransportationMode getTransportationMode() {
-        return TransportationMode.BICYCLE;
+        return TransportationMode.BIKE;
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java
index 53075a2d4..c32f8dffb 100644
--- a/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java
@@ -20,7 +20,6 @@ package com.graphhopper.routing.util;
 import com.graphhopper.reader.ReaderWay;
 import com.graphhopper.routing.ev.EncodedValue;
 import com.graphhopper.routing.ev.UnsignedDecimalEncodedValue;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
 import com.graphhopper.storage.IntsRef;
 import com.graphhopper.util.Helper;
 import com.graphhopper.util.PMap;
@@ -61,7 +60,6 @@ public class CarFlagEncoder extends AbstractFlagEncoder {
                 properties.getDouble("speed_factor", 5),
                 properties.getInt("max_turn_costs", properties.getBool("turn_costs", false) ? 1 : 0));
 
-        restrictions.addAll(Arrays.asList("motorcar", "motor_vehicle", "vehicle", "access"));
         restrictedValues.add("agricultural");
         restrictedValues.add("forestry");
         restrictedValues.add("no");
@@ -149,7 +147,7 @@ public class CarFlagEncoder extends AbstractFlagEncoder {
     }
 
     public TransportationMode getTransportationMode() {
-        return TransportationMode.MOTOR_VEHICLE;
+        return TransportationMode.CAR;
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java b/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java
index d174de533..f235d9174 100644
--- a/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java
+++ b/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java
@@ -318,8 +318,10 @@ public class EncodingManager implements EncodedValueLookup {
                 _addEdgeTagParser(new OSMRoadEnvironmentParser(), false, false);
             if (!em.hasEncodedValue(MaxSpeed.KEY))
                 _addEdgeTagParser(new OSMMaxSpeedParser(), false, false);
-            if (!em.hasEncodedValue(RoadAccess.KEY))
+            if (!em.hasEncodedValue(RoadAccess.KEY)) {
+                // TODO introduce road_access for different vehicles? But how to create it in DefaultTagParserFactory?
                 _addEdgeTagParser(new OSMRoadAccessParser(), false, false);
+            }
 
             // ensure that SpatialRuleParsers come after required EncodedValues like max_speed or road_access
             // TODO can we avoid this hack without complex dependency management?
@@ -356,7 +358,8 @@ public class EncodingManager implements EncodedValueLookup {
             // FlagEncoder can demand TurnCostParsers => add them after the explicitly added ones
             for (AbstractFlagEncoder encoder : flagEncoderList) {
                 if (encoder.supportsTurnCosts() && !em.turnCostParsers.containsKey(encoder.toString()))
-                    _addTurnCostParser(new OSMTurnRelationParser(encoder.toString(), encoder.getMaxTurnCosts()));
+                    _addTurnCostParser(new OSMTurnRelationParser(encoder.toString(), encoder.getMaxTurnCosts(),
+                            OSMRoadAccessParser.toOSMRestrictions(encoder.getTransportationMode())));
             }
 
             if (em.encodedValueMap.isEmpty())
diff --git a/core/src/main/java/com/graphhopper/routing/util/FlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/FlagEncoder.java
index e33f6ac5f..fc4b68522 100644
--- a/core/src/main/java/com/graphhopper/routing/util/FlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/FlagEncoder.java
@@ -20,7 +20,6 @@ package com.graphhopper.routing.util;
 import com.graphhopper.routing.ev.BooleanEncodedValue;
 import com.graphhopper.routing.ev.DecimalEncodedValue;
 import com.graphhopper.routing.ev.EncodedValueLookup;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
 
 /**
  * This class provides methods to define how a value (like speed or direction) converts to a flag
diff --git a/core/src/main/java/com/graphhopper/routing/util/FootFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/FootFlagEncoder.java
index aaf0299ea..14af94c1e 100644
--- a/core/src/main/java/com/graphhopper/routing/util/FootFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/FootFlagEncoder.java
@@ -19,7 +19,6 @@ package com.graphhopper.routing.util;
 
 import com.graphhopper.reader.ReaderWay;
 import com.graphhopper.routing.ev.*;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
 import com.graphhopper.routing.weighting.PriorityWeighting;
 import com.graphhopper.storage.IntsRef;
 import com.graphhopper.util.PMap;
@@ -70,7 +69,6 @@ public class FootFlagEncoder extends AbstractFlagEncoder {
 
     protected FootFlagEncoder(int speedBits, double speedFactor) {
         super(speedBits, speedFactor, 0);
-        restrictions.addAll(Arrays.asList("foot", "access"));
 
         restrictedValues.add("no");
         restrictedValues.add("restricted");
diff --git a/core/src/main/java/com/graphhopper/routing/util/MotorcycleFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/MotorcycleFlagEncoder.java
index 5ba2e7387..7414ab005 100644
--- a/core/src/main/java/com/graphhopper/routing/util/MotorcycleFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/MotorcycleFlagEncoder.java
@@ -53,9 +53,6 @@ public class MotorcycleFlagEncoder extends CarFlagEncoder {
 
     public MotorcycleFlagEncoder(PMap properties) {
         super(properties.putObject("speed_two_directions", true));
-        restrictions.remove("motorcar");
-        // moped, mofa
-        restrictions.add("motorcycle");
 
         absoluteBarriers.remove("bus_trap");
         absoluteBarriers.remove("sump_buster");
@@ -278,6 +275,11 @@ public class MotorcycleFlagEncoder extends CarFlagEncoder {
         return (Math.pow(bendiness, 2));
     }
 
+    @Override
+    public TransportationMode getTransportationMode() {
+        return TransportationMode.MOTORCYCLE;
+    }
+
     @Override
     public boolean supports(Class<?> feature) {
         if (super.supports(feature))
diff --git a/core/src/main/java/com/graphhopper/routing/util/spatialrules/TransportationMode.java b/core/src/main/java/com/graphhopper/routing/util/TransportationMode.java
similarity index 62%
rename from core/src/main/java/com/graphhopper/routing/util/spatialrules/TransportationMode.java
rename to core/src/main/java/com/graphhopper/routing/util/TransportationMode.java
index 5cb7383c9..480197457 100644
--- a/core/src/main/java/com/graphhopper/routing/util/spatialrules/TransportationMode.java
+++ b/core/src/main/java/com/graphhopper/routing/util/TransportationMode.java
@@ -15,28 +15,26 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package com.graphhopper.routing.util.spatialrules;
+package com.graphhopper.routing.util;
 
 /**
- * Defining different types of transportation.
- * <p>
- * We started with a subset of the definition found in the OSM Wiki
- * https://wiki.openstreetmap.org/wiki/Key:access#Land-based_transportation
+ * Define different types of transportation that are used to create and populate our encoded values from a data source
+ * like OpenStreetMap.
  *
  * @author Robin Boldt
+ * @author Peter Karich
  */
 public enum TransportationMode {
+    OTHER(false), FOOT(false), VEHICLE(false), BIKE(false),
+    MOTOR_VEHICLE(true), CAR(true), MOTORCYCLE(true), HGV(true);
 
-    OTHER(0), MOTOR_VEHICLE(1), BICYCLE(2), FOOT(3);
+    private final boolean motorVehicle;
 
-    private final int value;
-
-    TransportationMode(int value) {
-        this.value = value;
+    TransportationMode(boolean motorVehicle) {
+        this.motorVehicle = motorVehicle;
     }
 
-    public int getValue() {
-        return value;
+    public boolean isMotorVehicle() {
+        return motorVehicle;
     }
-
 }
diff --git a/core/src/main/java/com/graphhopper/routing/util/WheelchairFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/WheelchairFlagEncoder.java
index 190bcb103..6b9859400 100644
--- a/core/src/main/java/com/graphhopper/routing/util/WheelchairFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/WheelchairFlagEncoder.java
@@ -59,8 +59,8 @@ public class WheelchairFlagEncoder extends FootFlagEncoder {
 
     protected WheelchairFlagEncoder(int speedBits, double speedFactor) {
         super(speedBits, speedFactor);
-        restrictions.add("wheelchair");
 
+        restrictions.add("wheelchair");
         absoluteBarriers.add("handrail");
         absoluteBarriers.add("wall");
         absoluteBarriers.add("turnstile");
diff --git a/core/src/main/java/com/graphhopper/routing/util/parsers/OSMMaxSpeedParser.java b/core/src/main/java/com/graphhopper/routing/util/parsers/OSMMaxSpeedParser.java
index 2679f637c..a640f3c96 100644
--- a/core/src/main/java/com/graphhopper/routing/util/parsers/OSMMaxSpeedParser.java
+++ b/core/src/main/java/com/graphhopper/routing/util/parsers/OSMMaxSpeedParser.java
@@ -25,7 +25,7 @@ import com.graphhopper.routing.ev.MaxSpeed;
 import com.graphhopper.routing.ev.RoadClass;
 import com.graphhopper.routing.util.parsers.helpers.OSMValueExtractor;
 import com.graphhopper.routing.util.spatialrules.SpatialRuleSet;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
+import com.graphhopper.routing.util.TransportationMode;
 import com.graphhopper.storage.IntsRef;
 
 import java.util.List;
@@ -59,7 +59,7 @@ public class OSMMaxSpeedParser implements TagParser {
         SpatialRuleSet spatialRuleSet = way.getTag("spatial_rule_set", null);
         if (spatialRuleSet != null && spatialRuleSet != SpatialRuleSet.EMPTY) {
             RoadClass roadClass = RoadClass.find(way.getTag("highway", ""));
-            maxSpeed = spatialRuleSet.getMaxSpeed(roadClass, TransportationMode.MOTOR_VEHICLE, maxSpeed);
+            maxSpeed = spatialRuleSet.getMaxSpeed(roadClass, TransportationMode.CAR, maxSpeed);
         }
 
         double fwdSpeed = OSMValueExtractor.stringToKmh(way.getTag("maxspeed:forward"));
diff --git a/core/src/main/java/com/graphhopper/routing/util/parsers/OSMRoadAccessParser.java b/core/src/main/java/com/graphhopper/routing/util/parsers/OSMRoadAccessParser.java
index 4f10b310c..de7b91f23 100644
--- a/core/src/main/java/com/graphhopper/routing/util/parsers/OSMRoadAccessParser.java
+++ b/core/src/main/java/com/graphhopper/routing/util/parsers/OSMRoadAccessParser.java
@@ -19,8 +19,8 @@ package com.graphhopper.routing.util.parsers;
 
 import com.graphhopper.reader.ReaderWay;
 import com.graphhopper.routing.ev.*;
+import com.graphhopper.routing.util.TransportationMode;
 import com.graphhopper.routing.util.spatialrules.SpatialRuleSet;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
 import com.graphhopper.storage.IntsRef;
 
 import java.util.Arrays;
@@ -33,7 +33,7 @@ public class OSMRoadAccessParser implements TagParser {
     private final List<String> restrictions;
 
     public OSMRoadAccessParser() {
-        this(new EnumEncodedValue<>(RoadAccess.KEY, RoadAccess.class), Arrays.asList("motorcar", "motor_vehicle", "vehicle", "access"));
+        this(new EnumEncodedValue<>(RoadAccess.KEY, RoadAccess.class), toOSMRestrictions(TransportationMode.CAR));
     }
 
     public OSMRoadAccessParser(EnumEncodedValue<RoadAccess> roadAccessEnc, List<String> restrictions) {
@@ -60,10 +60,31 @@ public class OSMRoadAccessParser implements TagParser {
         SpatialRuleSet spatialRuleSet = readerWay.getTag("spatial_rule_set", null);
         if (spatialRuleSet != null && spatialRuleSet != SpatialRuleSet.EMPTY) {
             RoadClass roadClass = RoadClass.find(readerWay.getTag("highway", ""));
-            accessValue = spatialRuleSet.getAccess(roadClass, TransportationMode.MOTOR_VEHICLE, YES);
+            accessValue = spatialRuleSet.getAccess(roadClass, TransportationMode.CAR, YES);
         }
-            
+
         roadAccessEnc.setEnum(false, edgeFlags, accessValue);
         return edgeFlags;
     }
+
+    public static List<String> toOSMRestrictions(TransportationMode mode) {
+        switch (mode) {
+            case FOOT:
+                return Arrays.asList("foot", "access");
+            case VEHICLE:
+                return Arrays.asList("vehicle", "access");
+            case BIKE:
+                return Arrays.asList("bicycle", "vehicle", "access");
+            case MOTOR_VEHICLE:
+                return Arrays.asList("motor_vehicle", "vehicle", "access");
+            case CAR:
+                return Arrays.asList("motorcar", "motor_vehicle", "vehicle", "access");
+            case MOTORCYCLE:
+                return Arrays.asList("motorcycle", "motor_vehicle", "vehicle", "access");
+            case HGV:
+                return Arrays.asList("hgv", "motor_vehicle", "vehicle", "access");
+            default:
+                throw new IllegalArgumentException("Cannot convert TransportationMode " + mode + " to list of restrictions");
+        }
+    }
 }
diff --git a/core/src/main/java/com/graphhopper/routing/util/parsers/OSMTurnRelationParser.java b/core/src/main/java/com/graphhopper/routing/util/parsers/OSMTurnRelationParser.java
index 1fce0885a..ec62aa1dd 100644
--- a/core/src/main/java/com/graphhopper/routing/util/parsers/OSMTurnRelationParser.java
+++ b/core/src/main/java/com/graphhopper/routing/util/parsers/OSMTurnRelationParser.java
@@ -25,9 +25,6 @@ import com.graphhopper.storage.TurnCostStorage;
 import com.graphhopper.util.EdgeExplorer;
 import com.graphhopper.util.EdgeIterator;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 
 import static com.graphhopper.routing.util.EncodingManager.getKey;
@@ -38,7 +35,7 @@ import static com.graphhopper.routing.util.EncodingManager.getKey;
 public class OSMTurnRelationParser implements TurnCostParser {
     private String name;
     private DecimalEncodedValue turnCostEnc;
-    private final Collection<String> restrictions;
+    private final List<String> restrictions;
     private BooleanEncodedValue accessEnc;
     private EdgeExplorer cachedOutExplorer, cachedInExplorer;
 
@@ -46,32 +43,16 @@ public class OSMTurnRelationParser implements TurnCostParser {
      * @param maxTurnCosts specify the maximum value used for turn costs, if this value is reached a
      *                     turn is forbidden and results in costs of positive infinity.
      */
-    public OSMTurnRelationParser(String name, int maxTurnCosts) {
-        this(name, maxTurnCosts, Collections.<String>emptyList());
-    }
-
-    public OSMTurnRelationParser(String name, int maxTurnCosts, Collection<String> restrictions) {
+    public OSMTurnRelationParser(String name, int maxTurnCosts, List<String> restrictions) {
         this.name = name;
         this.turnCostEnc = TurnCost.create(name, maxTurnCosts);
 
-        if (restrictions.isEmpty()) {
-            // https://wiki.openstreetmap.org/wiki/Key:access
-            if (name.contains("car"))
-                this.restrictions = Arrays.asList("motorcar", "motor_vehicle", "vehicle", "access");
-            else if (name.contains("motorbike") || name.contains("motorcycle"))
-                this.restrictions = Arrays.asList("motorcycle", "motor_vehicle", "vehicle", "access");
-            else if (name.contains("truck"))
-                this.restrictions = Arrays.asList("hgv", "motor_vehicle", "vehicle", "access");
-            else if (name.contains("bike") || name.contains("bicycle"))
-                this.restrictions = Arrays.asList("bicycle", "vehicle", "access");
-            else
-                // assume default is some motor_vehicle, exception is too strict
-                this.restrictions = Arrays.asList("motor_vehicle", "vehicle", "access");
-        } else {
-            this.restrictions = restrictions;
-        }
+        if (restrictions.isEmpty())
+            throw new IllegalArgumentException("restrictions cannot be empty");
+        this.restrictions = restrictions;
     }
 
+    // for test only
     DecimalEncodedValue getTurnCostEnc() {
         return turnCostEnc;
     }
diff --git a/core/src/main/java/com/graphhopper/routing/util/spatialrules/AbstractSpatialRule.java b/core/src/main/java/com/graphhopper/routing/util/spatialrules/AbstractSpatialRule.java
index 3116cbeed..7f04e2440 100644
--- a/core/src/main/java/com/graphhopper/routing/util/spatialrules/AbstractSpatialRule.java
+++ b/core/src/main/java/com/graphhopper/routing/util/spatialrules/AbstractSpatialRule.java
@@ -20,6 +20,7 @@ package com.graphhopper.routing.util.spatialrules;
 import java.util.Collections;
 import java.util.List;
 
+import com.graphhopper.routing.util.TransportationMode;
 import org.locationtech.jts.geom.Polygon;
 
 import com.graphhopper.routing.ev.RoadAccess;
diff --git a/core/src/main/java/com/graphhopper/routing/util/spatialrules/SpatialRule.java b/core/src/main/java/com/graphhopper/routing/util/spatialrules/SpatialRule.java
index 568369591..a1f7d42dd 100644
--- a/core/src/main/java/com/graphhopper/routing/util/spatialrules/SpatialRule.java
+++ b/core/src/main/java/com/graphhopper/routing/util/spatialrules/SpatialRule.java
@@ -22,6 +22,7 @@ import com.graphhopper.routing.ev.RoadClass;
 
 import java.util.List;
 
+import com.graphhopper.routing.util.TransportationMode;
 import org.locationtech.jts.geom.Polygon;
 
 /**
diff --git a/core/src/main/java/com/graphhopper/routing/util/spatialrules/SpatialRuleSet.java b/core/src/main/java/com/graphhopper/routing/util/spatialrules/SpatialRuleSet.java
index e86b25a88..3cb48d38c 100644
--- a/core/src/main/java/com/graphhopper/routing/util/spatialrules/SpatialRuleSet.java
+++ b/core/src/main/java/com/graphhopper/routing/util/spatialrules/SpatialRuleSet.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import com.graphhopper.routing.ev.RoadAccess;
 import com.graphhopper.routing.ev.RoadClass;
+import com.graphhopper.routing.util.TransportationMode;
 
 /**
  * Contains all rules which are applicable for a certain position.
diff --git a/core/src/main/java/com/graphhopper/routing/util/spatialrules/countries/AustriaSpatialRule.java b/core/src/main/java/com/graphhopper/routing/util/spatialrules/countries/AustriaSpatialRule.java
index faead9686..06304eec8 100644
--- a/core/src/main/java/com/graphhopper/routing/util/spatialrules/countries/AustriaSpatialRule.java
+++ b/core/src/main/java/com/graphhopper/routing/util/spatialrules/countries/AustriaSpatialRule.java
@@ -25,7 +25,7 @@ import com.graphhopper.routing.ev.Country;
 import com.graphhopper.routing.ev.RoadAccess;
 import com.graphhopper.routing.ev.RoadClass;
 import com.graphhopper.routing.util.spatialrules.AbstractSpatialRule;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
+import com.graphhopper.routing.util.TransportationMode;
 
 /**
  * Defines the default rules for Austria roads
@@ -40,7 +40,7 @@ public class AustriaSpatialRule extends AbstractSpatialRule {
     
     @Override
     public double getMaxSpeed(RoadClass roadClass, TransportationMode transport, double currentMaxSpeed) {
-        if (!Double.isNaN(currentMaxSpeed) || transport != TransportationMode.MOTOR_VEHICLE) {
+        if (!Double.isNaN(currentMaxSpeed) || !transport.isMotorVehicle()) {
             return currentMaxSpeed;
         }
         
@@ -72,7 +72,7 @@ public class AustriaSpatialRule extends AbstractSpatialRule {
             return currentRoadAccess;
         }
         
-        if (transport != TransportationMode.MOTOR_VEHICLE) {
+        if (!transport.isMotorVehicle()) {
             return RoadAccess.YES;
         }
         
diff --git a/core/src/main/java/com/graphhopper/routing/util/spatialrules/countries/GermanySpatialRule.java b/core/src/main/java/com/graphhopper/routing/util/spatialrules/countries/GermanySpatialRule.java
index e1fb93fe8..22b5de25c 100644
--- a/core/src/main/java/com/graphhopper/routing/util/spatialrules/countries/GermanySpatialRule.java
+++ b/core/src/main/java/com/graphhopper/routing/util/spatialrules/countries/GermanySpatialRule.java
@@ -26,7 +26,7 @@ import com.graphhopper.routing.ev.MaxSpeed;
 import com.graphhopper.routing.ev.RoadAccess;
 import com.graphhopper.routing.ev.RoadClass;
 import com.graphhopper.routing.util.spatialrules.AbstractSpatialRule;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
+import com.graphhopper.routing.util.TransportationMode;
 
 /**
  * Defines the default rules for German roads
@@ -47,7 +47,7 @@ public class GermanySpatialRule extends AbstractSpatialRule {
      */
     @Override
     public double getMaxSpeed(RoadClass roadClass, TransportationMode transport, double currentMaxSpeed) {
-        if (!Double.isNaN(currentMaxSpeed) || transport != TransportationMode.MOTOR_VEHICLE) {
+        if (!Double.isNaN(currentMaxSpeed) || !transport.isMotorVehicle()) {
             return currentMaxSpeed;
         }
         
@@ -79,7 +79,7 @@ public class GermanySpatialRule extends AbstractSpatialRule {
             return currentRoadAccess;
         }
         
-        if (transport != TransportationMode.MOTOR_VEHICLE) {
+        if (!transport.isMotorVehicle()) {
             return RoadAccess.YES;
         }
 
diff --git a/web-bundle/src/main/java/com/graphhopper/http/GraphHopperBundle.java b/web-bundle/src/main/java/com/graphhopper/http/GraphHopperBundle.java
index cf0d07c8d..9a3449084 100644
--- a/web-bundle/src/main/java/com/graphhopper/http/GraphHopperBundle.java
+++ b/web-bundle/src/main/java/com/graphhopper/http/GraphHopperBundle.java
@@ -277,5 +277,7 @@ public class GraphHopperBundle implements ConfiguredBundle<GraphHopperBundleConf
         environment.jersey().register(I18NResource.class);
         environment.jersey().register(InfoResource.class);
         environment.healthChecks().register("graphhopper", new GraphHopperHealthCheck(graphHopper));
+        environment.jersey().register(environment.healthChecks());
+        environment.jersey().register(HealthcheckResource.class);
     }
 }
diff --git a/web-bundle/src/main/java/com/graphhopper/http/health/GraphHopperHealthCheck.java b/web-bundle/src/main/java/com/graphhopper/http/health/GraphHopperHealthCheck.java
index b2a62cc32..63c3db0bd 100644
--- a/web-bundle/src/main/java/com/graphhopper/http/health/GraphHopperHealthCheck.java
+++ b/web-bundle/src/main/java/com/graphhopper/http/health/GraphHopperHealthCheck.java
@@ -20,7 +20,6 @@ package com.graphhopper.http.health;
 
 import com.codahale.metrics.health.HealthCheck;
 import com.graphhopper.GraphHopper;
-import com.graphhopper.storage.GraphHopperStorage;
 
 public class GraphHopperHealthCheck extends HealthCheck {
 
@@ -32,11 +31,12 @@ public class GraphHopperHealthCheck extends HealthCheck {
 
     @Override
     protected Result check() {
-        boolean valid = graphHopper.getGraphHopperStorage().getBounds().isValid();
-        if (valid) {
-            return Result.healthy();
-        } else {
+        if (!graphHopper.getGraphHopperStorage().getBounds().isValid()) {
             return Result.unhealthy("GraphHopperStorage has invalid bounds.");
         }
+        if (!graphHopper.getFullyLoaded()) {
+            return Result.unhealthy("GraphHopper is not fully loaded.");
+        }
+        return Result.healthy();
     }
 }
diff --git a/web-bundle/src/main/java/com/graphhopper/resources/HealthcheckResource.java b/web-bundle/src/main/java/com/graphhopper/resources/HealthcheckResource.java
new file mode 100644
index 000000000..8f4792312
--- /dev/null
+++ b/web-bundle/src/main/java/com/graphhopper/resources/HealthcheckResource.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to GraphHopper GmbH under one or more contributor
+ *  license agreements. See the NOTICE file distributed with this work for
+ *  additional information regarding copyright ownership.
+ *
+ *  GraphHopper GmbH licenses this file to you 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.
+ */
+package com.graphhopper.resources;
+
+import com.codahale.metrics.health.HealthCheck;
+import com.codahale.metrics.health.HealthCheckRegistry;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import java.util.SortedMap;
+
+/**
+ * This is a public facing health check that runs all registered health checks.
+ * Instead of providing details like the admin health check, this only returns OK/200 or UNHEALTHY/500.
+ *
+ * @author Robin Boldt
+ */
+@Path("health")
+public class HealthcheckResource {
+
+    private HealthCheckRegistry registry;
+
+    @Inject
+    public HealthcheckResource(HealthCheckRegistry registry) {
+        this.registry = registry;
+    }
+
+    @GET
+    public Response doGet() {
+        SortedMap<String, HealthCheck.Result> results = registry.runHealthChecks();
+        for (HealthCheck.Result result : results.values()) {
+            if (!result.isHealthy()) {
+                return Response.status(500).entity("UNHEALTHY").build();
+            }
+        }
+        return Response.ok("OK").build();
+    }
+}


Test patch:
diff --git a/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java b/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java
index 07d49c3da..6d2e8a3dd 100644
--- a/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java
+++ b/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java
@@ -20,7 +20,7 @@ package com.graphhopper.routing.weighting;
 import com.graphhopper.routing.ev.EnumEncodedValue;
 import com.graphhopper.routing.ev.RoadAccess;
 import com.graphhopper.routing.util.FlagEncoder;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
+import com.graphhopper.routing.util.TransportationMode;
 import com.graphhopper.util.EdgeIteratorState;
 import com.graphhopper.util.PMap;
 import com.graphhopper.util.Parameters.Routing;
@@ -69,9 +69,9 @@ public class FastestWeighting extends AbstractWeighting {
             throw new IllegalArgumentException("road_access is not available but expected for FastestWeighting");
 
         // ensure that we do not need to change getMinWeight, i.e. road_access_factor >= 1
-        double defaultDestinationFactor = encoder.getTransportationMode() == TransportationMode.MOTOR_VEHICLE ? 10 : 1;
+        double defaultDestinationFactor = encoder.getTransportationMode().isMotorVehicle()? 10 : 1;
         destinationPenalty = checkBounds("road_access_destination_factor", map.getDouble("road_access_destination_factor", defaultDestinationFactor), 1, 10);
-        double defaultPrivateFactor = encoder.getTransportationMode() == TransportationMode.MOTOR_VEHICLE ? 10 : 1.2;
+        double defaultPrivateFactor = encoder.getTransportationMode().isMotorVehicle()? 10 : 1.2;
         privatePenalty = checkBounds("road_access_private_factor", map.getDouble("road_access_private_factor", defaultPrivateFactor), 1, 10);
         roadAccessEnc = destinationPenalty > 1 || privatePenalty > 1 ? encoder.getEnumEncodedValue(RoadAccess.KEY, RoadAccess.class) : null;
     }
diff --git a/core/src/test/java/com/graphhopper/routing/util/EncodingManagerTest.java b/core/src/test/java/com/graphhopper/routing/util/EncodingManagerTest.java
index ec4e342b1..242318449 100644
--- a/core/src/test/java/com/graphhopper/routing/util/EncodingManagerTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/EncodingManagerTest.java
@@ -23,7 +23,6 @@ import com.graphhopper.routing.ev.BooleanEncodedValue;
 import com.graphhopper.routing.ev.EnumEncodedValue;
 import com.graphhopper.routing.ev.Roundabout;
 import com.graphhopper.routing.ev.RouteNetwork;
-import com.graphhopper.routing.util.spatialrules.TransportationMode;
 import com.graphhopper.storage.IntsRef;
 import org.junit.Test;
 
@@ -85,7 +84,7 @@ public class EncodingManagerTest {
     public void testToDetailsStringIncludesEncoderVersionNumber() {
         FlagEncoder encoder = new AbstractFlagEncoder(1, 2.0, 0) {
             public TransportationMode getTransportationMode() {
-                return TransportationMode.BICYCLE;
+                return TransportationMode.BIKE;
             }
 
             @Override
diff --git a/core/src/test/java/com/graphhopper/routing/util/parsers/OSMTurnRelationParserTest.java b/core/src/test/java/com/graphhopper/routing/util/parsers/OSMTurnRelationParserTest.java
index 0b142faeb..ddb8e4a91 100644
--- a/core/src/test/java/com/graphhopper/routing/util/parsers/OSMTurnRelationParserTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/parsers/OSMTurnRelationParserTest.java
@@ -5,6 +5,7 @@ import com.graphhopper.routing.EdgeBasedRoutingAlgorithmTest;
 import com.graphhopper.routing.ev.DecimalEncodedValue;
 import com.graphhopper.routing.util.CarFlagEncoder;
 import com.graphhopper.routing.util.EncodingManager;
+import com.graphhopper.routing.util.TransportationMode;
 import com.graphhopper.storage.GraphBuilder;
 import com.graphhopper.storage.GraphHopperStorage;
 import com.graphhopper.storage.TurnCostStorage;
@@ -29,7 +30,7 @@ public class OSMTurnRelationParserTest {
         internalToOSMEdge.put(3, 3L);
         internalToOSMEdge.put(4, 4L);
 
-        OSMTurnRelationParser parser = new OSMTurnRelationParser(encoder.toString(), 1);
+        OSMTurnRelationParser parser = new OSMTurnRelationParser(encoder.toString(), 1, OSMRoadAccessParser.toOSMRestrictions(TransportationMode.CAR));
         GraphHopperStorage ghStorage = new GraphBuilder(new EncodingManager.Builder().add(encoder).addTurnCostParser(parser).build()).create();
         EdgeBasedRoutingAlgorithmTest.initGraph(ghStorage);
         TurnCostParser.ExternalInternalMap map = new TurnCostParser.ExternalInternalMap() {
@@ -63,12 +64,4 @@ public class OSMTurnRelationParserTest {
         parser.addRelationToTCStorage(instance, map, ghStorage);
         assertTrue(Double.isInfinite(tcs.get(tce, 4, 3, 3)));
     }
-
-    @Test
-    public void unknownShouldBehaveLikeMotorVehicle() {
-        OSMTurnRelationParser parser = new OSMTurnRelationParser("fatcarsomething", 1);
-        OSMTurnRelation turnRelation = new OSMTurnRelation(4, 3, 3, OSMTurnRelation.Type.NOT);
-        turnRelation.setVehicleTypeRestricted("space");
-        parser.handleTurnRelationTags(turnRelation, null, null);
-    }
 }
\ No newline at end of file
diff --git a/core/src/test/java/com/graphhopper/routing/util/spatialrules/SpatialRuleLookupBuilderTest.java b/core/src/test/java/com/graphhopper/routing/util/spatialrules/SpatialRuleLookupBuilderTest.java
index 3f600972d..049e9f594 100644
--- a/core/src/test/java/com/graphhopper/routing/util/spatialrules/SpatialRuleLookupBuilderTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/spatialrules/SpatialRuleLookupBuilderTest.java
@@ -23,6 +23,7 @@ import com.graphhopper.reader.ReaderWay;
 import com.graphhopper.routing.ev.*;
 import com.graphhopper.routing.util.CarFlagEncoder;
 import com.graphhopper.routing.util.EncodingManager;
+import com.graphhopper.routing.util.TransportationMode;
 import com.graphhopper.routing.util.parsers.SpatialRuleParser;
 import com.graphhopper.routing.util.spatialrules.countries.GermanySpatialRule;
 import com.graphhopper.storage.Graph;
diff --git a/core/src/test/java/com/graphhopper/routing/util/spatialrules/SpatialRuleLookupJTSTest.java b/core/src/test/java/com/graphhopper/routing/util/spatialrules/SpatialRuleLookupJTSTest.java
index 21213f4aa..35fb8941c 100644
--- a/core/src/test/java/com/graphhopper/routing/util/spatialrules/SpatialRuleLookupJTSTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/spatialrules/SpatialRuleLookupJTSTest.java
@@ -2,6 +2,7 @@ package com.graphhopper.routing.util.spatialrules;
 
 import com.graphhopper.routing.ev.RoadAccess;
 import com.graphhopper.routing.ev.RoadClass;
+import com.graphhopper.routing.util.TransportationMode;
 import org.junit.Test;
 import org.locationtech.jts.geom.*;
 
diff --git a/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java b/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
index c2df569d8..c94ebf94f 100644
--- a/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
+++ b/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
@@ -709,6 +709,11 @@ public class OSMReaderTest {
     public void testTurnFlagCombination() {
         CarFlagEncoder car = new CarFlagEncoder(5, 5, 24);
         CarFlagEncoder truck = new CarFlagEncoder(5, 5, 24) {
+            @Override
+            public TransportationMode getTransportationMode() {
+                return TransportationMode.HGV;
+            }
+
             @Override
             public String toString() {
                 return "truck";