package org.juxtapose.streamline.stm; import java.util.Collections; import java.util.HashMap; import java.util.Set; import org.juxtapose.streamline.producer.ISTMEntryKey; import org.juxtapose.streamline.producer.ISTMEntryProducer; import org.juxtapose.streamline.producer.executor.IExecutor; import org.juxtapose.streamline.tools.DataConstants; import org.juxtapose.streamline.util.ISTMEntrySubscriber; import org.juxtapose.streamline.util.ISTMEntry; import org.juxtapose.streamline.util.PersistentArrayList; import org.juxtapose.streamline.util.Status; import org.juxtapose.streamline.util.data.DataType; import org.juxtapose.streamline.util.data.DataTypeNull; import org.juxtapose.streamline.util.data.DataTypeRef; import com.trifork.clj_ds.IPersistentMap; /** * @author Pontus J�rgne * 28 jun 2011 * Copyright (c) Pontus J�rgne. All rights reserved * * This class belongs to the the STM. PublishedData is an STM entry * only STM may create or modify a PublishedData on pub/sub requests * */ final class STMEntry implements ISTMEntry { final IPersistentMap<String, DataType<?>> dataMap; final Set<String> deltaSet; final PersistentArrayList<ISTMEntrySubscriber> lowPrioSubscribers; final PersistentArrayList<ISTMEntrySubscriber> highPrioSubscribers; final ISTMEntryProducer producer; final long sequenceID; final boolean completeVersion; /** * @param inData * @param inLastUpdate * @param inSubscribers * @param inProducer * @param inStatus */ protected STMEntry( IPersistentMap<String, DataType<?>> inData, Set<String> inChanges, PersistentArrayList<ISTMEntrySubscriber> inLowPrioSubscribers, PersistentArrayList<ISTMEntrySubscriber> inHighPrioSubscribers, ISTMEntryProducer inProducer, long inSequenceID, boolean inCompleteUpdate ) { dataMap = inData; deltaSet = Collections.unmodifiableSet( inChanges ); lowPrioSubscribers = inLowPrioSubscribers; highPrioSubscribers = inHighPrioSubscribers; producer = inProducer; sequenceID = inSequenceID; completeVersion = inCompleteUpdate; } public void updateSubscribers( ISTMEntryKey inKey, boolean inFullUpdate ) { for( int i = 0; i < highPrioSubscribers.size(); i++ ) { ISTMEntrySubscriber subscriber = highPrioSubscribers.get( i ); subscriber.updateData( inKey, this, inFullUpdate ); } for( int i = 0; i < lowPrioSubscribers.size(); i++ ) { ISTMEntrySubscriber subscriber = lowPrioSubscribers.get( i ); subscriber.updateData( inKey, this, inFullUpdate ); } } /** * @param inSubscriber * @return */ public ISTMEntry addSubscriber( ISTMEntrySubscriber inSubscriber ) { if( inSubscriber.getPriority() == IExecutor.HIGH ) { PersistentArrayList<ISTMEntrySubscriber> newSub = highPrioSubscribers.add( inSubscriber ); return new STMEntry( dataMap, deltaSet, lowPrioSubscribers, newSub, producer, sequenceID, completeVersion ); } else { PersistentArrayList<ISTMEntrySubscriber> newSub = lowPrioSubscribers.add( inSubscriber ); return new STMEntry( dataMap, deltaSet, newSub, highPrioSubscribers, producer, sequenceID, completeVersion ); } } /** * @param inSubscriber * @return */ public ISTMEntry removeSubscriber( ISTMEntrySubscriber inSubscriber ) { if( inSubscriber.getPriority() == IExecutor.HIGH ) { PersistentArrayList<ISTMEntrySubscriber> newSub = highPrioSubscribers.remove( inSubscriber ); return new STMEntry( dataMap, deltaSet, lowPrioSubscribers, newSub, producer, sequenceID, completeVersion ); } else { PersistentArrayList<ISTMEntrySubscriber> newSub = lowPrioSubscribers.remove( inSubscriber ); return new STMEntry( dataMap, deltaSet, newSub, highPrioSubscribers, producer, sequenceID, completeVersion ); } } /** * @return */ public boolean hasSubscribers() { return lowPrioSubscribers.size() > 0 || highPrioSubscribers.size() > 0; } /** * @param inKey * @param inValue * @return * @throws Exception */ public ISTMEntry putDataValue( String inKey, DataType<?> inValue )throws Exception { IPersistentMap<String, DataType<?>> newMap; if( inValue instanceof DataTypeNull ) newMap = dataMap.without( inKey ); else newMap = dataMap.assoc( inKey, inValue ); return new STMEntry( newMap, deltaSet, lowPrioSubscribers, highPrioSubscribers, producer, sequenceID+1, completeVersion ); } /** * @param inStateTransitionMap * @return * @throws Exception */ public ISTMEntry putDataValues( HashMap<String, DataType<?>> inStateTransitionMap )throws Exception { IPersistentMap<String, DataType<?>> newDataMap = dataMap; for( String key : inStateTransitionMap.keySet() ) { DataType<?> value = inStateTransitionMap.get( key ); if( value instanceof DataTypeNull ) newDataMap = newDataMap.without( key ); else if( value instanceof DataTypeRef ) { newDataMap = newDataMap.assoc( key, value ); } else { newDataMap = newDataMap.assoc( key, value ); } } return new STMEntry( newDataMap, deltaSet, lowPrioSubscribers, highPrioSubscribers, producer, sequenceID+1, completeVersion ); } /** * @param inDataMap * @return */ public ISTMEntry setDataMap( IPersistentMap<String, DataType<?>> inDataMap ) { return new STMEntry( inDataMap, deltaSet, lowPrioSubscribers, highPrioSubscribers, producer, sequenceID+1, completeVersion ); } /** * @param inDataMap * @return */ public ISTMEntry setUpdatedData( IPersistentMap<String, DataType<?>> inDataMap, Set<String> inDelta, boolean inCompleteUpdate ) { return new STMEntry( inDataMap, inDelta, lowPrioSubscribers, highPrioSubscribers, producer, (inCompleteUpdate ? sequenceID+1 : sequenceID), inCompleteUpdate ); } public boolean isCompleteVersion() { return completeVersion; } /** * @return */ public IPersistentMap<String, DataType<?>> getDataMap() { return dataMap; } /** * @return */ public Set<String> getDeltaSet() { return deltaSet; } public ISTMEntryProducer getProducer() { return producer; } /** * @param inKey * @return */ public DataType<?> getValue( String inKey ) { return dataMap.valAt( inKey ); } @Override public boolean isDeltaValue(String inKey) { return deltaSet.contains( inKey ); } public Status getStatus() { return (Status)dataMap.valAt( DataConstants.FIELD_STATUS ).get(); } public long getSequenceID() { return sequenceID; } public int getHighPriosubscriberCount() { return highPrioSubscribers.size(); } public int getPriority() { return highPrioSubscribers.size() > 0 ? IExecutor.HIGH : IExecutor.LOW; } /* (non-Javadoc) * @see org.juxtapose.streamline.util.ISTMEntry#changeSubscriberPriority(org.juxtapose.streamline.util.ISTMEntrySubscriber, int) * this method will return null if the subscriber is not contained within the anticipated list. */ @Override public ISTMEntry changeSubscriberPriority( ISTMEntrySubscriber inSubscriber, int inNewPriority ) { if( inNewPriority == IExecutor.HIGH ) { PersistentArrayList<ISTMEntrySubscriber> newLowPrioSubscribers = lowPrioSubscribers.remove( inSubscriber ); if( newLowPrioSubscribers == lowPrioSubscribers ) { return null; } PersistentArrayList<ISTMEntrySubscriber> newHighPrioSubscribers = highPrioSubscribers.add( inSubscriber ); return new STMEntry( dataMap, deltaSet, newLowPrioSubscribers, newHighPrioSubscribers, producer, sequenceID, completeVersion ); } else if( inNewPriority == IExecutor.LOW ) { PersistentArrayList<ISTMEntrySubscriber> newHighPrioSubscribers = highPrioSubscribers.remove( inSubscriber ); if( newHighPrioSubscribers == highPrioSubscribers ) { return null; } PersistentArrayList<ISTMEntrySubscriber> newLowPrioSubscribers = lowPrioSubscribers.add( inSubscriber ); return new STMEntry( dataMap, deltaSet, newLowPrioSubscribers, newHighPrioSubscribers, producer, sequenceID, completeVersion ); } else { return this; } } @Override public DataType<?> getUpdatedValue( String inKey ) { if( deltaSet.contains( inKey )) return getValue( inKey ); return null; } public String toString() { return "version: "+sequenceID+" "+dataMap+" delta: "+deltaSet; } }