/*
* 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.remote;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import org.apache.nifi.remote.protocol.CommunicationsSession;
public class Peer implements Communicant {
private final PeerDescription description;
private final CommunicationsSession commsSession;
private final String url;
private final String clusterUrl;
private final Map<String, Long> penaltyExpirationMap = new HashMap<>();
private boolean closed = false;
public Peer(final PeerDescription description, final CommunicationsSession commsSession, final String peerUrl, final String clusterUrl) {
this.description = description;
this.commsSession = commsSession;
this.url = peerUrl;
this.clusterUrl = clusterUrl;
try {
// Parse peerUrl to validate it.
new URI(peerUrl);
} catch (final Exception e) {
throw new IllegalArgumentException("Invalid URL: " + peerUrl);
}
}
public PeerDescription getDescription() {
return description;
}
@Override
public String getUrl() {
return url;
}
public String getClusterUrl() {
return clusterUrl;
}
public CommunicationsSession getCommunicationsSession() {
return commsSession;
}
public void close() throws IOException {
this.closed = true;
// Consume the InputStream so that it doesn't linger on the Peer's outgoing socket buffer
try {
commsSession.getInput().consume();
} finally {
commsSession.close();
}
}
/**
* Penalizes this peer for the given destination only for the provided
* number of milliseconds
*
* @param destinationId id of destination
* @param millis period of time to penalize peer
*/
public void penalize(final String destinationId, final long millis) {
final Long currentPenalty = penaltyExpirationMap.get(destinationId);
final long proposedPenalty = System.currentTimeMillis() + millis;
if (currentPenalty == null || proposedPenalty > currentPenalty) {
penaltyExpirationMap.put(destinationId, proposedPenalty);
}
}
public boolean isPenalized(final String destinationId) {
final Long currentPenalty = penaltyExpirationMap.get(destinationId);
return (currentPenalty != null && currentPenalty > System.currentTimeMillis());
}
public boolean isClosed() {
return closed;
}
@Override
public String getHost() {
return description.getHostname();
}
@Override
public int hashCode() {
return 8320 + url.hashCode();
}
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (!(obj instanceof Peer)) {
return false;
}
final Peer other = (Peer) obj;
return this.url.equals(other.url);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Peer[url=").append(url);
if (closed) {
sb.append(",CLOSED");
}
sb.append("]");
return sb.toString();
}
@Override
public int getPort() {
return description.getPort();
}
@Override
public String getDistinguishedName() {
return commsSession.getUserDn();
}
@Override
public String createTransitUri(String sourceFlowFileIdentifier) {
return commsSession.createTransitUri(url, sourceFlowFileIdentifier);
}
}