/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.controller.repository;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.nifi.controller.queue.FlowFileQueue;
import org.apache.nifi.controller.repository.claim.ContentClaim;
import org.apache.nifi.processor.Relationship;
public class StandardRepositoryRecord implements RepositoryRecord {
private RepositoryRecordType type = null;
private FlowFileRecord workingFlowFileRecord = null;
private Relationship transferRelationship = null;
private FlowFileQueue destination = null;
private final FlowFileRecord originalFlowFileRecord;
private final FlowFileQueue originalQueue;
private String swapLocation;
private final Map<String, String> updatedAttributes = new HashMap<>();
private final Map<String, String> originalAttributes;
private List<ContentClaim> transientClaims;
/**
* Creates a new record which has no original claim or flow file - it is entirely new
*
* @param originalQueue queue
*/
public StandardRepositoryRecord(final FlowFileQueue originalQueue) {
this(originalQueue, null);
this.type = RepositoryRecordType.CREATE;
}
/**
* Creates a record based on given original items
*
* @param originalQueue queue
* @param originalFlowFileRecord record
*/
public StandardRepositoryRecord(final FlowFileQueue originalQueue, final FlowFileRecord originalFlowFileRecord) {
this(originalQueue, originalFlowFileRecord, null);
this.type = RepositoryRecordType.UPDATE;
}
public StandardRepositoryRecord(final FlowFileQueue originalQueue, final FlowFileRecord originalFlowFileRecord, final String swapLocation) {
this.originalQueue = originalQueue;
this.originalFlowFileRecord = originalFlowFileRecord;
this.type = RepositoryRecordType.SWAP_OUT;
this.swapLocation = swapLocation;
this.originalAttributes = originalFlowFileRecord == null ? Collections.<String, String>emptyMap() : originalFlowFileRecord.getAttributes();
}
@Override
public FlowFileQueue getDestination() {
return destination;
}
public void setDestination(final FlowFileQueue destination) {
this.destination = destination;
}
@Override
public RepositoryRecordType getType() {
return type;
}
FlowFileRecord getOriginal() {
return originalFlowFileRecord;
}
@Override
public String getSwapLocation() {
return swapLocation;
}
public void setSwapLocation(final String swapLocation) {
this.swapLocation = swapLocation;
if (type != RepositoryRecordType.SWAP_OUT) {
type = RepositoryRecordType.SWAP_IN; // we are swapping in a new record
}
}
@Override
public ContentClaim getOriginalClaim() {
return (originalFlowFileRecord == null) ? null : originalFlowFileRecord.getContentClaim();
}
@Override
public FlowFileQueue getOriginalQueue() {
return originalQueue;
}
public void setWorking(final FlowFileRecord flowFile) {
workingFlowFileRecord = flowFile;
}
public void setWorking(final FlowFileRecord flowFile, final String attributeKey, final String attributeValue) {
workingFlowFileRecord = flowFile;
// If setting attribute to same value as original, don't add to updated attributes
final String currentValue = originalAttributes.get(attributeKey);
if (currentValue == null || !currentValue.equals(attributeValue)) {
updatedAttributes.put(attributeKey, attributeValue);
}
}
public void setWorking(final FlowFileRecord flowFile, final Map<String, String> updatedAttribs) {
workingFlowFileRecord = flowFile;
for (final Map.Entry<String, String> entry : updatedAttribs.entrySet()) {
final String currentValue = originalAttributes.get(entry.getKey());
if (currentValue == null || !currentValue.equals(entry.getValue())) {
updatedAttributes.put(entry.getKey(), entry.getValue());
}
}
}
@Override
public boolean isAttributesChanged() {
return !updatedAttributes.isEmpty();
}
public void markForAbort() {
type = RepositoryRecordType.CONTENTMISSING;
}
@Override
public boolean isMarkedForAbort() {
return RepositoryRecordType.CONTENTMISSING.equals(type);
}
public void markForDelete() {
type = RepositoryRecordType.DELETE;
}
public boolean isMarkedForDelete() {
return RepositoryRecordType.DELETE.equals(type);
}
public void setTransferRelationship(final Relationship relationship) {
transferRelationship = relationship;
}
public Relationship getTransferRelationship() {
return transferRelationship;
}
FlowFileRecord getWorking() {
return workingFlowFileRecord;
}
ContentClaim getWorkingClaim() {
return (workingFlowFileRecord == null) ? null : workingFlowFileRecord.getContentClaim();
}
@Override
public FlowFileRecord getCurrent() {
return (workingFlowFileRecord == null) ? originalFlowFileRecord : workingFlowFileRecord;
}
@Override
public ContentClaim getCurrentClaim() {
return (getCurrent() == null) ? null : getCurrent().getContentClaim();
}
@Override
public long getCurrentClaimOffset() {
return (getCurrent() == null) ? 0L : getCurrent().getContentClaimOffset();
}
boolean isWorking() {
return (workingFlowFileRecord != null);
}
Map<String, String> getOriginalAttributes() {
return originalAttributes;
}
Map<String, String> getUpdatedAttributes() {
return updatedAttributes;
}
@Override
public String toString() {
return "StandardRepositoryRecord[UpdateType=" + getType() + ",Record=" + getCurrent() + "]";
}
@Override
public List<ContentClaim> getTransientClaims() {
return transientClaims == null ? Collections.<ContentClaim> emptyList() : Collections.unmodifiableList(transientClaims);
}
void addTransientClaim(final ContentClaim claim) {
if (claim == null) {
return;
}
if (transientClaims == null) {
transientClaims = new ArrayList<>();
}
transientClaims.add(claim);
}
}