package ilarkesto.gwt.server; import ilarkesto.base.PermissionDeniedException; import ilarkesto.base.Sys; import ilarkesto.base.Utl; import ilarkesto.base.time.DateAndTime; import ilarkesto.base.time.TimePeriod; import ilarkesto.core.logging.Log; import ilarkesto.gwt.client.ADataTransferObject; import ilarkesto.persistence.AEntity; import ilarkesto.webapp.AWebSession; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; public abstract class AGwtConversation { private static final Log LOG = Log.get(AGwtConversation.class); private static final TimePeriod DEFAULT_TIMEOUT = TimePeriod.minutes(2); /** * Data that will be transferred to the client at the next request. */ private ADataTransferObject nextData; private Map<AEntity, DateAndTime> remoteEntityModificationTimes = new HashMap<AEntity, DateAndTime>(); private AWebSession session; private int number; private DateAndTime lastTouched; protected abstract ADataTransferObject createDataTransferObject(); public AGwtConversation(AWebSession session, int number) { super(); this.session = session; this.number = number; nextData = createDataTransferObject(); if (nextData != null) { nextData.developmentMode = Sys.isDevelopmentMode(); nextData.entityIdBase = UUID.randomUUID().toString(); nextData.conversationNumber = number; } touch(); } public int getNumber() { return number; } public final void clearRemoteEntities() { remoteEntityModificationTimes.clear(); } public final void clearRemoteEntitiesByType(Class<? extends AEntity> type) { List<AEntity> toRemove = new ArrayList<AEntity>(); for (AEntity entity : remoteEntityModificationTimes.keySet()) { if (entity.getClass().equals(type)) toRemove.add(entity); } for (AEntity entity : toRemove) { remoteEntityModificationTimes.remove(entity); } } protected boolean isEntityVisible(AEntity entity) { return true; } protected void filterEntityProperties(AEntity entity, Map propertiesMap) {} public synchronized boolean isAvailableOnClient(AEntity entity) { return remoteEntityModificationTimes.containsKey(entity); } public synchronized void sendToClient(AEntity entity) { if (entity == null) return; if (!isEntityVisible(entity)) throw new PermissionDeniedException(entity + " is not visible"); DateAndTime timeRemote = remoteEntityModificationTimes.get(entity); DateAndTime timeLocal = entity.getLastModified(); if (timeLocal.equals(timeRemote)) { LOG.debug("Remote entity already up to date:", Utl.toStringWithType(entity), "for", this); return; } Map propertiesMap = entity.createPropertiesMap(); filterEntityProperties(entity, propertiesMap); getNextData().addEntity(propertiesMap); remoteEntityModificationTimes.put(entity, timeLocal); LOG.debug("Sending", Utl.toStringWithType(entity), "to", this); } public final void sendToClient(Collection<? extends AEntity> entities) { if (entities == null) return; for (AEntity entity : entities) sendToClient(entity); } public final ADataTransferObject popNextData() { if (nextData == null) return null; synchronized (nextData) { ADataTransferObject ret = nextData; nextData = createDataTransferObject(); return ret; } } public ADataTransferObject getNextData() { return nextData; } public AWebSession getSession() { return session; } public final void touch() { lastTouched = DateAndTime.now(); } protected TimePeriod getTimeout() { return DEFAULT_TIMEOUT; } public final boolean isTimeouted() { return lastTouched.getPeriodToNow().isGreaterThen(getTimeout()); } public final DateAndTime getLastTouched() { return lastTouched; } public void invalidate() {} @Override public String toString() { return "#" + number + "@" + getSession(); } }