From 17a625a21597558647346fb53b9af71ace3cce8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Thu, 19 Dec 2024 16:19:01 +0100 Subject: [PATCH 1/9] Add new caches for system, vehicle type and pricing plan to prepare for denormalization --- .../entur/lamassu/cache/PricingPlanCache.java | 23 ++++++++++++ .../org/entur/lamassu/cache/SystemCache.java | 23 ++++++++++++ .../entur/lamassu/cache/VehicleTypeCache.java | 23 ++++++++++++ .../cache/impl/PricingPlanCacheImpl.java | 35 +++++++++++++++++++ .../lamassu/cache/impl/SystemCacheImpl.java | 33 +++++++++++++++++ .../cache/impl/VehicleTypeCacheImpl.java | 35 +++++++++++++++++++ .../config/cache/RedissonCacheConfig.java | 25 +++++++++++++ 7 files changed, 197 insertions(+) create mode 100644 src/main/java/org/entur/lamassu/cache/PricingPlanCache.java create mode 100644 src/main/java/org/entur/lamassu/cache/SystemCache.java create mode 100644 src/main/java/org/entur/lamassu/cache/VehicleTypeCache.java create mode 100644 src/main/java/org/entur/lamassu/cache/impl/PricingPlanCacheImpl.java create mode 100644 src/main/java/org/entur/lamassu/cache/impl/SystemCacheImpl.java create mode 100644 src/main/java/org/entur/lamassu/cache/impl/VehicleTypeCacheImpl.java diff --git a/src/main/java/org/entur/lamassu/cache/PricingPlanCache.java b/src/main/java/org/entur/lamassu/cache/PricingPlanCache.java new file mode 100644 index 00000000..136bf2e1 --- /dev/null +++ b/src/main/java/org/entur/lamassu/cache/PricingPlanCache.java @@ -0,0 +1,23 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.cache; + +import org.entur.lamassu.model.entities.PricingPlan; + +public interface PricingPlanCache extends EntityCache {} diff --git a/src/main/java/org/entur/lamassu/cache/SystemCache.java b/src/main/java/org/entur/lamassu/cache/SystemCache.java new file mode 100644 index 00000000..5ae964c1 --- /dev/null +++ b/src/main/java/org/entur/lamassu/cache/SystemCache.java @@ -0,0 +1,23 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.cache; + +import org.entur.lamassu.model.entities.System; + +public interface SystemCache extends EntityCache {} diff --git a/src/main/java/org/entur/lamassu/cache/VehicleTypeCache.java b/src/main/java/org/entur/lamassu/cache/VehicleTypeCache.java new file mode 100644 index 00000000..6edfa7f6 --- /dev/null +++ b/src/main/java/org/entur/lamassu/cache/VehicleTypeCache.java @@ -0,0 +1,23 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.cache; + +import org.entur.lamassu.model.entities.VehicleType; + +public interface VehicleTypeCache extends EntityCache {} diff --git a/src/main/java/org/entur/lamassu/cache/impl/PricingPlanCacheImpl.java b/src/main/java/org/entur/lamassu/cache/impl/PricingPlanCacheImpl.java new file mode 100644 index 00000000..54b22cf1 --- /dev/null +++ b/src/main/java/org/entur/lamassu/cache/impl/PricingPlanCacheImpl.java @@ -0,0 +1,35 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.cache.impl; + +import org.entur.lamassu.cache.PricingPlanCache; +import org.entur.lamassu.model.entities.PricingPlan; +import org.redisson.api.RMapCache; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class PricingPlanCacheImpl + extends EntityCacheImpl + implements PricingPlanCache { + + public PricingPlanCacheImpl(@Autowired RMapCache cache) { + super(cache); + } +} diff --git a/src/main/java/org/entur/lamassu/cache/impl/SystemCacheImpl.java b/src/main/java/org/entur/lamassu/cache/impl/SystemCacheImpl.java new file mode 100644 index 00000000..350fe8d9 --- /dev/null +++ b/src/main/java/org/entur/lamassu/cache/impl/SystemCacheImpl.java @@ -0,0 +1,33 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.cache.impl; + +import org.entur.lamassu.cache.SystemCache; +import org.entur.lamassu.model.entities.System; +import org.redisson.api.RMapCache; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class SystemCacheImpl extends EntityCacheImpl implements SystemCache { + + public SystemCacheImpl(@Autowired RMapCache cache) { + super(cache); + } +} diff --git a/src/main/java/org/entur/lamassu/cache/impl/VehicleTypeCacheImpl.java b/src/main/java/org/entur/lamassu/cache/impl/VehicleTypeCacheImpl.java new file mode 100644 index 00000000..fd97a630 --- /dev/null +++ b/src/main/java/org/entur/lamassu/cache/impl/VehicleTypeCacheImpl.java @@ -0,0 +1,35 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.cache.impl; + +import org.entur.lamassu.cache.VehicleTypeCache; +import org.entur.lamassu.model.entities.VehicleType; +import org.redisson.api.RMapCache; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class VehicleTypeCacheImpl + extends EntityCacheImpl + implements VehicleTypeCache { + + protected VehicleTypeCacheImpl(@Autowired RMapCache cache) { + super(cache); + } +} diff --git a/src/main/java/org/entur/lamassu/config/cache/RedissonCacheConfig.java b/src/main/java/org/entur/lamassu/config/cache/RedissonCacheConfig.java index 999a38da..8782b86c 100644 --- a/src/main/java/org/entur/lamassu/config/cache/RedissonCacheConfig.java +++ b/src/main/java/org/entur/lamassu/config/cache/RedissonCacheConfig.java @@ -6,8 +6,11 @@ import org.entur.lamassu.cache.VehicleSpatialIndexId; import org.entur.lamassu.config.project.LamassuProjectInfoConfiguration; import org.entur.lamassu.model.entities.GeofencingZones; +import org.entur.lamassu.model.entities.PricingPlan; import org.entur.lamassu.model.entities.Station; +import org.entur.lamassu.model.entities.System; import org.entur.lamassu.model.entities.Vehicle; +import org.entur.lamassu.model.entities.VehicleType; import org.redisson.Redisson; import org.redisson.api.RBucket; import org.redisson.api.RGeo; @@ -30,6 +33,9 @@ public class RedissonCacheConfig { public static final String GBFS_FEED_CACHE_KEY = "gbfsFeedCache"; public static final String GBFS_V3_FEED_CACHE_KEY = "gbfsV3FeedCache"; + public static final String SYSTEM_CACHE_KEY = "systemCache"; + public static final String VEHICLE_TYPE_CACHE_KEY = "vehicleTypeCache"; + public static final String PRICING_PLAN_CACHE_KEY = "pricingPlanCache"; public static final String VEHICLE_CACHE_KEY = "vehicleCache"; public static final String STATION_CACHE_KEY = "stationCache"; public static final String GEOFENCING_ZONES_CACHE_KEY = "geofencingZonesCache"; @@ -114,6 +120,25 @@ RMapCache v3FeedCache(RedissonClient redissonClient) { ); } + @Bean + public RMapCache systemCache(RedissonClient redissonClient) { + return redissonClient.getMapCache(SYSTEM_CACHE_KEY + "_" + serializationVersion); + } + + @Bean + public RMapCache vehicleTypeCache(RedissonClient redissonClient) { + return redissonClient.getMapCache( + VEHICLE_TYPE_CACHE_KEY + "_" + serializationVersion + ); + } + + @Bean + public RMapCache pricingPlanCache(RedissonClient redissonClient) { + return redissonClient.getMapCache( + PRICING_PLAN_CACHE_KEY + "_" + serializationVersion + ); + } + @Bean public RMapCache vehicleCache(RedissonClient redissonClient) { return redissonClient.getMapCache(VEHICLE_CACHE_KEY + "_" + serializationVersion); From b617a270ad95635d50954a8a0c71840664745bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Fri, 20 Dec 2024 10:10:36 +0100 Subject: [PATCH 2/9] Add updaters --- .../entityupdater/EntityCachesUpdater.java | 86 +++++++++++++++---- .../entityupdater/PricingPlansUpdater.java | 72 ++++++++++++++++ .../leader/entityupdater/SystemUpdater.java | 59 +++++++++++++ .../entityupdater/VehicleTypesUpdater.java | 70 +++++++++++++++ .../entitymapper/VehicleTypeMapper.java | 85 ++++++++++++++++++ .../lamassu/model/entities/VehicleType.java | 18 ++++ 6 files changed, 374 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/entur/lamassu/leader/entityupdater/PricingPlansUpdater.java create mode 100644 src/main/java/org/entur/lamassu/leader/entityupdater/SystemUpdater.java create mode 100644 src/main/java/org/entur/lamassu/leader/entityupdater/VehicleTypesUpdater.java diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java index 77dbf007..e23deb97 100644 --- a/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java @@ -27,16 +27,25 @@ @Component public class EntityCachesUpdater { + private final SystemUpdater systemUpdater; + private final VehicleTypesUpdater vehicleTypesUpdater; + private final PricingPlansUpdater pricingPlansUpdater; private final VehiclesUpdater vehiclesUpdater; private final StationsUpdater stationsUpdater; private final GeofencingZonesUpdater geofencingZonesUpdater; @Autowired public EntityCachesUpdater( + SystemUpdater systemUpdater, + VehicleTypesUpdater vehicleTypesUpdater, + PricingPlansUpdater pricingPlansUpdater, VehiclesUpdater vehiclesUpdater, StationsUpdater stationsUpdater, GeofencingZonesUpdater geofencingZonesUpdater ) { + this.systemUpdater = systemUpdater; + this.vehicleTypesUpdater = vehicleTypesUpdater; + this.pricingPlansUpdater = pricingPlansUpdater; this.vehiclesUpdater = vehiclesUpdater; this.stationsUpdater = stationsUpdater; this.geofencingZonesUpdater = geofencingZonesUpdater; @@ -47,6 +56,18 @@ public void updateEntityCaches( GbfsV3Delivery delivery, GbfsV3Delivery oldDelivery ) { + if (canUpdateSystem(delivery, feedProvider)) { + systemUpdater.update(delivery.systemInformation(), feedProvider); + } + + if (canUpdateVehicleTypes(delivery, feedProvider)) { + vehicleTypesUpdater.update(delivery.vehicleTypes(), feedProvider); + } + + if (canUpdatePricingPlans(delivery, feedProvider)) { + pricingPlansUpdater.update(delivery.systemPricingPlans(), feedProvider); + } + if (canUpdateVehicles(delivery, feedProvider)) { vehiclesUpdater.addOrUpdateVehicles(feedProvider, delivery, oldDelivery); } @@ -55,13 +76,7 @@ public void updateEntityCaches( stationsUpdater.addOrUpdateStations(feedProvider, delivery, oldDelivery); } - if ( - delivery.geofencingZones() != null && - ( - feedProvider.getExcludeFeeds() == null || - !feedProvider.getExcludeFeeds().contains(GBFSFeedName.GeofencingZones) - ) - ) { + if (canUpdateGeofencingZones(delivery, feedProvider)) { geofencingZonesUpdater.addOrUpdateGeofencingZones( feedProvider, delivery.geofencingZones() @@ -69,11 +84,46 @@ public void updateEntityCaches( } } + private boolean canUpdateSystem(GbfsV3Delivery delivery, FeedProvider feedProvider) { + if (exclude(feedProvider, GBFSFeedName.SystemInformation)) { + return false; + } + return delivery.systemInformation() != null; + } + + private boolean canUpdateVehicleTypes( + GbfsV3Delivery delivery, + FeedProvider feedProvider + ) { + if (exclude(feedProvider, GBFSFeedName.VehicleTypes)) { + return false; + } + return delivery.vehicleTypes() != null; + } + + private boolean canUpdatePricingPlans( + GbfsV3Delivery delivery, + FeedProvider feedProvider + ) { + if (exclude(feedProvider, GBFSFeedName.SystemPricingPlans)) { + return false; + } + return delivery.systemPricingPlans() != null; + } + + private boolean canUpdateGeofencingZones( + GbfsV3Delivery delivery, + FeedProvider feedProvider + ) { + if (exclude(feedProvider, GBFSFeedName.GeofencingZones)) { + return false; + } + + return delivery.geofencingZones() != null; + } + private boolean canUpdateVehicles(GbfsV3Delivery delivery, FeedProvider feedProvider) { - if ( - feedProvider.getExcludeFeeds() != null && - feedProvider.getExcludeFeeds().contains(GBFSFeedName.FreeBikeStatus) - ) { + if (exclude(feedProvider, GBFSFeedName.FreeBikeStatus)) { return false; } @@ -91,11 +141,8 @@ private boolean canUpdateVehicles(GbfsV3Delivery delivery, FeedProvider feedProv private boolean canUpdateStations(GbfsV3Delivery delivery, FeedProvider feedProvider) { if ( - feedProvider.getExcludeFeeds() != null && - ( - feedProvider.getExcludeFeeds().contains(GBFSFeedName.StationInformation) || - feedProvider.getExcludeFeeds().contains(GBFSFeedName.StationStatus) - ) + exclude(feedProvider, GBFSFeedName.StationInformation) || + exclude(feedProvider, GBFSFeedName.StationStatus) ) { return false; } @@ -113,4 +160,11 @@ private boolean canUpdateStations(GbfsV3Delivery delivery, FeedProvider feedProv delivery.systemPricingPlans().getData() != null ); } + + private boolean exclude(FeedProvider feedProvider, GBFSFeedName feedName) { + return ( + feedProvider.getExcludeFeeds() != null && + feedProvider.getExcludeFeeds().contains(feedName) + ); + } } diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/PricingPlansUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/PricingPlansUpdater.java new file mode 100644 index 00000000..a43df9c3 --- /dev/null +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/PricingPlansUpdater.java @@ -0,0 +1,72 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.leader.entityupdater; + +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.entur.lamassu.cache.PricingPlanCache; +import org.entur.lamassu.mapper.entitymapper.PricingPlanMapper; +import org.entur.lamassu.model.entities.PricingPlan; +import org.entur.lamassu.model.entities.VehicleType; +import org.entur.lamassu.model.provider.FeedProvider; +import org.entur.lamassu.util.CacheUtil; +import org.mobilitydata.gbfs.v3_0.system_pricing_plans.GBFSSystemPricingPlans; +import org.springframework.stereotype.Component; + +@Component +public class PricingPlansUpdater { + + private final PricingPlanCache pricingPlanCache; + private final PricingPlanMapper pricingPlanMapper; + + public PricingPlansUpdater( + PricingPlanCache pricingPlanCache, + PricingPlanMapper pricingPlanMapper + ) { + this.pricingPlanCache = pricingPlanCache; + this.pricingPlanMapper = pricingPlanMapper; + } + + public void update( + GBFSSystemPricingPlans gbfsSystemPricingPlans, + FeedProvider feedProvider + ) { + var mapped = gbfsSystemPricingPlans + .getData() + .getPlans() + .stream() + .map(pricingPlanMapper::mapPricingPlan) + .collect(Collectors.toMap(PricingPlan::getId, pricingPlan -> pricingPlan)); + + var lastUpdated = gbfsSystemPricingPlans.getLastUpdated(); + var ttl = gbfsSystemPricingPlans.getTtl(); + + pricingPlanCache.updateAll( + mapped, + CacheUtil.getTtl( + (int) Instant.now().getEpochSecond(), + (int) (lastUpdated.getTime() / 100), + ttl, + 86400 + ), + TimeUnit.SECONDS + ); + } +} diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/SystemUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/SystemUpdater.java new file mode 100644 index 00000000..78450ae8 --- /dev/null +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/SystemUpdater.java @@ -0,0 +1,59 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.leader.entityupdater; + +import java.time.Instant; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.entur.lamassu.cache.SystemCache; +import org.entur.lamassu.mapper.entitymapper.SystemMapper; +import org.entur.lamassu.model.provider.FeedProvider; +import org.entur.lamassu.util.CacheUtil; +import org.mobilitydata.gbfs.v3_0.system_information.GBFSSystemInformation; +import org.springframework.stereotype.Component; + +@Component +public class SystemUpdater { + + private final SystemCache systemCache; + private final SystemMapper systemMapper; + + public SystemUpdater(SystemCache systemCache, SystemMapper systemMapper) { + this.systemCache = systemCache; + this.systemMapper = systemMapper; + } + + public void update(GBFSSystemInformation systemInformation, FeedProvider feedProvider) { + var mapped = systemMapper.mapSystem(systemInformation.getData(), feedProvider); + + var lastUpdated = systemInformation.getLastUpdated(); + var ttl = systemInformation.getTtl(); + + systemCache.updateAll( + Map.of(mapped.getId(), mapped), + CacheUtil.getTtl( + (int) Instant.now().getEpochSecond(), + (int) (lastUpdated.getTime() / 100), + ttl, + 86400 + ), + TimeUnit.SECONDS + ); + } +} diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/VehicleTypesUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/VehicleTypesUpdater.java new file mode 100644 index 00000000..8f53bed1 --- /dev/null +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/VehicleTypesUpdater.java @@ -0,0 +1,70 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.leader.entityupdater; + +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.entur.lamassu.cache.VehicleTypeCache; +import org.entur.lamassu.mapper.entitymapper.VehicleTypeMapper; +import org.entur.lamassu.model.entities.VehicleType; +import org.entur.lamassu.model.provider.FeedProvider; +import org.entur.lamassu.util.CacheUtil; +import org.mobilitydata.gbfs.v3_0.vehicle_types.GBFSVehicleTypes; +import org.springframework.stereotype.Component; + +@Component +public class VehicleTypesUpdater { + + private final VehicleTypeCache vehicleTypeCache; + private final VehicleTypeMapper vehicleTypeMapper; + + public VehicleTypesUpdater( + VehicleTypeCache vehicleTypeCache, + VehicleTypeMapper vehicleTypeMapper + ) { + this.vehicleTypeCache = vehicleTypeCache; + this.vehicleTypeMapper = vehicleTypeMapper; + } + + public void update(GBFSVehicleTypes gbfsVehicleTypes, FeedProvider feedProvider) { + var mapped = gbfsVehicleTypes + .getData() + .getVehicleTypes() + .stream() + .map(vehicleType -> + vehicleTypeMapper.mapVehicleType(vehicleType, feedProvider.getLanguage()) + ) + .collect(Collectors.toMap(VehicleType::getId, vehicleType -> vehicleType)); + + var lastUpdated = gbfsVehicleTypes.getLastUpdated(); + var ttl = gbfsVehicleTypes.getTtl(); + + vehicleTypeCache.updateAll( + mapped, + CacheUtil.getTtl( + (int) Instant.now().getEpochSecond(), + (int) (lastUpdated.getTime() / 100), + ttl, + 86400 + ), + TimeUnit.SECONDS + ); + } +} diff --git a/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleTypeMapper.java b/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleTypeMapper.java index 9f1ae387..be03e38c 100644 --- a/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleTypeMapper.java +++ b/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleTypeMapper.java @@ -48,6 +48,91 @@ public VehicleTypeMapper(TranslationMapper translationMapper) { this.translationMapper = translationMapper; } + public VehicleType mapVehicleType(GBFSVehicleType vehicleType, String language) { + var mapped = new VehicleType(); + mapped.setId(vehicleType.getVehicleTypeId()); + mapped.setFormFactor(FormFactor.valueOf(vehicleType.getFormFactor().name())); + mapped.setRiderCapacity(vehicleType.getRiderCapacity()); + mapped.setCargoVolumeCapacity(vehicleType.getCargoVolumeCapacity()); + mapped.setCargoLoadCapacity(vehicleType.getCargoLoadCapacity()); + mapped.setPropulsionType( + PropulsionType.valueOf(vehicleType.getPropulsionType().name()) + ); + mapped.setEcoLabel(mapEcoLabels(vehicleType.getEcoLabels())); + mapped.setEcoLabels(mapEcoLabels(vehicleType.getEcoLabels())); + mapped.setMaxRangeMeters(vehicleType.getMaxRangeMeters()); + mapped.setName( + translationMapper.mapTranslatedString( + Optional + .ofNullable(vehicleType.getName()) + .orElse(Collections.emptyList()) + .stream() + .map(name -> + translationMapper.mapTranslation(name.getLanguage(), name.getText()) + ) + .toList() + ) + ); + mapped.setDescription( + translationMapper.mapTranslatedString( + Optional + .ofNullable(vehicleType.getDescription()) + .orElse(Collections.emptyList()) + .stream() + .map(description -> + translationMapper.mapTranslation( + description.getLanguage(), + description.getText() + ) + ) + .toList() + ) + ); + mapped.setVehicleAccessories( + mapVehicleAccessories(vehicleType.getVehicleAccessories()) + ); + mapped.setgCO2km(vehicleType.getgCO2Km() != null ? vehicleType.getgCO2Km() : null); + mapped.setVehicleImage(vehicleType.getVehicleImage()); + mapped.setMake( + Optional + .ofNullable(vehicleType.getMake()) + .orElse(Collections.emptyList()) + .stream() + .filter(make -> make.getLanguage().equals(language)) + .map(GBFSMake::getText) + .findFirst() + .orElse(null) + ); + mapped.setModel( + Optional + .ofNullable(vehicleType.getModel()) + .orElse(Collections.emptyList()) + .stream() + .filter(model -> model.getLanguage().equals(language)) + .map(GBFSModel::getText) + .findFirst() + .orElse(null) + ); + mapped.setColor(vehicleType.getColor()); + mapped.setWheelCount( + vehicleType.getWheelCount() != null ? vehicleType.getWheelCount() : null + ); + mapped.setMaxPermittedSpeed( + vehicleType.getMaxPermittedSpeed() != null + ? vehicleType.getMaxPermittedSpeed() + : null + ); + mapped.setRatedPower( + vehicleType.getRatedPower() != null ? vehicleType.getRatedPower() : null + ); + mapped.setDefaultReserveTime(vehicleType.getDefaultReserveTime()); + mapped.setReturnConstraint(mapReturnConstraint(vehicleType.getReturnConstraint())); + mapped.setVehicleAssets(mapVehicleAssets(vehicleType.getVehicleAssets())); + mapped.setDefaultPricingPlanId(vehicleType.getDefaultPricingPlanId()); + mapped.setPricingPlanIds(vehicleType.getPricingPlanIds()); + return mapped; + } + public VehicleType mapVehicleType( GBFSVehicleType vehicleType, List pricingPlans, diff --git a/src/main/java/org/entur/lamassu/model/entities/VehicleType.java b/src/main/java/org/entur/lamassu/model/entities/VehicleType.java index 1bbb2906..e38ac6f4 100644 --- a/src/main/java/org/entur/lamassu/model/entities/VehicleType.java +++ b/src/main/java/org/entur/lamassu/model/entities/VehicleType.java @@ -29,6 +29,8 @@ public class VehicleType implements Entity { private VehicleAssets vehicleAssets; private PricingPlan defaultPricingPlan; private List pricingPlans; + private String defaultPricingPlanId; + private List pricingPlanIds; @Override public String getId() { @@ -231,6 +233,22 @@ public void setPricingPlans(List pricingPlans) { this.pricingPlans = pricingPlans; } + public String getDefaultPricingPlanId() { + return defaultPricingPlanId; + } + + public void setDefaultPricingPlanId(String defaultPricingPlanId) { + this.defaultPricingPlanId = defaultPricingPlanId; + } + + public List getPricingPlanIds() { + return pricingPlanIds; + } + + public void setPricingPlanIds(List pricingPlanIds) { + this.pricingPlanIds = pricingPlanIds; + } + @Override public String toString() { return ( From 2891e128804eac27d92f629f62fce01b2a4574b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Fri, 20 Dec 2024 11:40:54 +0100 Subject: [PATCH 3/9] Add cache for region entity --- .../org/entur/lamassu/cache/RegionCache.java | 23 ++++++++++++++ .../lamassu/cache/impl/RegionCacheImpl.java | 31 +++++++++++++++++++ .../config/cache/RedissonCacheConfig.java | 7 +++++ 3 files changed, 61 insertions(+) create mode 100644 src/main/java/org/entur/lamassu/cache/RegionCache.java create mode 100644 src/main/java/org/entur/lamassu/cache/impl/RegionCacheImpl.java diff --git a/src/main/java/org/entur/lamassu/cache/RegionCache.java b/src/main/java/org/entur/lamassu/cache/RegionCache.java new file mode 100644 index 00000000..53f97519 --- /dev/null +++ b/src/main/java/org/entur/lamassu/cache/RegionCache.java @@ -0,0 +1,23 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.cache; + +import org.entur.lamassu.model.entities.Region; + +public interface RegionCache extends EntityCache {} diff --git a/src/main/java/org/entur/lamassu/cache/impl/RegionCacheImpl.java b/src/main/java/org/entur/lamassu/cache/impl/RegionCacheImpl.java new file mode 100644 index 00000000..ce233e8c --- /dev/null +++ b/src/main/java/org/entur/lamassu/cache/impl/RegionCacheImpl.java @@ -0,0 +1,31 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.cache.impl; + +import org.entur.lamassu.cache.RegionCache; +import org.entur.lamassu.model.entities.Region; +import org.redisson.api.RMapCache; +import org.springframework.stereotype.Component; + +@Component +public class RegionCacheImpl extends EntityCacheImpl implements RegionCache { + public RegionCacheImpl(RMapCache cache) { + super(cache); + } +} diff --git a/src/main/java/org/entur/lamassu/config/cache/RedissonCacheConfig.java b/src/main/java/org/entur/lamassu/config/cache/RedissonCacheConfig.java index 8782b86c..109b81da 100644 --- a/src/main/java/org/entur/lamassu/config/cache/RedissonCacheConfig.java +++ b/src/main/java/org/entur/lamassu/config/cache/RedissonCacheConfig.java @@ -7,6 +7,7 @@ import org.entur.lamassu.config.project.LamassuProjectInfoConfiguration; import org.entur.lamassu.model.entities.GeofencingZones; import org.entur.lamassu.model.entities.PricingPlan; +import org.entur.lamassu.model.entities.Region; import org.entur.lamassu.model.entities.Station; import org.entur.lamassu.model.entities.System; import org.entur.lamassu.model.entities.Vehicle; @@ -38,6 +39,7 @@ public class RedissonCacheConfig { public static final String PRICING_PLAN_CACHE_KEY = "pricingPlanCache"; public static final String VEHICLE_CACHE_KEY = "vehicleCache"; public static final String STATION_CACHE_KEY = "stationCache"; + public static final String REGION_CACHE_KEY = "regionCache"; public static final String GEOFENCING_ZONES_CACHE_KEY = "geofencingZonesCache"; public static final String VEHICLE_SPATIAL_INDEX_KEY = "vehicleSpatialIndex"; public static final String STATION_SPATIAL_INDEX_KEY = "stationSpatialIndex"; @@ -149,6 +151,11 @@ public RMapCache stationCache(RedissonClient redissonClient) { return redissonClient.getMapCache(STATION_CACHE_KEY + "_" + serializationVersion); } + @Bean + public RMapCache regionCache(RedissonClient redissonClient) { + return redissonClient.getMapCache(REGION_CACHE_KEY + "_" + serializationVersion); + } + @Bean public RMapCache geofencingZonesCache( RedissonClient redissonClient From 68210382785f10ed8761887642fa0d70884ef19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Fri, 20 Dec 2024 11:42:09 +0100 Subject: [PATCH 4/9] Add region updater --- .../entityupdater/EntityCachesUpdater.java | 17 ++++++ .../leader/entityupdater/RegionsUpdater.java | 61 +++++++++++++++++++ .../mapper/entitymapper/RegionMapper.java | 61 +++++++++++++++++++ .../entur/lamassu/model/entities/Region.java | 4 +- 4 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/entur/lamassu/leader/entityupdater/RegionsUpdater.java create mode 100644 src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java index e23deb97..92f06742 100644 --- a/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java @@ -30,6 +30,7 @@ public class EntityCachesUpdater { private final SystemUpdater systemUpdater; private final VehicleTypesUpdater vehicleTypesUpdater; private final PricingPlansUpdater pricingPlansUpdater; + private final RegionsUpdater regionsUpdater; private final VehiclesUpdater vehiclesUpdater; private final StationsUpdater stationsUpdater; private final GeofencingZonesUpdater geofencingZonesUpdater; @@ -39,6 +40,7 @@ public EntityCachesUpdater( SystemUpdater systemUpdater, VehicleTypesUpdater vehicleTypesUpdater, PricingPlansUpdater pricingPlansUpdater, + RegionsUpdater regionsUpdater, VehiclesUpdater vehiclesUpdater, StationsUpdater stationsUpdater, GeofencingZonesUpdater geofencingZonesUpdater @@ -46,6 +48,7 @@ public EntityCachesUpdater( this.systemUpdater = systemUpdater; this.vehicleTypesUpdater = vehicleTypesUpdater; this.pricingPlansUpdater = pricingPlansUpdater; + this.regionsUpdater = regionsUpdater; this.vehiclesUpdater = vehiclesUpdater; this.stationsUpdater = stationsUpdater; this.geofencingZonesUpdater = geofencingZonesUpdater; @@ -68,6 +71,10 @@ public void updateEntityCaches( pricingPlansUpdater.update(delivery.systemPricingPlans(), feedProvider); } + if (canUpdateRegions(delivery, feedProvider)) { + regionsUpdater.updateRegions(delivery.systemRegions(), feedProvider.getLanguage()); + } + if (canUpdateVehicles(delivery, feedProvider)) { vehiclesUpdater.addOrUpdateVehicles(feedProvider, delivery, oldDelivery); } @@ -111,6 +118,16 @@ private boolean canUpdatePricingPlans( return delivery.systemPricingPlans() != null; } + private boolean canUpdateRegions( + GbfsV3Delivery delivery, + FeedProvider feedProvider + ) { + if (exclude(feedProvider, GBFSFeedName.SystemRegions)) { + return false; + } + return delivery.systemRegions() != null; + } + private boolean canUpdateGeofencingZones( GbfsV3Delivery delivery, FeedProvider feedProvider diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/RegionsUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/RegionsUpdater.java new file mode 100644 index 00000000..9b9c5445 --- /dev/null +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/RegionsUpdater.java @@ -0,0 +1,61 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.leader.entityupdater; + +import org.entur.lamassu.cache.RegionCache; +import org.entur.lamassu.mapper.entitymapper.RegionMapper; +import org.entur.lamassu.model.entities.Region; +import org.entur.lamassu.util.CacheUtil; +import org.mobilitydata.gbfs.v3_0.system_regions.GBFSSystemRegions; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Component +public class RegionsUpdater { + private final RegionCache regionCache; + private final RegionMapper regionMapper; + + public RegionsUpdater(RegionCache regionCache, RegionMapper regionMapper) { + this.regionCache = regionCache; + this.regionMapper = regionMapper; + } + + public void updateRegions(GBFSSystemRegions systemRegions, String language) { + var mapped = systemRegions.getData().getRegions().stream().map(region -> regionMapper.mapRegion(region, language)) + .collect(Collectors.toMap(Region::getId, region -> region)); + + var lastUpdated = systemRegions.getLastUpdated(); + var ttl = systemRegions.getTtl(); + + regionCache.updateAll( + mapped, + CacheUtil.getTtl( + (int) Instant.now().getEpochSecond(), + (int) (lastUpdated.getTime() / 100), + ttl, + 86400 + ), + TimeUnit.SECONDS + ); + + } +} diff --git a/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java b/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java new file mode 100644 index 00000000..342ab1fc --- /dev/null +++ b/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java @@ -0,0 +1,61 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.mapper.entitymapper; + +import org.entur.lamassu.model.entities.Region; +import org.mobilitydata.gbfs.v3_0.system_regions.GBFSRegion; +import org.mobilitydata.gbfs.v3_0.system_regions.GBFSSystemRegions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class RegionMapper { + private static final Logger logger = LoggerFactory.getLogger(RegionMapper.class); + + private final TranslationMapper translationMapper; + + @Autowired + public RegionMapper(TranslationMapper translationMapper) { + this.translationMapper = translationMapper; + } + + public Region mapRegion(GBFSRegion sourceRegion, String language) { + + var region = new Region(); + region.setId(sourceRegion.getRegionId()); + region.setName( + translationMapper.mapSingleTranslation( + language, + sourceRegion + .getName() + .stream() + .filter(name -> name.getLanguage().equals(language)) + .map(org.mobilitydata.gbfs.v3_0.system_regions.GBFSName::getText) + .findFirst() + .orElse(null) + ) + ); + return region; + + } +} diff --git a/src/main/java/org/entur/lamassu/model/entities/Region.java b/src/main/java/org/entur/lamassu/model/entities/Region.java index 6988ad9e..10647c08 100644 --- a/src/main/java/org/entur/lamassu/model/entities/Region.java +++ b/src/main/java/org/entur/lamassu/model/entities/Region.java @@ -18,9 +18,7 @@ package org.entur.lamassu.model.entities; -import java.io.Serializable; - -public class Region implements Serializable { +public class Region implements Entity { private String id; private TranslatedString name; From d8c32dca468caf36411eb0f30800ec5ba984d7ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Fri, 20 Dec 2024 11:48:37 +0100 Subject: [PATCH 5/9] Formatting --- .../lamassu/cache/impl/RegionCacheImpl.java | 7 +- .../entityupdater/EntityCachesUpdater.java | 5 +- .../leader/entityupdater/RegionsUpdater.java | 65 ++++++++++--------- .../mapper/entitymapper/RegionMapper.java | 56 ++++++++-------- 4 files changed, 66 insertions(+), 67 deletions(-) diff --git a/src/main/java/org/entur/lamassu/cache/impl/RegionCacheImpl.java b/src/main/java/org/entur/lamassu/cache/impl/RegionCacheImpl.java index ce233e8c..58c414e6 100644 --- a/src/main/java/org/entur/lamassu/cache/impl/RegionCacheImpl.java +++ b/src/main/java/org/entur/lamassu/cache/impl/RegionCacheImpl.java @@ -25,7 +25,8 @@ @Component public class RegionCacheImpl extends EntityCacheImpl implements RegionCache { - public RegionCacheImpl(RMapCache cache) { - super(cache); - } + + public RegionCacheImpl(RMapCache cache) { + super(cache); + } } diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java index 92f06742..a0b7e21a 100644 --- a/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java @@ -118,10 +118,7 @@ private boolean canUpdatePricingPlans( return delivery.systemPricingPlans() != null; } - private boolean canUpdateRegions( - GbfsV3Delivery delivery, - FeedProvider feedProvider - ) { + private boolean canUpdateRegions(GbfsV3Delivery delivery, FeedProvider feedProvider) { if (exclude(feedProvider, GBFSFeedName.SystemRegions)) { return false; } diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/RegionsUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/RegionsUpdater.java index 9b9c5445..f2c51a45 100644 --- a/src/main/java/org/entur/lamassu/leader/entityupdater/RegionsUpdater.java +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/RegionsUpdater.java @@ -18,6 +18,9 @@ package org.entur.lamassu.leader.entityupdater; +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.entur.lamassu.cache.RegionCache; import org.entur.lamassu.mapper.entitymapper.RegionMapper; import org.entur.lamassu.model.entities.Region; @@ -25,37 +28,37 @@ import org.mobilitydata.gbfs.v3_0.system_regions.GBFSSystemRegions; import org.springframework.stereotype.Component; -import java.time.Instant; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - @Component public class RegionsUpdater { - private final RegionCache regionCache; - private final RegionMapper regionMapper; - - public RegionsUpdater(RegionCache regionCache, RegionMapper regionMapper) { - this.regionCache = regionCache; - this.regionMapper = regionMapper; - } - - public void updateRegions(GBFSSystemRegions systemRegions, String language) { - var mapped = systemRegions.getData().getRegions().stream().map(region -> regionMapper.mapRegion(region, language)) - .collect(Collectors.toMap(Region::getId, region -> region)); - - var lastUpdated = systemRegions.getLastUpdated(); - var ttl = systemRegions.getTtl(); - - regionCache.updateAll( - mapped, - CacheUtil.getTtl( - (int) Instant.now().getEpochSecond(), - (int) (lastUpdated.getTime() / 100), - ttl, - 86400 - ), - TimeUnit.SECONDS - ); - - } + + private final RegionCache regionCache; + private final RegionMapper regionMapper; + + public RegionsUpdater(RegionCache regionCache, RegionMapper regionMapper) { + this.regionCache = regionCache; + this.regionMapper = regionMapper; + } + + public void updateRegions(GBFSSystemRegions systemRegions, String language) { + var mapped = systemRegions + .getData() + .getRegions() + .stream() + .map(region -> regionMapper.mapRegion(region, language)) + .collect(Collectors.toMap(Region::getId, region -> region)); + + var lastUpdated = systemRegions.getLastUpdated(); + var ttl = systemRegions.getTtl(); + + regionCache.updateAll( + mapped, + CacheUtil.getTtl( + (int) Instant.now().getEpochSecond(), + (int) (lastUpdated.getTime() / 100), + ttl, + 86400 + ), + TimeUnit.SECONDS + ); + } } diff --git a/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java b/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java index 342ab1fc..694fb826 100644 --- a/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java +++ b/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java @@ -18,6 +18,7 @@ package org.entur.lamassu.mapper.entitymapper; +import java.util.Optional; import org.entur.lamassu.model.entities.Region; import org.mobilitydata.gbfs.v3_0.system_regions.GBFSRegion; import org.mobilitydata.gbfs.v3_0.system_regions.GBFSSystemRegions; @@ -26,36 +27,33 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.Optional; - @Component public class RegionMapper { - private static final Logger logger = LoggerFactory.getLogger(RegionMapper.class); - - private final TranslationMapper translationMapper; - - @Autowired - public RegionMapper(TranslationMapper translationMapper) { - this.translationMapper = translationMapper; - } - - public Region mapRegion(GBFSRegion sourceRegion, String language) { - - var region = new Region(); - region.setId(sourceRegion.getRegionId()); - region.setName( - translationMapper.mapSingleTranslation( - language, - sourceRegion - .getName() - .stream() - .filter(name -> name.getLanguage().equals(language)) - .map(org.mobilitydata.gbfs.v3_0.system_regions.GBFSName::getText) - .findFirst() - .orElse(null) - ) - ); - return region; - } + private static final Logger logger = LoggerFactory.getLogger(RegionMapper.class); + + private final TranslationMapper translationMapper; + + @Autowired + public RegionMapper(TranslationMapper translationMapper) { + this.translationMapper = translationMapper; + } + + public Region mapRegion(GBFSRegion sourceRegion, String language) { + var region = new Region(); + region.setId(sourceRegion.getRegionId()); + region.setName( + translationMapper.mapSingleTranslation( + language, + sourceRegion + .getName() + .stream() + .filter(name -> name.getLanguage().equals(language)) + .map(org.mobilitydata.gbfs.v3_0.system_regions.GBFSName::getText) + .findFirst() + .orElse(null) + ) + ); + return region; + } } From 614bd5d7c324a78b261dadc8aafa545b88d7e0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Fri, 20 Dec 2024 15:50:45 +0100 Subject: [PATCH 6/9] Move resolving of pricing plans, regions, vehicle types and system to graphql layer --- .../controller/StationGraphQLController.java | 80 ++++++- .../controller/VehicleGraphQLController.java | 33 ++- .../leader/entityupdater/StationsUpdater.java | 60 +---- .../leader/entityupdater/VehiclesUpdater.java | 99 +------- .../mapper/entitymapper/StationMapper.java | 220 +++--------------- .../mapper/entitymapper/VehicleMapper.java | 13 +- .../entur/lamassu/model/entities/Station.java | 18 ++ .../entur/lamassu/model/entities/Vehicle.java | 32 ++- .../entities/VehicleDocksAvailability.java | 9 + .../model/entities/VehicleDocksCapacity.java | 9 + .../entities/VehicleTypeAvailability.java | 9 + .../model/entities/VehicleTypeCapacity.java | 10 + .../model/entities/VehicleTypesCapacity.java | 9 + .../lamassu/service/SpatialIndexService.java | 83 +++++++ .../lamassu/service/GeoSearchServiceTest.java | 8 +- .../util/SpatialIndexIdFilterTest.java | 10 +- .../util/TestSpatialIndexBuilder.java} | 38 +-- src/test/resources/v3/vehicle_status.json | 3 +- 18 files changed, 375 insertions(+), 368 deletions(-) create mode 100644 src/main/java/org/entur/lamassu/service/SpatialIndexService.java rename src/{main/java/org/entur/lamassu/util/SpatialIndexIdUtil.java => test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java} (59%) diff --git a/src/main/java/org/entur/lamassu/graphql/controller/StationGraphQLController.java b/src/main/java/org/entur/lamassu/graphql/controller/StationGraphQLController.java index 0df5e380..59118fcc 100644 --- a/src/main/java/org/entur/lamassu/graphql/controller/StationGraphQLController.java +++ b/src/main/java/org/entur/lamassu/graphql/controller/StationGraphQLController.java @@ -1,15 +1,27 @@ package org.entur.lamassu.graphql.controller; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; +import org.entur.lamassu.cache.PricingPlanCache; import org.entur.lamassu.cache.StationCache; +import org.entur.lamassu.cache.SystemCache; +import org.entur.lamassu.cache.VehicleTypeCache; import org.entur.lamassu.model.entities.FormFactor; +import org.entur.lamassu.model.entities.PricingPlan; import org.entur.lamassu.model.entities.PropulsionType; import org.entur.lamassu.model.entities.Station; +import org.entur.lamassu.model.entities.System; +import org.entur.lamassu.model.entities.VehicleDocksAvailability; +import org.entur.lamassu.model.entities.VehicleType; +import org.entur.lamassu.model.entities.VehicleTypeAvailability; import org.entur.lamassu.service.*; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.QueryMapping; +import org.springframework.graphql.data.method.annotation.SchemaMapping; import org.springframework.stereotype.Controller; @Controller @@ -17,15 +29,24 @@ public class StationGraphQLController extends BaseGraphQLController { private final GeoSearchService geoSearchService; private final StationCache stationCache; + private final VehicleTypeCache vehicleTypeCache; + private final SystemCache systemCache; + private final PricingPlanCache pricingPlanCache; public StationGraphQLController( GeoSearchService geoSearchService, FeedProviderService feedProviderService, - StationCache stationCache + StationCache stationCache, + VehicleTypeCache vehicleTypeCache, + SystemCache systemCache, + PricingPlanCache pricingPlanCache ) { super(feedProviderService); this.geoSearchService = geoSearchService; this.stationCache = stationCache; + this.vehicleTypeCache = vehicleTypeCache; + this.systemCache = systemCache; + this.pricingPlanCache = pricingPlanCache; } @QueryMapping @@ -99,4 +120,61 @@ public Collection stations( public Collection stationsById(@Argument List ids) { return stationCache.getAll(Set.copyOf(ids)); } + + @SchemaMapping(typeName = "VehicleTypeAvailability", field = "vehicleType") + public VehicleType getVehicleType(VehicleTypeAvailability vehicleTypeAvailability) { + return vehicleTypeCache.get(vehicleTypeAvailability.getVehicleTypeId()); + } + + @SchemaMapping(typeName = "VehicleDocksAvailability", field = "vehicleTypes") + public List getVehicleType( + VehicleDocksAvailability vehicleDocksAvailability + ) { + return vehicleTypeCache.getAll( + new HashSet<>(vehicleDocksAvailability.getVehicleTypeIds()) + ); + } + + @SchemaMapping(typeName = "Station", field = "system") + public System getSystem(Station station) { + return systemCache.get(station.getSystemId()); + } + + /** + * GBFS does not have pricing plans directly on station. They should be resolved + * via vehicle types instead. This is a workaround for not having to resolve + * all of a system's pricing plans, by collecting only the pricing plan's referred + * to by a stations various references to vehicle types + */ + @SchemaMapping(typeName = "Station", field = "pricingPlans") + public List getPricingPlans(Station station) { + Set pricingPlanIds = new HashSet<>(); + + // example: + station + .getVehicleTypesAvailable() + .stream() + .map(this::getVehicleType) + .forEach(vehicleType -> { + if (vehicleType.getPricingPlanIds() != null) { + pricingPlanIds.addAll(vehicleType.getPricingPlanIds()); + } + if (vehicleType.getDefaultPricingPlanId() != null) { + pricingPlanIds.add(vehicleType.getDefaultPricingPlanId()); + } + }); + + // should add from other vehicle types as well + + return pricingPlanCache.getAll(pricingPlanIds); + } + // TODO implement + /* private List vehicleCapacity; + private List vehicleDocksCapacity; + private List vehicleTypeCapacity; + private List vehicleTypesCapacity; */ + + // TODO: implement region resolving + + // TODO: we must also resolve pricing plans from within vehicle type } diff --git a/src/main/java/org/entur/lamassu/graphql/controller/VehicleGraphQLController.java b/src/main/java/org/entur/lamassu/graphql/controller/VehicleGraphQLController.java index e7351a53..af855d78 100644 --- a/src/main/java/org/entur/lamassu/graphql/controller/VehicleGraphQLController.java +++ b/src/main/java/org/entur/lamassu/graphql/controller/VehicleGraphQLController.java @@ -3,10 +3,16 @@ import java.util.Collection; import java.util.List; import java.util.Set; +import org.entur.lamassu.cache.PricingPlanCache; +import org.entur.lamassu.cache.SystemCache; import org.entur.lamassu.cache.VehicleCache; +import org.entur.lamassu.cache.VehicleTypeCache; import org.entur.lamassu.model.entities.FormFactor; +import org.entur.lamassu.model.entities.PricingPlan; import org.entur.lamassu.model.entities.PropulsionType; +import org.entur.lamassu.model.entities.System; import org.entur.lamassu.model.entities.Vehicle; +import org.entur.lamassu.model.entities.VehicleType; import org.entur.lamassu.service.BoundingBoxQueryParameters; import org.entur.lamassu.service.FeedProviderService; import org.entur.lamassu.service.GeoSearchService; @@ -14,6 +20,7 @@ import org.entur.lamassu.service.VehicleFilterParameters; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.QueryMapping; +import org.springframework.graphql.data.method.annotation.SchemaMapping; import org.springframework.stereotype.Controller; @Controller @@ -21,15 +28,24 @@ public class VehicleGraphQLController extends BaseGraphQLController { private final GeoSearchService geoSearchService; private final VehicleCache vehicleCache; + private final VehicleTypeCache vehicleTypeCache; + private final PricingPlanCache pricingPlanCache; + private final SystemCache systemCache; public VehicleGraphQLController( GeoSearchService geoSearchService, FeedProviderService feedProviderService, - VehicleCache vehicleCache + VehicleCache vehicleCache, + VehicleTypeCache vehicleTypeCache, + PricingPlanCache pricingPlanCache, + SystemCache systemCache ) { super(feedProviderService); this.geoSearchService = geoSearchService; this.vehicleCache = vehicleCache; + this.vehicleTypeCache = vehicleTypeCache; + this.pricingPlanCache = pricingPlanCache; + this.systemCache = systemCache; } @QueryMapping @@ -102,4 +118,19 @@ public Collection vehicles( return vehicles; } + + @SchemaMapping(typeName = "Vehicle", field = "vehicleType") + public VehicleType vehicleType(Vehicle vehicle) { + return vehicleTypeCache.get(vehicle.getVehicleTypeId()); + } + + @SchemaMapping(typeName = "Vehicle", field = "pricingPlan") + public PricingPlan pricingPlan(Vehicle vehicle) { + return pricingPlanCache.get(vehicle.getPricingPlanId()); + } + + @SchemaMapping(typeName = "Vehicle", field = "system") + public System system(Vehicle vehicle) { + return systemCache.get(vehicle.getSystemId()); + } } diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/StationsUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/StationsUpdater.java index f63a2f6b..ed8d95c8 100644 --- a/src/main/java/org/entur/lamassu/leader/entityupdater/StationsUpdater.java +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/StationsUpdater.java @@ -30,23 +30,16 @@ import org.entur.lamassu.cache.StationCache; import org.entur.lamassu.cache.StationSpatialIndex; import org.entur.lamassu.cache.StationSpatialIndexId; -import org.entur.lamassu.mapper.entitymapper.PricingPlanMapper; import org.entur.lamassu.mapper.entitymapper.StationMapper; -import org.entur.lamassu.mapper.entitymapper.SystemMapper; import org.entur.lamassu.metrics.MetricsService; -import org.entur.lamassu.model.entities.PricingPlan; import org.entur.lamassu.model.entities.Station; import org.entur.lamassu.model.provider.FeedProvider; +import org.entur.lamassu.service.SpatialIndexService; import org.entur.lamassu.util.CacheUtil; -import org.entur.lamassu.util.SpatialIndexIdUtil; import org.mobilitydata.gbfs.v3_0.station_information.GBFSData; import org.mobilitydata.gbfs.v3_0.station_information.GBFSStationInformation; import org.mobilitydata.gbfs.v3_0.station_status.GBFSStation; import org.mobilitydata.gbfs.v3_0.station_status.GBFSStationStatus; -import org.mobilitydata.gbfs.v3_0.system_information.GBFSSystemInformation; -import org.mobilitydata.gbfs.v3_0.system_pricing_plans.GBFSSystemPricingPlans; -import org.mobilitydata.gbfs.v3_0.system_regions.GBFSSystemRegions; -import org.mobilitydata.gbfs.v3_0.vehicle_types.GBFSVehicleTypes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -58,12 +51,10 @@ public class StationsUpdater { private final StationCache stationCache; private final StationSpatialIndex spatialIndex; - private final SystemMapper systemMapper; - private final PricingPlanMapper pricingPlanMapper; private final StationMapper stationMapper; - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final MetricsService metricsService; + private final SpatialIndexService spatialIndexService; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Value("${org.entur.lamassu.stationEntityCacheMinimumTtl:30}") private Integer stationEntityCacheMinimumTtl; @@ -75,17 +66,15 @@ public class StationsUpdater { public StationsUpdater( StationCache stationCache, StationSpatialIndex spatialIndex, - SystemMapper systemMapper, - PricingPlanMapper pricingPlanMapper, StationMapper stationMapper, - MetricsService metricsService + MetricsService metricsService, + SpatialIndexService spatialIndexService ) { this.stationCache = stationCache; this.spatialIndex = spatialIndex; - this.systemMapper = systemMapper; - this.pricingPlanMapper = pricingPlanMapper; this.stationMapper = stationMapper; this.metricsService = metricsService; + this.spatialIndexService = spatialIndexService; } public void addOrUpdateStations( @@ -96,10 +85,6 @@ public void addOrUpdateStations( GBFSStationStatus stationStatusFeed = delivery.stationStatus(); GBFSStationStatus oldStationStatusFeed = oldDelivery.stationStatus(); GBFSStationInformation stationInformationFeed = delivery.stationInformation(); - GBFSSystemInformation systemInformationFeed = delivery.systemInformation(); - GBFSSystemPricingPlans pricingPlansFeed = delivery.systemPricingPlans(); - GBFSVehicleTypes vehicleTypesFeed = delivery.vehicleTypes(); - GBFSSystemRegions systemRegionsFeed = delivery.systemRegions(); var stationIds = stationStatusFeed .getData() @@ -139,9 +124,6 @@ public void addOrUpdateStations( var originalStations = stationCache.getAllAsMap(stationIds); - var system = getSystem(feedProvider, systemInformationFeed); - var pricingPlans = getPricingPlans(pricingPlansFeed); - var stationInfo = Optional .ofNullable(stationInformationFeed) .map(GBFSStationInformation::getData) @@ -172,13 +154,10 @@ public void addOrUpdateStations( }) .map(station -> stationMapper.mapStation( - system, - pricingPlans, stationInfo.get(station.getStationId()), station, - vehicleTypesFeed, - systemRegionsFeed, - system.getLanguage() + feedProvider.getSystemId(), + feedProvider.getLanguage() ) ) .collect(Collectors.toMap(Station::getId, s -> s)); @@ -189,14 +168,11 @@ public void addOrUpdateStations( ); stations.forEach((key, station) -> { - var spatialIndexId = SpatialIndexIdUtil.createStationSpatialIndexId( - station, - feedProvider - ); + var spatialIndexId = spatialIndexService.createStationIndex(station, feedProvider); var previousStation = originalStations.get(key); if (previousStation != null) { - var oldSpatialIndexId = SpatialIndexIdUtil.createStationSpatialIndexId( + var oldSpatialIndexId = spatialIndexService.createStationIndex( previousStation, feedProvider ); @@ -247,20 +223,4 @@ public void addOrUpdateStations( stationCache.count() ); } - - private List getPricingPlans(GBFSSystemPricingPlans pricingPlansFeed) { - return pricingPlansFeed - .getData() - .getPlans() - .stream() - .map(pricingPlanMapper::mapPricingPlan) - .collect(Collectors.toList()); - } - - private org.entur.lamassu.model.entities.System getSystem( - FeedProvider feedProvider, - GBFSSystemInformation systemInformationFeed - ) { - return systemMapper.mapSystem(systemInformationFeed.getData(), feedProvider); - } } diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/VehiclesUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/VehiclesUpdater.java index 39bb509d..18da81eb 100644 --- a/src/main/java/org/entur/lamassu/leader/entityupdater/VehiclesUpdater.java +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/VehiclesUpdater.java @@ -18,7 +18,6 @@ package org.entur.lamassu.leader.entityupdater; -import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Map; @@ -29,22 +28,14 @@ import org.entur.lamassu.cache.VehicleCache; import org.entur.lamassu.cache.VehicleSpatialIndex; import org.entur.lamassu.cache.VehicleSpatialIndexId; -import org.entur.lamassu.mapper.entitymapper.PricingPlanMapper; -import org.entur.lamassu.mapper.entitymapper.SystemMapper; import org.entur.lamassu.mapper.entitymapper.VehicleMapper; -import org.entur.lamassu.mapper.entitymapper.VehicleTypeMapper; import org.entur.lamassu.metrics.MetricsService; -import org.entur.lamassu.model.entities.PricingPlan; import org.entur.lamassu.model.entities.Vehicle; -import org.entur.lamassu.model.entities.VehicleType; import org.entur.lamassu.model.provider.FeedProvider; +import org.entur.lamassu.service.SpatialIndexService; import org.entur.lamassu.util.CacheUtil; -import org.entur.lamassu.util.SpatialIndexIdUtil; -import org.mobilitydata.gbfs.v3_0.system_information.GBFSSystemInformation; -import org.mobilitydata.gbfs.v3_0.system_pricing_plans.GBFSSystemPricingPlans; import org.mobilitydata.gbfs.v3_0.vehicle_status.GBFSVehicle; import org.mobilitydata.gbfs.v3_0.vehicle_status.GBFSVehicleStatus; -import org.mobilitydata.gbfs.v3_0.vehicle_types.GBFSVehicleTypes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -56,12 +47,10 @@ public class VehiclesUpdater { private final VehicleCache vehicleCache; private final VehicleSpatialIndex spatialIndex; - private final SystemMapper systemMapper; - private final PricingPlanMapper pricingPlanMapper; - private final VehicleTypeMapper vehicleTypeMapper; private final VehicleMapper vehicleMapper; private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final MetricsService metricsService; + private final SpatialIndexService spatialIndexService; @Value("${org.entur.lamassu.vehicleEntityCacheMinimumTtl:30}") private Integer vehicleEntityCacheMinimumTtl; @@ -74,18 +63,14 @@ public VehiclesUpdater( VehicleCache vehicleCache, VehicleSpatialIndex spatialIndex, VehicleMapper vehicleMapper, - SystemMapper systemMapper, - PricingPlanMapper pricingPlanMapper, - VehicleTypeMapper vehicleTypeMapper, - MetricsService metricsService + MetricsService metricsService, + SpatialIndexService spatialIndexService ) { this.vehicleCache = vehicleCache; this.spatialIndex = spatialIndex; this.vehicleMapper = vehicleMapper; - this.systemMapper = systemMapper; - this.pricingPlanMapper = pricingPlanMapper; - this.vehicleTypeMapper = vehicleTypeMapper; this.metricsService = metricsService; + this.spatialIndexService = spatialIndexService; } public void addOrUpdateVehicles( @@ -95,9 +80,6 @@ public void addOrUpdateVehicles( ) { GBFSVehicleStatus vehicleStatusFeed = delivery.vehicleStatus(); GBFSVehicleStatus oldFreeBikeStatusFeed = oldDelivery.vehicleStatus(); - GBFSSystemInformation systemInformationFeed = delivery.systemInformation(); - GBFSSystemPricingPlans pricingPlansFeed = delivery.systemPricingPlans(); - GBFSVehicleTypes vehicleTypesFeed = delivery.vehicleTypes(); var vehicleIds = vehicleStatusFeed .getData() @@ -139,30 +121,14 @@ public void addOrUpdateVehicles( } var currentVehicles = vehicleCache.getAllAsMap(new HashSet<>(vehicleIds)); - var system = getSystem(feedProvider, systemInformationFeed); - var pricingPlans = getPricingPlans(pricingPlansFeed); - var vehicleTypes = getVehicleTypes( - vehicleTypesFeed, - pricingPlans, - system.getLanguage() - ); var vehicleList = vehicleStatusFeed .getData() .getVehicles() .stream() - .filter(new VehicleFilter(pricingPlans, vehicleTypes)) - .map(vehicle -> - vehicleMapper.mapVehicle( - vehicle, - vehicleTypes.get(vehicle.getVehicleTypeId()), - // pricingPlanId is optional for vehicles and defaults to it's vehicleType's default pricing plan - vehicle.getPricingPlanId() != null - ? pricingPlans.get(vehicle.getPricingPlanId()) - : vehicleTypes.get(vehicle.getVehicleTypeId()).getDefaultPricingPlan(), - system - ) - ) + // TODO consider the consequence of removing this filter + //.filter(new VehicleFilter(pricingPlans, vehicleTypes)) + .map(vehicle -> vehicleMapper.mapVehicle(vehicle, feedProvider.getSystemId())) .toList(); var duplicateVehicles = vehicleList @@ -188,14 +154,11 @@ public void addOrUpdateVehicles( ); vehicles.forEach((key, vehicle) -> { - var spatialIndexId = SpatialIndexIdUtil.createVehicleSpatialIndexId( - vehicle, - feedProvider - ); + var spatialIndexId = spatialIndexService.createVehicleIndex(vehicle, feedProvider); var previousVehicle = currentVehicles.get(key); if (previousVehicle != null) { - var oldSpatialIndexId = SpatialIndexIdUtil.createVehicleSpatialIndexId( + var oldSpatialIndexId = spatialIndexService.createVehicleIndex( previousVehicle, feedProvider ); @@ -211,10 +174,7 @@ public void addOrUpdateVehicles( .stream() .filter(currentVehicles::containsKey) .map(id -> - SpatialIndexIdUtil.createVehicleSpatialIndexId( - currentVehicles.get(id), - feedProvider - ) + spatialIndexService.createVehicleIndex(currentVehicles.get(id), feedProvider) ) .collect(Collectors.toSet()) ); @@ -258,41 +218,4 @@ public void addOrUpdateVehicles( vehicleCache.count() ); } - - private Map getVehicleTypes( - GBFSVehicleTypes vehicleTypesFeed, - Map pricingPlans, - String language - ) { - return vehicleTypesFeed - .getData() - .getVehicleTypes() - .stream() - .map(vehicleType -> - vehicleTypeMapper.mapVehicleType( - vehicleType, - new ArrayList<>(pricingPlans.values()), - language - ) - ) - .collect(Collectors.toMap(VehicleType::getId, i -> i)); - } - - private org.entur.lamassu.model.entities.System getSystem( - FeedProvider feedProvider, - GBFSSystemInformation systemInformationFeed - ) { - return systemMapper.mapSystem(systemInformationFeed.getData(), feedProvider); - } - - private Map getPricingPlans( - GBFSSystemPricingPlans pricingPlansFeed - ) { - return pricingPlansFeed - .getData() - .getPlans() - .stream() - .map(pricingPlanMapper::mapPricingPlan) - .collect(Collectors.toMap(PricingPlan::getId, i -> i)); - } } diff --git a/src/main/java/org/entur/lamassu/mapper/entitymapper/StationMapper.java b/src/main/java/org/entur/lamassu/mapper/entitymapper/StationMapper.java index c4f08a2e..2e24a0de 100644 --- a/src/main/java/org/entur/lamassu/mapper/entitymapper/StationMapper.java +++ b/src/main/java/org/entur/lamassu/mapper/entitymapper/StationMapper.java @@ -22,10 +22,8 @@ import com.mapbox.geojson.utils.PolylineUtils; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; import org.entur.lamassu.model.entities.MultiPolygon; import org.entur.lamassu.model.entities.ParkingType; import org.entur.lamassu.model.entities.PricingPlan; @@ -35,7 +33,6 @@ import org.entur.lamassu.model.entities.System; import org.entur.lamassu.model.entities.VehicleDocksAvailability; import org.entur.lamassu.model.entities.VehicleDocksCapacity; -import org.entur.lamassu.model.entities.VehicleType; import org.entur.lamassu.model.entities.VehicleTypeAvailability; import org.entur.lamassu.model.entities.VehicleTypeCapacity; import org.entur.lamassu.model.entities.VehicleTypesCapacity; @@ -59,28 +56,20 @@ public class StationMapper { private final TranslationMapper translationMapper; private final RentalUrisMapper rentalUrisMapper; - private final VehicleTypeMapper vehicleTypeMapper; - - private static final Logger logger = LoggerFactory.getLogger(StationMapper.class); @Autowired public StationMapper( TranslationMapper translationMapper, - RentalUrisMapper rentalUrisMapper, - VehicleTypeMapper vehicleTypeMapper + RentalUrisMapper rentalUrisMapper ) { this.translationMapper = translationMapper; this.rentalUrisMapper = rentalUrisMapper; - this.vehicleTypeMapper = vehicleTypeMapper; } public Station mapStation( - System system, - List pricingPlans, GBFSStation stationInformation, org.mobilitydata.gbfs.v3_0.station_status.GBFSStation stationStatus, - GBFSVehicleTypes vehicleTypesFeed, - GBFSSystemRegions regions, + String systemId, String language ) { var station = new Station(); @@ -114,7 +103,7 @@ public Station mapStation( station.setLon(stationInformation.getLon()); station.setAddress(stationInformation.getAddress()); station.setCrossStreet(stationInformation.getCrossStreet()); - station.setRegion(mapRegion(regions, stationInformation.getRegionId(), language)); + station.setRegionId(stationInformation.getRegionId()); station.setPostCode(stationInformation.getPostCode()); station.setRentalMethods(mapRentalMethods(stationInformation.getRentalMethods())); station.setVirtualStation(stationInformation.getIsVirtualStation()); @@ -128,34 +117,24 @@ public Station mapStation( station.setVehicleCapacity( stationInformation.getVehicleTypesCapacity() != null - ? mapVehicleCapacities( - stationInformation.getVehicleTypesCapacity(), - mapVehicleTypes(vehicleTypesFeed, pricingPlans, language) - ) + ? mapVehicleCapacities(stationInformation.getVehicleTypesCapacity()) : null ); station.setVehicleTypesCapacity( stationInformation.getVehicleTypesCapacity() != null - ? mapVehicleTypesCapacity( - stationInformation.getVehicleTypesCapacity(), - mapVehicleTypes(vehicleTypesFeed, pricingPlans, language) - ) + ? mapVehicleTypesCapacity(stationInformation.getVehicleTypesCapacity()) : null ); station.setVehicleTypeCapacity( stationInformation.getVehicleDocksCapacity() != null - ? mapVehicleTypeCapacities( - stationInformation.getVehicleDocksCapacity(), - mapVehicleTypes(vehicleTypesFeed, pricingPlans, language) - ) + ? mapVehicleTypeCapacities(stationInformation.getVehicleDocksCapacity()) : null ); station.setVehicleDocksCapacity( stationInformation.getVehicleDocksCapacity() != null ? mapVehicleDocksCapacityToVehicleTypeCapacity( - stationInformation.getVehicleDocksCapacity(), - mapVehicleTypes(vehicleTypesFeed, pricingPlans, language) + stationInformation.getVehicleDocksCapacity() ) : null ); @@ -177,12 +156,7 @@ public Station mapStation( ); station.setVehicleTypesAvailable( stationStatus.getVehicleTypesAvailable() != null - ? mapVehicleTypesAvailable( - vehicleTypesFeed, - stationStatus.getVehicleTypesAvailable(), - pricingPlans, - language - ) + ? mapVehicleTypesAvailable(stationStatus.getVehicleTypesAvailable()) : null ); station.setNumBikesDisabled( @@ -202,12 +176,7 @@ public Station mapStation( ); station.setVehicleDocksAvailable( stationStatus.getVehicleDocksAvailable() != null - ? mapVehicleDocksAvailable( - vehicleTypesFeed, - stationStatus.getVehicleDocksAvailable(), - pricingPlans, - language - ) + ? mapVehicleDocksAvailable(stationStatus.getVehicleDocksAvailable()) : null ); station.setNumDocksDisabled(station.getNumDocksDisabled()); @@ -219,8 +188,7 @@ public Station mapStation( ? stationStatus.getLastReported().getTime() / 1000 : null ); - station.setSystem(system); - station.setPricingPlans(pricingPlans); + station.setSystemId(systemId); station.setStationAreaPolylineEncodedMultiPolygon( station.getStationArea() != null ? station @@ -277,222 +245,98 @@ private List mapRentalMethods( .orElse(null); } - private Region mapRegion(GBFSSystemRegions regions, String regionId, String language) { - if (regionId == null || regionId.isBlank()) { - return null; - } - - var sourceRegion = Optional - .ofNullable(regions) - .flatMap(r -> - r - .getData() - .getRegions() - .stream() - .filter(region -> region.getRegionId().equals(regionId)) - .findFirst() - ); - - if (sourceRegion.isPresent()) { - var region = new Region(); - region.setId(regionId); - region.setName( - translationMapper.mapSingleTranslation( - language, - sourceRegion - .get() - .getName() - .stream() - .filter(name -> name.getLanguage().equals(language)) - .map(org.mobilitydata.gbfs.v3_0.system_regions.GBFSName::getText) - .findFirst() - .orElse(null) - ) - ); - return region; - } else { - logger.warn( - "Could not map regionId to a region from system_regions feed {}", - regionId - ); - return null; - } - } - private List mapVehicleCapacities( - List vehicleCapacityList, - Map vehicleTypes + List vehicleCapacityList ) { return vehicleCapacityList .stream() - .map(vehicleCapacity -> mapVehicleTypeCapacity(vehicleTypes, vehicleCapacity)) + .map(StationMapper::mapVehicleTypeCapacity) .toList(); } private static @NotNull VehicleTypeCapacity mapVehicleTypeCapacity( - Map vehicleTypes, GBFSVehicleTypesCapacity vehicleCapacity ) { var mapped = new VehicleTypeCapacity(); - mapped.setVehicleType( - vehicleTypes.get(vehicleCapacity.getVehicleTypeIds().getFirst()) - ); + mapped.setVehicleTypeId(vehicleCapacity.getVehicleTypeIds().getFirst()); mapped.setCount(vehicleCapacity.getCount()); return mapped; } private List mapVehicleTypesCapacity( - List vehicleTypesCapacity, - Map vehicleTypes + List vehicleTypesCapacity ) { - return vehicleTypesCapacity - .stream() - .map(v -> mapVehicleTypeCapacity(v, vehicleTypes)) - .toList(); + return vehicleTypesCapacity.stream().map(this::mapVehicleTypesCapacity).toList(); } - private VehicleTypesCapacity mapVehicleTypeCapacity( - GBFSVehicleTypesCapacity vehicleTypesCapacity, - Map vehicleTypes + private VehicleTypesCapacity mapVehicleTypesCapacity( + GBFSVehicleTypesCapacity vehicleTypesCapacity ) { var mapped = new VehicleTypesCapacity(); - mapped.setVehicleTypes( - vehicleTypesCapacity.getVehicleTypeIds().stream().map(vehicleTypes::get).toList() - ); + mapped.setVehicleTypeIds(vehicleTypesCapacity.getVehicleTypeIds()); mapped.setCount(vehicleTypesCapacity.getCount()); return mapped; } private List mapVehicleTypeCapacities( - List vehicleCapacity, - Map vehicleTypes + List vehicleCapacity ) { return vehicleCapacity .stream() - .map(entry -> mapVehicleDocksCapacityToVehicleTypeCapacity(entry, vehicleTypes)) + .map(this::mapVehicleDocksCapacityToVehicleTypeCapacity) .toList(); } private VehicleTypeCapacity mapVehicleDocksCapacityToVehicleTypeCapacity( - GBFSVehicleDocksCapacity vehicleDocksCapacity, - Map vehicleTypes + GBFSVehicleDocksCapacity vehicleDocksCapacity ) { var mapped = new VehicleTypeCapacity(); - mapped.setVehicleType( - vehicleTypes.get(vehicleDocksCapacity.getVehicleTypeIds().getFirst()) - ); + mapped.setVehicleTypeId(vehicleDocksCapacity.getVehicleTypeIds().getFirst()); mapped.setCount(vehicleDocksCapacity.getCount()); return mapped; } private List mapVehicleDocksCapacityToVehicleTypeCapacity( - List vehicleDocksCapacity, - Map vehicleTypes + List vehicleDocksCapacity ) { - return vehicleDocksCapacity - .stream() - .map(v -> mapVehicleDocksCapacity(v, vehicleTypes)) - .toList(); + return vehicleDocksCapacity.stream().map(this::mapVehicleDocksCapacity).toList(); } private VehicleDocksCapacity mapVehicleDocksCapacity( - GBFSVehicleDocksCapacity vehicleDocksCapacity, - Map vehicleTypes + GBFSVehicleDocksCapacity vehicleDocksCapacity ) { var mapped = new VehicleDocksCapacity(); - mapped.setVehicleTypes( - vehicleDocksCapacity.getVehicleTypeIds().stream().map(vehicleTypes::get).toList() - ); + mapped.setVehicleTypeIds(vehicleDocksCapacity.getVehicleTypeIds()); mapped.setCount(vehicleDocksCapacity.getCount()); return mapped; } - private Map mapVehicleTypes( - GBFSVehicleTypes vehicleTypesFeed, - List pricingPlans, - String language - ) { - return vehicleTypesFeed - .getData() - .getVehicleTypes() - .stream() - .map(vehicleType -> - vehicleTypeMapper.mapVehicleType(vehicleType, pricingPlans, language) - ) - .collect(Collectors.toMap(VehicleType::getId, vehicleType -> vehicleType)); - } - private List mapVehicleTypesAvailable( - GBFSVehicleTypes vehicleTypesFeed, - List vehicleTypesAvailable, - List pricingPlans, - String language + List vehicleTypesAvailable ) { - var mappedVehicleTypes = vehicleTypesFeed - .getData() - .getVehicleTypes() - .stream() - .map(vehicleType -> - vehicleTypeMapper.mapVehicleType(vehicleType, pricingPlans, language) - ) - .collect(Collectors.toMap(VehicleType::getId, vehicleType -> vehicleType)); - - return vehicleTypesAvailable - .stream() - .map(vehicleTypeAvailability -> - mapVehicleTypeAvailability( - mappedVehicleTypes.get(vehicleTypeAvailability.getVehicleTypeId()), - vehicleTypeAvailability - ) - ) - .collect(Collectors.toList()); + return vehicleTypesAvailable.stream().map(this::mapVehicleTypeAvailability).toList(); } private VehicleTypeAvailability mapVehicleTypeAvailability( - VehicleType vehicleType, GBFSVehicleTypesAvailable vehicleTypeAvailability ) { var mapped = new VehicleTypeAvailability(); - mapped.setVehicleType(vehicleType); + mapped.setVehicleTypeId(vehicleTypeAvailability.getVehicleTypeId()); mapped.setCount(vehicleTypeAvailability.getCount()); return mapped; } private List mapVehicleDocksAvailable( - GBFSVehicleTypes vehicleTypesFeed, - List vehicleDocksAvailable, - List pricingPlans, - String language + List vehicleDocksAvailable ) { - var mappedVehicleTypes = vehicleTypesFeed - .getData() - .getVehicleTypes() - .stream() - .map(vehicleType -> - vehicleTypeMapper.mapVehicleType(vehicleType, pricingPlans, language) - ) - .collect(Collectors.toMap(VehicleType::getId, vehicleType -> vehicleType)); - - return vehicleDocksAvailable - .stream() - .map(vehicleDocksAvailability -> - mapVehicleDocksAvailability(mappedVehicleTypes, vehicleDocksAvailability) - ) - .collect(Collectors.toList()); + return vehicleDocksAvailable.stream().map(this::mapVehicleDocksAvailability).toList(); } private VehicleDocksAvailability mapVehicleDocksAvailability( - Map mappedVehicleTypes, GBFSVehicleDocksAvailable vehicleDocksAvailability ) { - var vehicleTypes = vehicleDocksAvailability - .getVehicleTypeIds() - .stream() - .map(mappedVehicleTypes::get) - .toList(); - var mapped = new VehicleDocksAvailability(); - mapped.setVehicleTypes(vehicleTypes); + mapped.setVehicleTypeIds(vehicleDocksAvailability.getVehicleTypeIds()); mapped.setCount(vehicleDocksAvailability.getCount()); return mapped; } diff --git a/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleMapper.java b/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleMapper.java index cbf7894e..39c8aa57 100644 --- a/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleMapper.java +++ b/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleMapper.java @@ -38,12 +38,7 @@ public VehicleMapper(RentalUrisMapper rentalUrisMapper) { this.rentalUrisMapper = rentalUrisMapper; } - public Vehicle mapVehicle( - GBFSVehicle vehicle, - VehicleType vehicleType, - PricingPlan pricingPlan, - System system - ) { + public Vehicle mapVehicle(GBFSVehicle vehicle, String systemId) { var mappedVehicle = new Vehicle(); mappedVehicle.setId(vehicle.getVehicleId()); mappedVehicle.setLat(vehicle.getLat()); @@ -54,12 +49,12 @@ public Vehicle mapVehicle( vehicle.getCurrentRangeMeters() == null ? 0.0 : vehicle.getCurrentRangeMeters() ); mappedVehicle.setCurrentFuelPercent(vehicle.getCurrentFuelPercent()); - mappedVehicle.setVehicleType(vehicleType); - mappedVehicle.setPricingPlan(pricingPlan); + mappedVehicle.setVehicleTypeId(vehicle.getVehicleTypeId()); + mappedVehicle.setPricingPlanId(vehicle.getPricingPlanId()); mappedVehicle.setVehicleEquipment(mapVehicleEquipment(vehicle.getVehicleEquipment())); mappedVehicle.setRentalUris(rentalUrisMapper.mapRentalUris(vehicle.getRentalUris())); mappedVehicle.setAvailableUntil(vehicle.getAvailableUntil()); - mappedVehicle.setSystem(system); + mappedVehicle.setSystemId(systemId); return mappedVehicle; } diff --git a/src/main/java/org/entur/lamassu/model/entities/Station.java b/src/main/java/org/entur/lamassu/model/entities/Station.java index 1b5c5264..39c4bc11 100644 --- a/src/main/java/org/entur/lamassu/model/entities/Station.java +++ b/src/main/java/org/entur/lamassu/model/entities/Station.java @@ -61,6 +61,8 @@ public class Station implements LocationEntity { private System system; private List pricingPlans; private List> stationAreaPolylineEncodedMultiPolygon; + private String systemId; + private String regionId; @Override public String getId() { @@ -375,6 +377,22 @@ public List> getStationAreaPolylineEncodedMultiPolygon() { return stationAreaPolylineEncodedMultiPolygon; } + public String getSystemId() { + return systemId; + } + + public void setSystemId(String systemId) { + this.systemId = systemId; + } + + public String getRegionId() { + return regionId; + } + + public void setRegionId(String regionId) { + this.regionId = regionId; + } + @Override public String toString() { return ( diff --git a/src/main/java/org/entur/lamassu/model/entities/Vehicle.java b/src/main/java/org/entur/lamassu/model/entities/Vehicle.java index 910b870a..80625c16 100644 --- a/src/main/java/org/entur/lamassu/model/entities/Vehicle.java +++ b/src/main/java/org/entur/lamassu/model/entities/Vehicle.java @@ -18,6 +18,9 @@ public class Vehicle implements LocationEntity { private PricingPlan pricingPlan; private System system; private RentalUris rentalUris; + private String vehicleTypeId; + private String pricingPlanId; + private String systemId; @Override public String getId() { @@ -126,6 +129,30 @@ public void setRentalUris(RentalUris rentalUris) { this.rentalUris = rentalUris; } + public String getVehicleTypeId() { + return vehicleTypeId; + } + + public void setVehicleTypeId(String vehicleTypeId) { + this.vehicleTypeId = vehicleTypeId; + } + + public String getPricingPlanId() { + return pricingPlanId; + } + + public void setPricingPlanId(String pricingPlanId) { + this.pricingPlanId = pricingPlanId; + } + + public String getSystemId() { + return systemId; + } + + public void setSystemId(String systemId) { + this.systemId = systemId; + } + @Override public String toString() { return ( @@ -145,8 +172,9 @@ public String toString() { currentRangeMeters + ", currentFuelPercent=" + currentFuelPercent + - ", vehicleType=" + - vehicleType + + ", vehicleTypeId='" + + vehicleTypeId + + '\'' + ", vehicleEquipment=" + vehicleEquipment + ", availableUntil='" + diff --git a/src/main/java/org/entur/lamassu/model/entities/VehicleDocksAvailability.java b/src/main/java/org/entur/lamassu/model/entities/VehicleDocksAvailability.java index 915902a8..2011a428 100644 --- a/src/main/java/org/entur/lamassu/model/entities/VehicleDocksAvailability.java +++ b/src/main/java/org/entur/lamassu/model/entities/VehicleDocksAvailability.java @@ -24,6 +24,7 @@ public class VehicleDocksAvailability implements Serializable { private List vehicleTypes; + private List vehicleTypeIds; private Integer count; public List getVehicleTypes() { @@ -42,6 +43,14 @@ public void setCount(Integer count) { this.count = count; } + public List getVehicleTypeIds() { + return vehicleTypeIds; + } + + public void setVehicleTypeIds(List vehicleTypeIds) { + this.vehicleTypeIds = vehicleTypeIds; + } + @Override public String toString() { return ( diff --git a/src/main/java/org/entur/lamassu/model/entities/VehicleDocksCapacity.java b/src/main/java/org/entur/lamassu/model/entities/VehicleDocksCapacity.java index cd78966c..ece75fcf 100644 --- a/src/main/java/org/entur/lamassu/model/entities/VehicleDocksCapacity.java +++ b/src/main/java/org/entur/lamassu/model/entities/VehicleDocksCapacity.java @@ -24,6 +24,7 @@ public class VehicleDocksCapacity implements Serializable { private List vehicleTypes; + private List vehicleTypeIds; private Integer count; public List getVehicleTypes() { @@ -41,4 +42,12 @@ public Integer getCount() { public void setCount(Integer count) { this.count = count; } + + public List getVehicleTypeIds() { + return vehicleTypeIds; + } + + public void setVehicleTypeIds(List vehicleTypeIds) { + this.vehicleTypeIds = vehicleTypeIds; + } } diff --git a/src/main/java/org/entur/lamassu/model/entities/VehicleTypeAvailability.java b/src/main/java/org/entur/lamassu/model/entities/VehicleTypeAvailability.java index 8723af98..f7ee03fd 100644 --- a/src/main/java/org/entur/lamassu/model/entities/VehicleTypeAvailability.java +++ b/src/main/java/org/entur/lamassu/model/entities/VehicleTypeAvailability.java @@ -23,6 +23,7 @@ public class VehicleTypeAvailability implements Serializable { private VehicleType vehicleType; + private String vehicleTypeId; private Integer count; public VehicleType getVehicleType() { @@ -41,6 +42,14 @@ public void setCount(Integer count) { this.count = count; } + public String getVehicleTypeId() { + return vehicleTypeId; + } + + public void setVehicleTypeId(String vehicleTypeId) { + this.vehicleTypeId = vehicleTypeId; + } + @Override public String toString() { return ( diff --git a/src/main/java/org/entur/lamassu/model/entities/VehicleTypeCapacity.java b/src/main/java/org/entur/lamassu/model/entities/VehicleTypeCapacity.java index 8a310cc5..1c0c4257 100644 --- a/src/main/java/org/entur/lamassu/model/entities/VehicleTypeCapacity.java +++ b/src/main/java/org/entur/lamassu/model/entities/VehicleTypeCapacity.java @@ -24,6 +24,8 @@ public class VehicleTypeCapacity implements Serializable { private VehicleType vehicleType; + private String vehicleTypeId; + private Integer count; public VehicleType getVehicleType() { @@ -42,6 +44,14 @@ public void setCount(Integer count) { this.count = count; } + public String getVehicleTypeId() { + return vehicleTypeId; + } + + public void setVehicleTypeId(String vehicleTypeId) { + this.vehicleTypeId = vehicleTypeId; + } + @Override public String toString() { return ( diff --git a/src/main/java/org/entur/lamassu/model/entities/VehicleTypesCapacity.java b/src/main/java/org/entur/lamassu/model/entities/VehicleTypesCapacity.java index 081c4840..f2c27c52 100644 --- a/src/main/java/org/entur/lamassu/model/entities/VehicleTypesCapacity.java +++ b/src/main/java/org/entur/lamassu/model/entities/VehicleTypesCapacity.java @@ -24,6 +24,7 @@ public class VehicleTypesCapacity implements Serializable { private List vehicleTypes; + private List vehicleTypeIds; private Integer count; public List getVehicleTypes() { @@ -41,4 +42,12 @@ public Integer getCount() { public void setCount(Integer count) { this.count = count; } + + public List getVehicleTypeIds() { + return vehicleTypeIds; + } + + public void setVehicleTypeIds(List vehicleTypeIds) { + this.vehicleTypeIds = vehicleTypeIds; + } } diff --git a/src/main/java/org/entur/lamassu/service/SpatialIndexService.java b/src/main/java/org/entur/lamassu/service/SpatialIndexService.java new file mode 100644 index 00000000..93579106 --- /dev/null +++ b/src/main/java/org/entur/lamassu/service/SpatialIndexService.java @@ -0,0 +1,83 @@ +package org.entur.lamassu.service; + +import java.util.List; +import java.util.stream.Collectors; +import org.entur.lamassu.cache.StationSpatialIndexId; +import org.entur.lamassu.cache.VehicleSpatialIndexId; +import org.entur.lamassu.cache.VehicleTypeCache; +import org.entur.lamassu.model.entities.Station; +import org.entur.lamassu.model.entities.Vehicle; +import org.entur.lamassu.model.entities.VehicleType; +import org.entur.lamassu.model.provider.FeedProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class SpatialIndexService { + + private final VehicleTypeCache vehicleTypeCache; + + @Autowired + public SpatialIndexService(VehicleTypeCache vehicleTypeCache) { + this.vehicleTypeCache = vehicleTypeCache; + } + + public VehicleSpatialIndexId createVehicleIndex( + Vehicle vehicle, + FeedProvider provider + ) { + VehicleType vehicleType = vehicleTypeCache.get(vehicle.getVehicleTypeId()); + if (vehicleType == null) { + throw new IllegalStateException( + "Vehicle type not found for id: " + vehicle.getVehicleTypeId() + ); + } + + var id = new VehicleSpatialIndexId(); + id.setId(vehicle.getId()); + id.setCodespace(provider.getCodespace()); + id.setSystemId(provider.getSystemId()); + id.setOperatorId(provider.getOperatorId()); + id.setFormFactor(vehicleType.getFormFactor()); + id.setPropulsionType(vehicleType.getPropulsionType()); + id.setReserved(vehicle.getReserved()); + id.setDisabled(vehicle.getDisabled()); + return id; + } + + public StationSpatialIndexId createStationIndex( + Station station, + FeedProvider provider + ) { + var id = new StationSpatialIndexId(); + id.setId(station.getId()); + id.setCodespace(provider.getCodespace()); + id.setSystemId(provider.getSystemId()); + id.setOperatorId(provider.getOperatorId()); + + if (station.getVehicleTypesAvailable() != null) { + var vehicleTypeIds = station + .getVehicleTypesAvailable() + .stream() + .map(vta -> vta.getVehicleTypeId()) + .collect(Collectors.toSet()); + + List vehicleTypes = vehicleTypeCache.getAll(vehicleTypeIds); + + id.setAvailableFormFactors( + vehicleTypes.stream().map(VehicleType::getFormFactor).collect(Collectors.toList()) + ); + id.setAvailablePropulsionTypes( + vehicleTypes + .stream() + .map(VehicleType::getPropulsionType) + .collect(Collectors.toList()) + ); + } else { + id.setAvailableFormFactors(List.of()); + id.setAvailablePropulsionTypes(List.of()); + } + + return id; + } +} diff --git a/src/test/java/org/entur/lamassu/service/GeoSearchServiceTest.java b/src/test/java/org/entur/lamassu/service/GeoSearchServiceTest.java index 5f72365d..8303b21e 100644 --- a/src/test/java/org/entur/lamassu/service/GeoSearchServiceTest.java +++ b/src/test/java/org/entur/lamassu/service/GeoSearchServiceTest.java @@ -39,7 +39,7 @@ import org.entur.lamassu.model.provider.FeedProvider; import org.entur.lamassu.service.impl.GeoSearchServiceImpl; import org.entur.lamassu.stubs.VehicleCacheStub; -import org.entur.lamassu.util.SpatialIndexIdUtil; +import org.entur.lamassu.util.TestSpatialIndexBuilder; import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; @@ -77,7 +77,7 @@ public void setup() { vehicles .stream() .map(vehicle -> - SpatialIndexIdUtil.createVehicleSpatialIndexId(vehicle, feedProvider) + TestSpatialIndexBuilder.createVehicleIndex(vehicle, feedProvider) ) .collect(Collectors.toList()) ); @@ -109,9 +109,7 @@ public void testRemoveVehicleSpatialIndexOrphans() { var orphans = service.removeVehicleSpatialIndexOrphans(); verify(vehicleSpatialIndex) .removeAll( - Set.of( - SpatialIndexIdUtil.createVehicleSpatialIndexId(vehicleToRemove, feedProvider) - ) + Set.of(TestSpatialIndexBuilder.createVehicleIndex(vehicleToRemove, feedProvider)) ); } diff --git a/src/test/java/org/entur/lamassu/util/SpatialIndexIdFilterTest.java b/src/test/java/org/entur/lamassu/util/SpatialIndexIdFilterTest.java index 08c29791..3bcddd35 100644 --- a/src/test/java/org/entur/lamassu/util/SpatialIndexIdFilterTest.java +++ b/src/test/java/org/entur/lamassu/util/SpatialIndexIdFilterTest.java @@ -27,7 +27,7 @@ public void testNoFilter() { @Test public void testNoFilterReturnsStationWithoutVehicleTypesAvailable() { StationSpatialIndexId stationSpatialIndexId = - SpatialIndexIdUtil.createStationSpatialIndexId( + TestSpatialIndexBuilder.createStationIndex( aStationWithoutVehicleTypeAvailability(), aProvider() ); @@ -146,7 +146,7 @@ public void testVehicleTypesAvailableFilter() { } private VehicleSpatialIndexId aVehicleId() { - return SpatialIndexIdUtil.createVehicleSpatialIndexId(aVehicle(), aProvider()); + return TestSpatialIndexBuilder.createVehicleIndex(aVehicle(), aProvider()); } private List emptyList() { @@ -154,19 +154,19 @@ private List emptyList() { } private StationSpatialIndexId aStationId() { - return SpatialIndexIdUtil.createStationSpatialIndexId(aStation(), aProvider()); + return TestSpatialIndexBuilder.createStationIndex(aStation(), aProvider()); } private VehicleSpatialIndexId aReservedId() { var vehicle = aVehicle(); vehicle.setReserved(true); - return SpatialIndexIdUtil.createVehicleSpatialIndexId(vehicle, aProvider()); + return TestSpatialIndexBuilder.createVehicleIndex(vehicle, aProvider()); } private VehicleSpatialIndexId aDisabledId() { var vehicle = aVehicle(); vehicle.setDisabled(true); - return SpatialIndexIdUtil.createVehicleSpatialIndexId(vehicle, aProvider()); + return TestSpatialIndexBuilder.createVehicleIndex(vehicle, aProvider()); } private Vehicle aVehicle() { diff --git a/src/main/java/org/entur/lamassu/util/SpatialIndexIdUtil.java b/src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java similarity index 59% rename from src/main/java/org/entur/lamassu/util/SpatialIndexIdUtil.java rename to src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java index bcfb6521..18ce6d56 100644 --- a/src/main/java/org/entur/lamassu/util/SpatialIndexIdUtil.java +++ b/src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java @@ -1,6 +1,6 @@ package org.entur.lamassu.util; -import java.util.Collections; +import java.util.List; import java.util.stream.Collectors; import org.entur.lamassu.cache.StationSpatialIndexId; import org.entur.lamassu.cache.VehicleSpatialIndexId; @@ -8,19 +8,23 @@ import org.entur.lamassu.model.entities.Vehicle; import org.entur.lamassu.model.provider.FeedProvider; -public class SpatialIndexIdUtil { +/** + * Test helper class for creating spatial index IDs. + * This replaces the functionality of SpatialIndexService in tests. + */ +public class TestSpatialIndexBuilder { - private SpatialIndexIdUtil() {} + private TestSpatialIndexBuilder() {} - public static VehicleSpatialIndexId createVehicleSpatialIndexId( + public static VehicleSpatialIndexId createVehicleIndex( Vehicle vehicle, - FeedProvider feedProvider + FeedProvider provider ) { var id = new VehicleSpatialIndexId(); id.setId(vehicle.getId()); - id.setCodespace(feedProvider.getCodespace()); - id.setSystemId(feedProvider.getSystemId()); - id.setOperatorId(feedProvider.getOperatorId()); + id.setCodespace(provider.getCodespace()); + id.setSystemId(provider.getSystemId()); + id.setOperatorId(provider.getOperatorId()); id.setFormFactor(vehicle.getVehicleType().getFormFactor()); id.setPropulsionType(vehicle.getVehicleType().getPropulsionType()); id.setReserved(vehicle.getReserved()); @@ -28,15 +32,16 @@ public static VehicleSpatialIndexId createVehicleSpatialIndexId( return id; } - public static StationSpatialIndexId createStationSpatialIndexId( + public static StationSpatialIndexId createStationIndex( Station station, - FeedProvider feedProvider + FeedProvider provider ) { var id = new StationSpatialIndexId(); id.setId(station.getId()); - id.setCodespace(feedProvider.getCodespace()); - id.setSystemId(feedProvider.getSystemId()); - id.setOperatorId(feedProvider.getOperatorId()); + id.setCodespace(provider.getCodespace()); + id.setSystemId(provider.getSystemId()); + id.setOperatorId(provider.getOperatorId()); + if (station.getVehicleTypesAvailable() != null) { id.setAvailableFormFactors( station @@ -53,11 +58,8 @@ public static StationSpatialIndexId createStationSpatialIndexId( .collect(Collectors.toList()) ); } else { - // Note: in case no validation is activated, this issue would slip - // silently. On the other hand, logging it here for every station would - // be overwhelming... - id.setAvailableFormFactors(Collections.emptyList()); - id.setAvailablePropulsionTypes(Collections.emptyList()); + id.setAvailableFormFactors(List.of()); + id.setAvailablePropulsionTypes(List.of()); } return id; diff --git a/src/test/resources/v3/vehicle_status.json b/src/test/resources/v3/vehicle_status.json index 03387e5f..f7c257d1 100644 --- a/src/test/resources/v3/vehicle_status.json +++ b/src/test/resources/v3/vehicle_status.json @@ -12,6 +12,7 @@ "is_reserved":false, "is_disabled":false, "vehicle_type_id":"abc123", + "pricing_plan_id": "bike_plan_1", "rental_uris": { "android": "https://www.example.com/app?vehicle_id=973a5c94-c288-4a2b-afa6-de8aeb6ae2e5&platform=android&", "ios": "https://www.example.com/app?vehicle_id=973a5c94-c288-4a2b-afa6-de8aeb6ae2e5&platform=ios" @@ -60,4 +61,4 @@ } ] } -} \ No newline at end of file +} From 4cda2f6323f58e9d3cda6c856eb4e72dd1e24d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Fri, 20 Dec 2024 16:08:07 +0100 Subject: [PATCH 7/9] Cleanup --- .../graphql/controller/StationGraphQLController.java | 2 -- .../lamassu/leader/entityupdater/EntityCachesUpdater.java | 2 +- .../lamassu/leader/entityupdater/PricingPlansUpdater.java | 7 +------ .../entur/lamassu/mapper/entitymapper/RegionMapper.java | 6 ------ .../entur/lamassu/mapper/entitymapper/StationMapper.java | 7 ------- .../entur/lamassu/mapper/entitymapper/VehicleMapper.java | 3 --- 6 files changed, 2 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/entur/lamassu/graphql/controller/StationGraphQLController.java b/src/main/java/org/entur/lamassu/graphql/controller/StationGraphQLController.java index 59118fcc..8b7dcb01 100644 --- a/src/main/java/org/entur/lamassu/graphql/controller/StationGraphQLController.java +++ b/src/main/java/org/entur/lamassu/graphql/controller/StationGraphQLController.java @@ -3,9 +3,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; import org.entur.lamassu.cache.PricingPlanCache; import org.entur.lamassu.cache.StationCache; import org.entur.lamassu.cache.SystemCache; diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java index a0b7e21a..54437073 100644 --- a/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/EntityCachesUpdater.java @@ -68,7 +68,7 @@ public void updateEntityCaches( } if (canUpdatePricingPlans(delivery, feedProvider)) { - pricingPlansUpdater.update(delivery.systemPricingPlans(), feedProvider); + pricingPlansUpdater.update(delivery.systemPricingPlans()); } if (canUpdateRegions(delivery, feedProvider)) { diff --git a/src/main/java/org/entur/lamassu/leader/entityupdater/PricingPlansUpdater.java b/src/main/java/org/entur/lamassu/leader/entityupdater/PricingPlansUpdater.java index a43df9c3..0b36d3f3 100644 --- a/src/main/java/org/entur/lamassu/leader/entityupdater/PricingPlansUpdater.java +++ b/src/main/java/org/entur/lamassu/leader/entityupdater/PricingPlansUpdater.java @@ -24,8 +24,6 @@ import org.entur.lamassu.cache.PricingPlanCache; import org.entur.lamassu.mapper.entitymapper.PricingPlanMapper; import org.entur.lamassu.model.entities.PricingPlan; -import org.entur.lamassu.model.entities.VehicleType; -import org.entur.lamassu.model.provider.FeedProvider; import org.entur.lamassu.util.CacheUtil; import org.mobilitydata.gbfs.v3_0.system_pricing_plans.GBFSSystemPricingPlans; import org.springframework.stereotype.Component; @@ -44,10 +42,7 @@ public PricingPlansUpdater( this.pricingPlanMapper = pricingPlanMapper; } - public void update( - GBFSSystemPricingPlans gbfsSystemPricingPlans, - FeedProvider feedProvider - ) { + public void update(GBFSSystemPricingPlans gbfsSystemPricingPlans) { var mapped = gbfsSystemPricingPlans .getData() .getPlans() diff --git a/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java b/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java index 694fb826..53f5b809 100644 --- a/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java +++ b/src/main/java/org/entur/lamassu/mapper/entitymapper/RegionMapper.java @@ -18,20 +18,14 @@ package org.entur.lamassu.mapper.entitymapper; -import java.util.Optional; import org.entur.lamassu.model.entities.Region; import org.mobilitydata.gbfs.v3_0.system_regions.GBFSRegion; -import org.mobilitydata.gbfs.v3_0.system_regions.GBFSSystemRegions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class RegionMapper { - private static final Logger logger = LoggerFactory.getLogger(RegionMapper.class); - private final TranslationMapper translationMapper; @Autowired diff --git a/src/main/java/org/entur/lamassu/mapper/entitymapper/StationMapper.java b/src/main/java/org/entur/lamassu/mapper/entitymapper/StationMapper.java index 2e24a0de..a78c6b1d 100644 --- a/src/main/java/org/entur/lamassu/mapper/entitymapper/StationMapper.java +++ b/src/main/java/org/entur/lamassu/mapper/entitymapper/StationMapper.java @@ -26,11 +26,8 @@ import java.util.Optional; import org.entur.lamassu.model.entities.MultiPolygon; import org.entur.lamassu.model.entities.ParkingType; -import org.entur.lamassu.model.entities.PricingPlan; -import org.entur.lamassu.model.entities.Region; import org.entur.lamassu.model.entities.RentalMethod; import org.entur.lamassu.model.entities.Station; -import org.entur.lamassu.model.entities.System; import org.entur.lamassu.model.entities.VehicleDocksAvailability; import org.entur.lamassu.model.entities.VehicleDocksCapacity; import org.entur.lamassu.model.entities.VehicleTypeAvailability; @@ -44,10 +41,6 @@ import org.mobilitydata.gbfs.v3_0.station_information.GBFSVehicleTypesCapacity; import org.mobilitydata.gbfs.v3_0.station_status.GBFSVehicleDocksAvailable; import org.mobilitydata.gbfs.v3_0.station_status.GBFSVehicleTypesAvailable; -import org.mobilitydata.gbfs.v3_0.system_regions.GBFSSystemRegions; -import org.mobilitydata.gbfs.v3_0.vehicle_types.GBFSVehicleTypes; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleMapper.java b/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleMapper.java index 39c8aa57..a45f6129 100644 --- a/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleMapper.java +++ b/src/main/java/org/entur/lamassu/mapper/entitymapper/VehicleMapper.java @@ -19,11 +19,8 @@ package org.entur.lamassu.mapper.entitymapper; import java.util.List; -import org.entur.lamassu.model.entities.PricingPlan; -import org.entur.lamassu.model.entities.System; import org.entur.lamassu.model.entities.Vehicle; import org.entur.lamassu.model.entities.VehicleEquipment; -import org.entur.lamassu.model.entities.VehicleType; import org.mobilitydata.gbfs.v3_0.vehicle_status.GBFSVehicle; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; From 93ba1b8b428540078b0bd838d51838018555c424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Fri, 20 Dec 2024 16:17:31 +0100 Subject: [PATCH 8/9] Cleanup --- .../org/entur/lamassu/service/SpatialIndexService.java | 10 ++++------ .../entur/lamassu/util/TestSpatialIndexBuilder.java | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/entur/lamassu/service/SpatialIndexService.java b/src/main/java/org/entur/lamassu/service/SpatialIndexService.java index 93579106..8aa99c48 100644 --- a/src/main/java/org/entur/lamassu/service/SpatialIndexService.java +++ b/src/main/java/org/entur/lamassu/service/SpatialIndexService.java @@ -8,6 +8,7 @@ import org.entur.lamassu.model.entities.Station; import org.entur.lamassu.model.entities.Vehicle; import org.entur.lamassu.model.entities.VehicleType; +import org.entur.lamassu.model.entities.VehicleTypeAvailability; import org.entur.lamassu.model.provider.FeedProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -59,19 +60,16 @@ public StationSpatialIndexId createStationIndex( var vehicleTypeIds = station .getVehicleTypesAvailable() .stream() - .map(vta -> vta.getVehicleTypeId()) + .map(VehicleTypeAvailability::getVehicleTypeId) .collect(Collectors.toSet()); List vehicleTypes = vehicleTypeCache.getAll(vehicleTypeIds); id.setAvailableFormFactors( - vehicleTypes.stream().map(VehicleType::getFormFactor).collect(Collectors.toList()) + vehicleTypes.stream().map(VehicleType::getFormFactor).toList() ); id.setAvailablePropulsionTypes( - vehicleTypes - .stream() - .map(VehicleType::getPropulsionType) - .collect(Collectors.toList()) + vehicleTypes.stream().map(VehicleType::getPropulsionType).toList() ); } else { id.setAvailableFormFactors(List.of()); diff --git a/src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java b/src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java index 18ce6d56..e79a07bb 100644 --- a/src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java +++ b/src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java @@ -48,14 +48,14 @@ public static StationSpatialIndexId createStationIndex( .getVehicleTypesAvailable() .stream() .map(vta -> vta.getVehicleType().getFormFactor()) - .collect(Collectors.toList()) + .toList() ); id.setAvailablePropulsionTypes( station .getVehicleTypesAvailable() .stream() .map(vta -> vta.getVehicleType().getPropulsionType()) - .collect(Collectors.toList()) + .toList() ); } else { id.setAvailableFormFactors(List.of()); From 347b5ed0aa1d5ec0d463ed2c59e920d0c098053f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Fri, 20 Dec 2024 16:24:43 +0100 Subject: [PATCH 9/9] Cleanup --- .../java/org/entur/lamassu/util/TestSpatialIndexBuilder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java b/src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java index e79a07bb..d3f1ecb3 100644 --- a/src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java +++ b/src/test/java/org/entur/lamassu/util/TestSpatialIndexBuilder.java @@ -1,7 +1,6 @@ package org.entur.lamassu.util; import java.util.List; -import java.util.stream.Collectors; import org.entur.lamassu.cache.StationSpatialIndexId; import org.entur.lamassu.cache.VehicleSpatialIndexId; import org.entur.lamassu.model.entities.Station;