copy = newCopyInstance(this); if (this.id==null){ getId(); copy.id = this.getId(); this.visitAttributesDualFlat(copy, (name, thisAttribute, copyAttribute) -> { thisAttribute.internal_copyToUnsafe(copyAttribute,(data)->{ if (data==null){ return null; return data.copyDeep(level + 1, maxLevel,oldData,this,root); }); copy.addParent(parent.copy);
private boolean referenceEquals(Data ref1, Data ref2) { if (ref1 == null && ref2 == null) { return true; } if (ref1 == null || ref2 == null) { return false; } return ref1.idEquals(ref2); }
/** * see: {@link Data#addBackReferences} * @param <T> type * @return usableCopy */ @SuppressWarnings("unchecked") public <T extends Data> T addBackReferences() { if (!this.data.hasBackReferencesFlat()){ this.data.addBackReferences(); } return (T)data; }
/** * -fix all data with same id should be same object * -remove parents that are no not tin the tree * only call on root * */ public void fixDuplicatesAndAddBackReferences() { data.assertRoot(); List<Data> dataList = this.data.fixDuplicateObjects(); for (Data data : dataList) { data.resetBackReferencesFlat(); } this.data.addBackReferences(); }
private void addBackReferences(final Data root, final Data parent, long dataIterationRun){ addParent(parent); this.root=root; getDataDictionary().addBackReferencesToAttributes(this,root); this.visitDataChildrenFlat(data -> data.addBackReferences(root, Data.this,dataIterationRun),dataIterationRun); }
private Set<Data> getChangedFactories(R previousFactoryCopyRoot){ //one might think that the merger could do the change detection but that don't work for views and separation of concern is better anyway final HashSet<Data> result = new HashSet<>(); final HashMap<String, FactoryBase<?, ?,?>> previousFactories = previousFactoryCopyRoot.internalFactory().collectChildFactoriesDeepMapFromRoot(); for (Data data: currentFactoryRoot.collectChildFactories()){ final FactoryBase<?, ?,?> previousFactory = previousFactories.get(data.getId()); if (previousFactory!=null){ data.internal().visitAttributesDualFlat(previousFactory, (name, currentAttribute, previousAttribute) -> { if (!(currentAttribute instanceof DataViewReferenceAttribute) && !(currentAttribute instanceof DataViewListReferenceAttribute)){//Data views have no function no need to check if (!currentAttribute.internal_mergeMatch(previousAttribute)){ result.add(data); } } }); } } return result; }
sortButton.setOnAction(event -> { referenceListAttribute.sort((d1,d2)->{ String s1 = Optional.ofNullable(d1.internal().getDisplayText()).orElse(""); String s2 = Optional.ofNullable(d2.internal().getDisplayText()).orElse(""); return s1.compareTo(s2); }); copyButton.disableProperty().bind(tableView.getSelectionModel().selectedItemProperty().isNull().or(multipleItemsSelected).or(new SimpleBooleanProperty(!isUserEditable))); copyButton.setOnAction(event -> { T copy = tableView.getSelectionModel().getSelectedItem().utility().semanticCopy(); referenceListAttribute.add(copy); tableView.getSelectionModel().clearSelection();
private Map<String,Data> collectChildDataMap() { List<Data> dataList = collectChildrenDeep(); HashMap<String, Data> result = Maps.newHashMapWithExpectedSize(dataList.size()); for (Data factory: dataList){ result.put(factory.getId(),factory); } return result; }
private void addBackReferencesForSubtree(Data root, Data parent, HashSet<Data> visited){ addParent(parent); this.root=root; getDataDictionary().addBackReferencesToAttributes(this,root); if (visited.add(this)) {//use HashSet instead of iteration counter to avoid iterationCounter mix up getDataDictionary().visitDataChildren(this, child -> child.addBackReferencesForSubtree(root,this,visited)); } }
@SuppressWarnings("unchecked") private void merge(Data originalValue, Data newValue, MergeResult mergeResult, Function<String,Boolean> permissionChecker) { this.visitAttributesTripleFlat(originalValue, newValue, (attributeName, currentAttribute, originalAttribute, newAttribute) -> { if (!currentAttribute.internal_ignoreForMerging()){ if (currentAttribute.internal_hasMergeConflict(originalAttribute, newAttribute)) { mergeResult.addConflictInfo(new AttributeDiffInfo(Data.this.getId(), attributeName)); } else { if (currentAttribute.internal_isMergeable(originalAttribute, newAttribute)) { final AttributeDiffInfo attributeDiffInfo = new AttributeDiffInfo(attributeName,Data.this.getId()); if (currentAttribute.internal_hasWritePermission(permissionChecker)){ mergeResult.addMergeInfo(attributeDiffInfo); mergeResult.addMergeExecutions(() -> currentAttribute.internal_merge(newAttribute)); } else { mergeResult.addPermissionViolationInfo(attributeDiffInfo); } } } } }); }
/** * prepare a new factory which could be used to update data. mainly give it the correct baseVersionId * @return new possible factory update with prepared ids/metadata * */ default DataAndNewMetadata<R> prepareNewFactory(){ return prepareNewFactory(getCurrentFactoryStorageId(),getCurrentFactory().root.utility().copy()); }
/** * after serialisation or programmatically creation this mus be called first before using the object<br> * to:<br> * -propagate root/parent node to all children (for validation etc)<br> * -init ids *<br> * only call on root<br> *<br> */ private void addBackReferences() { addBackReferences(this,null,this.dataIterationRun+1); }
public void addDisplayTextListeners(AttributeChangeListener attributeChangeListener){ data.addDisplayTextListeners(data, attributeChangeListener); }
/** * @param root root * @param parent parent */ public void addBackReferencesForSubtree(Data root, Data parent){ data.addBackReferencesForSubtree(root,parent,new HashSet<>()); }
@SuppressWarnings("unchecked") public MergeResult<R> createMergeResult(Function<String,Boolean> permissionChecker) { MergeResult mergeResult = new MergeResult(currentData); Map<String, Data> currentMap = currentData.internal().collectChildDataMap(); Map<String, Data> originalMap = commonData.internal().collectChildDataMap(); Map<String, Data> newMap = newData.internal().collectChildDataMap(); for (Data newData : newMap.values()) {//avoid mixup with iteration countern newData.internal().resetIterationCounterFlat(); } for (Map.Entry<String, Data> entry : currentMap.entrySet()) { Data originalValue = getOriginalValue(originalMap, entry); Data newValue = getNewValue(newMap, entry); if (newValue==null && originalValue!=null){ //check for conflict for removed object entry.getValue().internal().visitAttributesDualFlat(originalValue, (name, currentAttribute, originalAttribute) -> { if (!currentAttribute.internal_ignoreForMerging()){ if (!currentAttribute.internal_mergeMatch(originalAttribute)){ mergeResult.addConflictInfo(new AttributeDiffInfo(name,entry.getValue().getId())); } } }); } if (originalValue!=null && newValue!=null){ entry.getValue().internal().merge(originalValue, newValue, mergeResult, permissionChecker); } } return mergeResult; }
@Override @SuppressWarnings("unchecked") public void internal_fixDuplicateObjects(Map<String, Data> idToDataMap) { List<T> fixedList = new ArrayList<>(); for (T entity : this.list) { fixedList.add((T)idToDataMap.get(entity.getId())); } this.list.clear(); this.list.addAll(fixedList); }
public InMemoryDataStorage(R initialFactory, ChangeSummaryCreator<R,S> changeSummaryCreator){ initialFactory.internal().addBackReferences(); this.initialFactory=initialFactory; this.changeSummaryCreator = changeSummaryCreator; }
@Override public boolean internal_mergeMatch(T value) { if (this.value == null && value == null) { return true; } if (this.value == null || value == null) { return false; } return this.value.idEquals(value); }