/** * Ctor. * * @param revisionEventTypeName name * @param spec specification * @param statementStopService for stop handling * @param eventAdapterService for nested property handling */ public VAERevisionProcessorDeclared( String revisionEventTypeName, RevisionSpec spec, StatementStopService statementStopService, EventAdapterService eventAdapterService, EventTypeIdGenerator eventTypeIdGenerator) { super(spec, revisionEventTypeName, eventAdapterService); // on statement stop, remove versions statementStopService.addSubscriber( new StatementStopCallback() { public void statementStopped() { statePerKey.clear(); } }); this.statePerKey = new HashMap<MultiKeyUntyped, RevisionStateDeclared>(); this.baseEventType = spec.getBaseEventType(); this.fullKeyGetters = PropertyUtility.getGetters(baseEventType, spec.getKeyPropertyNames()); // sort non-key properties, removing keys groups = PropertyUtility.analyzeGroups( spec.getChangesetPropertyNames(), spec.getDeltaTypes(), spec.getDeltaNames()); Map<String, RevisionPropertyTypeDesc> propertyDesc = createPropertyDescriptors(spec, groups); typeDescriptors = PropertyUtility.getPerType( groups, spec.getChangesetPropertyNames(), spec.getKeyPropertyNames()); EventTypeMetadata metadata = EventTypeMetadata.createValueAdd( revisionEventTypeName, EventTypeMetadata.TypeClass.REVISION); revisionEventType = new RevisionEventType( metadata, eventTypeIdGenerator.getTypeId(revisionEventTypeName), propertyDesc, eventAdapterService); }
public void onUpdate( EventBean[] newData, EventBean[] oldData, NamedWindowRootView namedWindowRootView, NamedWindowIndexRepository indexRepository) { // If new data is filled, it is not a delete if ((newData == null) || (newData.length == 0)) { // we are removing an event RevisionEventBeanDeclared revisionEvent = (RevisionEventBeanDeclared) oldData[0]; MultiKeyUntyped key = revisionEvent.getKey(); statePerKey.remove(key); // Insert into indexes for fast deletion, if there are any for (EventTable table : indexRepository.getTables()) { table.remove(oldData); } // make as not the latest event since its due for removal revisionEvent.setLatest(false); namedWindowRootView.updateChildren(null, oldData); return; } RevisionEventBeanDeclared revisionEvent = (RevisionEventBeanDeclared) newData[0]; EventBean underlyingEvent = revisionEvent.getUnderlyingFullOrDelta(); EventType underyingEventType = underlyingEvent.getEventType(); // obtain key values MultiKeyUntyped key = null; RevisionTypeDesc typesDesc = null; boolean isBaseEventType = false; if (underyingEventType == baseEventType) { key = PropertyUtility.getKeys(underlyingEvent, fullKeyGetters); isBaseEventType = true; } else { typesDesc = typeDescriptors.get(underyingEventType); // if this type cannot be found, check all supertypes, if any if (typesDesc == null) { Iterator<EventType> superTypes = underyingEventType.getDeepSuperTypes(); if (superTypes != null) { EventType superType; for (; superTypes.hasNext(); ) { superType = superTypes.next(); if (superType == baseEventType) { key = PropertyUtility.getKeys(underlyingEvent, fullKeyGetters); isBaseEventType = true; break; } typesDesc = typeDescriptors.get(superType); if (typesDesc != null) { typeDescriptors.put(underyingEventType, typesDesc); key = PropertyUtility.getKeys(underlyingEvent, typesDesc.getKeyPropertyGetters()); break; } } } } else { key = PropertyUtility.getKeys(underlyingEvent, typesDesc.getKeyPropertyGetters()); } if (key == null) { log.warn( "Ignoring event of event type '" + underyingEventType + "' for revision processing type '" + revisionEventTypeName); return; } } // get the state for this key value RevisionStateDeclared revisionState = statePerKey.get(key); // Delta event and no full if ((!isBaseEventType) && (revisionState == null)) { return; // Ignore the event, its a delta and we don't currently have a full event for it } // New full event if (revisionState == null) { revisionState = new RevisionStateDeclared(underlyingEvent, null, null); statePerKey.put(key, revisionState); // prepare revison event revisionEvent.setLastBaseEvent(underlyingEvent); revisionEvent.setKey(key); revisionEvent.setHolders(null); revisionEvent.setLatest(true); // Insert into indexes for fast deletion, if there are any for (EventTable table : indexRepository.getTables()) { table.add(newData); } // post to data window revisionState.setLastEvent(revisionEvent); namedWindowRootView.updateChildren(new EventBean[] {revisionEvent}, null); return; } // new version long versionNumber = revisionState.incRevisionNumber(); // Previously-seen full event if (isBaseEventType) { revisionState.setHolders(null); revisionState.setBaseEventUnderlying(underlyingEvent); } // Delta event to existing full event else { int groupNum = typesDesc.getGroup().getGroupNum(); RevisionBeanHolder[] holders = revisionState.getHolders(); if (holders == null) // optimization - the full event sets it to null, deltas all get a new one { holders = new RevisionBeanHolder[groups.length]; } else { holders = arrayCopy(holders); // preserve the last revisions } // add the new revision for a property group on top holders[groupNum] = new RevisionBeanHolder( versionNumber, underlyingEvent, typesDesc.getChangesetPropertyGetters()); revisionState.setHolders(holders); } // prepare revision event revisionEvent.setLastBaseEvent(revisionState.getBaseEventUnderlying()); revisionEvent.setHolders(revisionState.getHolders()); revisionEvent.setKey(key); revisionEvent.setLatest(true); // get prior event RevisionEventBeanDeclared lastEvent = revisionState.getLastEvent(); lastEvent.setLatest(false); // data to post EventBean[] newDataPost = new EventBean[] {revisionEvent}; EventBean[] oldDataPost = new EventBean[] {lastEvent}; // update indexes for (EventTable table : indexRepository.getTables()) { table.remove(oldDataPost); table.add(newDataPost); } // keep reference to last event revisionState.setLastEvent(revisionEvent); namedWindowRootView.updateChildren(newDataPost, oldDataPost); }
/** * Creates property descriptors for revision. * * @param spec specifies revision * @param groups the groups that group properties * @return map of property and descriptor */ public static Map<String, RevisionPropertyTypeDesc> createPropertyDescriptors( RevisionSpec spec, PropertyGroupDesc groups[]) { Map<String, int[]> propsPerGroup = PropertyUtility.getGroupsPerProperty(groups); Map<String, RevisionPropertyTypeDesc> propertyDesc = new HashMap<String, RevisionPropertyTypeDesc>(); int count = 0; for (String property : spec.getChangesetPropertyNames()) { EventPropertyGetter fullGetter = spec.getBaseEventType().getGetter(property); int propertyNumber = count; int[] propGroupsProperty = propsPerGroup.get(property); final RevisionGetterParameters params = new RevisionGetterParameters(property, propertyNumber, fullGetter, propGroupsProperty); // if there are no groups (full event property only), then simply use the full event getter EventPropertyGetter revisionGetter = new EventPropertyGetter() { public Object get(EventBean eventBean) throws PropertyAccessException { RevisionEventBeanDeclared riv = (RevisionEventBeanDeclared) eventBean; return riv.getVersionedValue(params); } public boolean isExistsProperty(EventBean eventBean) { return true; } public Object getFragment(EventBean eventBean) { return null; // fragments no provided by revision events } }; Class type = spec.getBaseEventType().getPropertyType(property); RevisionPropertyTypeDesc propertyTypeDesc = new RevisionPropertyTypeDesc(revisionGetter, params, type); propertyDesc.put(property, propertyTypeDesc); count++; } for (String property : spec.getBaseEventOnlyPropertyNames()) { final EventPropertyGetter fullGetter = spec.getBaseEventType().getGetter(property); // if there are no groups (full event property only), then simply use the full event getter EventPropertyGetter revisionGetter = new EventPropertyGetter() { public Object get(EventBean eventBean) throws PropertyAccessException { RevisionEventBeanDeclared riv = (RevisionEventBeanDeclared) eventBean; return fullGetter.get(riv.getLastBaseEvent()); } public boolean isExistsProperty(EventBean eventBean) { return true; } public Object getFragment(EventBean eventBean) { return null; // fragments no provided by revision events } }; Class type = spec.getBaseEventType().getPropertyType(property); RevisionPropertyTypeDesc propertyTypeDesc = new RevisionPropertyTypeDesc(revisionGetter, null, type); propertyDesc.put(property, propertyTypeDesc); count++; } count = 0; for (String property : spec.getKeyPropertyNames()) { final int keyPropertyNumber = count; EventPropertyGetter revisionGetter = new EventPropertyGetter() { public Object get(EventBean eventBean) throws PropertyAccessException { RevisionEventBeanDeclared riv = (RevisionEventBeanDeclared) eventBean; return riv.getKey().getKeys()[keyPropertyNumber]; } public boolean isExistsProperty(EventBean eventBean) { return true; } public Object getFragment(EventBean eventBean) { return null; } }; Class type = spec.getBaseEventType().getPropertyType(property); RevisionPropertyTypeDesc propertyTypeDesc = new RevisionPropertyTypeDesc(revisionGetter, null, type); propertyDesc.put(property, propertyTypeDesc); count++; } return propertyDesc; }