Skip to content

Commit

Permalink
Speed up data space transfer by introducing separate ObjectReference …
Browse files Browse the repository at this point in the history
…objects to create cleaner separation between entities in referential schemas and public schema. This allows skipping loading of stop areas when only reference is needed
  • Loading branch information
erlendnils1 committed Oct 2, 2017
1 parent e00aaa2 commit 45b9434
Show file tree
Hide file tree
Showing 55 changed files with 500 additions and 366 deletions.
@@ -1,114 +1,155 @@
package mobi.chouette.dao.interceptor;

import java.io.Serializable;

import javax.enterprise.inject.spi.CDI;

import lombok.extern.log4j.Log4j;
import mobi.chouette.dao.StopAreaDAO;
import mobi.chouette.model.ObjectReference;
import mobi.chouette.model.RouteSection;
import mobi.chouette.model.ScheduledStopPoint;
import mobi.chouette.model.StopArea;
import mobi.chouette.model.StopPoint;

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;

import javax.enterprise.inject.spi.CDI;

import java.io.Serializable;

/**
* StopPoint and RouteSections reside in separate schemas from StopArea. This Interceptor enriches these entities with relations between them upon load.
*/
@Log4j
public class RelationsToStopAreaInterceptor extends EmptyInterceptor {

private StopAreaDAO stopAreaDAO;

private static final String STOP_POINT_CONTAINED_IN_STOP_AREA_ID_PROPERTY = "containedInStopAreaObjectId";
private static final String DEPARTURE_STOP_AREA_ID_PROPERTY = "departureStopAreaObjectId";

private static final String ARRIVAL_STOP_AREA_ID_PROPERTY = "arrivalStopAreaObjectId";

@Override
public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
init();

if (entity instanceof ScheduledStopPoint) {

loadStopAreasForScheduledStopPoint((ScheduledStopPoint) entity, state, propertyNames);

} else if (entity instanceof RouteSection) {

loadStopAreasForRouteSections((RouteSection) entity, state, propertyNames);
}
return super.onLoad(entity, id, state, propertyNames, types);
}

private void loadStopAreasForScheduledStopPoint(ScheduledStopPoint entity, Object[] state, String[] propertyNames) {
ScheduledStopPoint scheduledStopPoint = entity;
log.trace("On load StopPoint id: " + scheduledStopPoint.getId());
String containedInStopAreaId = getProperty(STOP_POINT_CONTAINED_IN_STOP_AREA_ID_PROPERTY, propertyNames, state);

if (scheduledStopPoint.getContainedInStopArea() == null && containedInStopAreaId != null) {
scheduledStopPoint.setContainedInStopAreaORMOnly(stopAreaDAO.findByObjectId(containedInStopAreaId));
}
}

private void loadStopAreasForRouteSections(RouteSection entity, Object[] state, String[] propertyNames) {
RouteSection routeSection = entity;
log.trace("On load RouteSection id: " + routeSection.getId());

String arrivalStopAreaId = getProperty(ARRIVAL_STOP_AREA_ID_PROPERTY, propertyNames, state);
if (entity.getArrival() == null && arrivalStopAreaId != null) {
routeSection.setArrival(stopAreaDAO.findByObjectId(arrivalStopAreaId));
}

String departureStopAreaId = getProperty(DEPARTURE_STOP_AREA_ID_PROPERTY, propertyNames, state);
if (entity.getDeparture() == null && departureStopAreaId != null) {
routeSection.setDeparture(stopAreaDAO.findByObjectId(departureStopAreaId));
}
}

@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
onCreateOrUpdate(entity);
return super.onSave(entity, id, state, propertyNames, types);
}

@Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
onCreateOrUpdate(entity);
return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);
}

private void onCreateOrUpdate(Object entity) {
init();

if (entity instanceof ScheduledStopPoint) {
ScheduledStopPoint scheduledStopPoint = ((ScheduledStopPoint) entity);
StopArea stopArea = scheduledStopPoint.getContainedInStopArea();
if (stopArea != null) {
if (stopArea.getId() == null && !stopArea.isDetached() && stopArea.getImportMode().shouldCreateMissingStopAreas()) {
log.debug("Cascading persist of new stop area +" + stopArea.getObjectId() + "+ for created/updated stop point: " + scheduledStopPoint.getObjectId());
stopAreaDAO.create(stopArea);
}
}

}
}


private <T> T getProperty(String propertyName, String[] propertyNames, Object[] state) {
for (int i = 0; i < propertyNames.length; i++) {
if (propertyName.equals(propertyNames[i])) {
return (T) state[i];
}
}
throw new RuntimeException("Property not found: " + propertyName);
}


private void init() {
if (stopAreaDAO == null) {
stopAreaDAO = CDI.current().select(StopAreaDAO.class).get();
}
}
private StopAreaDAO stopAreaDAO;

private static final String STOP_POINT_CONTAINED_IN_STOP_AREA_ID_PROPERTY = "containedInStopAreaObjectId";
private static final String DEPARTURE_STOP_AREA_ID_PROPERTY = "departureStopAreaObjectId";

private static final String ARRIVAL_STOP_AREA_ID_PROPERTY = "arrivalStopAreaObjectId";

@Override
public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
init();

if (entity instanceof ScheduledStopPoint) {

loadStopAreasForScheduledStopPoint((ScheduledStopPoint) entity, state, propertyNames);

} else if (entity instanceof RouteSection) {

loadStopAreasForRouteSections((RouteSection) entity, state, propertyNames);
}
return super.onLoad(entity, id, state, propertyNames, types);
}

private void loadStopAreasForScheduledStopPoint(ScheduledStopPoint entity, Object[] state, String[] propertyNames) {
ScheduledStopPoint scheduledStopPoint = entity;
log.trace("On load StopPoint id: " + scheduledStopPoint.getId());
String containedInStopAreaId = getProperty(STOP_POINT_CONTAINED_IN_STOP_AREA_ID_PROPERTY, propertyNames, state);

if (!(scheduledStopPoint.getContainedInStopAreaRef() instanceof LazyLoadingStopAreaReference)) {
scheduledStopPoint.setContainedInStopAreaRef(new LazyLoadingStopAreaReference(containedInStopAreaId));
}
}

private void loadStopAreasForRouteSections(RouteSection entity, Object[] state, String[] propertyNames) {
RouteSection routeSection = entity;
log.trace("On load RouteSection id: " + routeSection.getId());

String arrivalStopAreaId = getProperty(ARRIVAL_STOP_AREA_ID_PROPERTY, propertyNames, state);
if (!(entity.getArrivalRef() instanceof LazyLoadingStopAreaReference)) {
routeSection.setArrivalRef(new LazyLoadingStopAreaReference(arrivalStopAreaId));
}

String departureStopAreaId = getProperty(DEPARTURE_STOP_AREA_ID_PROPERTY, propertyNames, state);
if (!(entity.getDepartureRef() instanceof LazyLoadingStopAreaReference)) {
routeSection.setDepartureRef(new LazyLoadingStopAreaReference(departureStopAreaId));
}
}


@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
onCreateOrUpdate(entity);
return super.onSave(entity, id, state, propertyNames, types);
}

@Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
onCreateOrUpdate(entity);
return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);
}

private void onCreateOrUpdate(Object entity) {
init();

if (entity instanceof ScheduledStopPoint) {
ScheduledStopPoint scheduledStopPoint = ((ScheduledStopPoint) entity);
if (scheduledStopPoint.getContainedInStopAreaRef().isLoaded()) {
StopArea stopArea = scheduledStopPoint.getContainedInStopAreaRef().getObject();
if (stopArea != null && stopArea.getId() == null && !stopArea.isDetached() && stopArea.getImportMode().shouldCreateMissingStopAreas()) {
log.debug("Cascading persist of new stop area " + stopArea.getObjectId() + " for created/updated stop point: " + scheduledStopPoint.getObjectId());
stopAreaDAO.create(stopArea);
}
}

}
}


private <T> T getProperty(String propertyName, String[] propertyNames, Object[] state) {
for (int i = 0; i < propertyNames.length; i++) {
if (propertyName.equals(propertyNames[i])) {
return (T) state[i];
}
}
throw new RuntimeException("Property not found: " + propertyName);
}


private void init() {
if (stopAreaDAO == null) {
stopAreaDAO = CDI.current().select(StopAreaDAO.class).get();
}
}

private class LazyLoadingStopAreaReference implements ObjectReference<StopArea> {

private String stopAreaObjectId;

private StopArea target;

private boolean loaded;

public LazyLoadingStopAreaReference(String stopAreaObjectId) {
this.stopAreaObjectId = stopAreaObjectId;
}

@Override
public String getObjectId() {
return stopAreaObjectId;
}

@Override
public StopArea getObject() {
if (!loaded){
setTarget();
}
return target;
}

@Override
public boolean isLoaded() {
return loaded;
}

private synchronized void setTarget() {
if (!loaded) {
if (stopAreaObjectId != null) {
target = stopAreaDAO.findByObjectId(stopAreaObjectId);
}
loaded = true;
}
}
}
}
@@ -1,5 +1,6 @@
package mobi.chouette.dao;

import mobi.chouette.model.SimpleObjectReference;
import mobi.chouette.model.StopArea;
import mobi.chouette.model.ScheduledStopPoint;
import mobi.chouette.model.type.ChouetteAreaEnum;
Expand Down Expand Up @@ -51,14 +52,14 @@ public void stopAreasArePersistedWhenScheduledStopPointsArePersistedAndPopulated
stopArea.setAreaType(ChouetteAreaEnum.BoardingPosition);
stopArea.setObjectId("StopArea:ID");

scheduledStopPoint.setContainedInStopArea(stopArea);
scheduledStopPoint.setContainedInStopAreaRef(new SimpleObjectReference(stopArea));

ContextHolder.setContext("chouette_gui"); // set tenant schema
scheduledStopPointDAO.create(scheduledStopPoint);

ScheduledStopPoint dbScheduledStopPoint = scheduledStopPointDAO.findByObjectId(scheduledStopPoint.getObjectId());

Assert.assertEquals(dbScheduledStopPoint.getContainedInStopArea().getObjectId(), stopArea.getObjectId());
Assert.assertEquals(dbScheduledStopPoint.getContainedInStopAreaRef().getObjectId(), stopArea.getObjectId());

StopArea dbStopArea = stopAreaDAO.findByObjectId(stopArea.getObjectId());

Expand Down
Expand Up @@ -8,6 +8,7 @@
import javax.ejb.EJB;

import mobi.chouette.model.ScheduledStopPoint;
import mobi.chouette.model.SimpleObjectReference;
import mobi.chouette.model.StopArea;
import mobi.chouette.model.StopPoint;
import mobi.chouette.model.type.StopAreaImportModeEnum;
Expand Down Expand Up @@ -118,7 +119,7 @@ public void testGetAllStopAreaObjectIds() {
private ScheduledStopPoint createScheduledStopPoint(String id, StopArea stopArea) {
ScheduledStopPoint sp = new ScheduledStopPoint();
sp.setObjectId(id);
sp.setContainedInStopArea(stopArea);
sp.setContainedInStopAreaRef(new SimpleObjectReference(stopArea));
scheduledStopPointDAO.create(sp);
return sp;
}
Expand Down
Expand Up @@ -161,15 +161,15 @@ public boolean execute(Context context) throws Exception {
// log.info("[DSU] processing : "
// + routeSection.getObjectId());

StopArea departure = routeSection.getDeparture();
StopArea departure = routeSection.getDeparture().getObject();

if (departure != null && departure.hasCoordinates()) {
createPhysicaStop(shared, keys, departure);
MetaData.updateBoundingBox(context, departure.getLongitude().doubleValue(),
departure.getLatitude().doubleValue());
}

StopArea arrival = routeSection.getArrival();
StopArea arrival = routeSection.getArrival().getObject();
if (arrival != null && arrival.hasCoordinates()) {
createPhysicaStop(shared, keys, arrival);
MetaData.updateBoundingBox(context, arrival.getLongitude().doubleValue(), arrival
Expand Down
Expand Up @@ -53,10 +53,10 @@ public boolean save(ConnectionLink neptuneObject, String prefix, boolean keepOri

public boolean save(Interchange neptuneObject, String prefix, boolean keepOriginalId) {
transfer.clear();
transfer.setFromStopId(toGtfsId(neptuneObject.getFeederStopPoint().getContainedInStopArea()
transfer.setFromStopId(toGtfsId(neptuneObject.getFeederStopPoint().getContainedInStopAreaRef()
.getObjectId(), prefix, keepOriginalId));
transfer
.setToStopId(toGtfsId(neptuneObject.getConsumerStopPoint().getContainedInStopArea().getObjectId(), prefix, keepOriginalId));
.setToStopId(toGtfsId(neptuneObject.getConsumerStopPoint().getContainedInStopAreaRef().getObjectId(), prefix, keepOriginalId));

if (Boolean.TRUE.equals(neptuneObject.getGuaranteed())) {
transfer.setTransferType(GtfsTransfer.TransferType.Timed);
Expand Down
Expand Up @@ -84,8 +84,8 @@ private boolean saveTimes(VehicleJourney vj, String prefix, String sharedPrefix,
int index = 0;
for (VehicleJourneyAtStop vjas : lvjas) {

if (vjas.getStopPoint().getScheduledStopPoint().getContainedInStopArea()!=null){
time.setStopId(toGtfsId(vjas.getStopPoint().getScheduledStopPoint().getContainedInStopArea().getObjectId(), sharedPrefix, keepOriginalId));
if (vjas.getStopPoint().getScheduledStopPoint().getContainedInStopAreaRef().getObject() != null) {
time.setStopId(toGtfsId(vjas.getStopPoint().getScheduledStopPoint().getContainedInStopAreaRef().getObjectId(), sharedPrefix, keepOriginalId));
}

LocalTime arrival = vjas.getArrivalTime();
Expand Down Expand Up @@ -251,7 +251,7 @@ private PickupType toPickUpType(BoardingPossibilityEnum forBoarding, PickupType
public boolean save(VehicleJourney vj, String serviceId, String prefix, String sharedPrefix, boolean keepOriginalId) {

time.setStopHeadsign(null); // Clear between each journey

String tripId = toGtfsId(vj.getObjectId(), prefix, keepOriginalId);

trip.setTripId(tripId);
Expand Down

0 comments on commit 45b9434

Please sign in to comment.