/** * 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.falcon.notification.service.request; import org.apache.commons.lang3.StringUtils; import org.apache.falcon.execution.NotificationHandler; import org.apache.falcon.notification.service.NotificationServicesRegistry; import org.apache.falcon.state.ID; import org.apache.hadoop.fs.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; /** * Request intended for {@link import org.apache.falcon.notification.service.impl.DataAvailabilityService} * for data notifications. * The setter methods of the class support chaining similar to a builder class. */ public class DataNotificationRequest extends NotificationRequest implements Delayed { // Boolean represents path availability to avoid checking all paths for every poll. private Map<Path, Boolean> locations; private long pollingFrequencyInMillis; private long timeoutInMillis; private String cluster; private long accessTimeInMillis; private long createdTimeInMillis; // Represents request was accessed by DataAvailability service first time or not. private boolean isFirst; /** * Given a number of instances, should the service wait for exactly those many, * at least those many or at most those many instances. */ public enum INSTANCELIMIT { EXACTLY_N, AT_LEAST_N, AT_MOST_N } /** * Constructor. * @param notifHandler * @param callbackId * @param cluster * @param pollingFrequencyInMillis * @param timeoutInMillis * @param locations */ public DataNotificationRequest(NotificationHandler notifHandler, ID callbackId, String cluster, long pollingFrequencyInMillis, long timeoutInMillis, Map<Path, Boolean> locations) { this.handler = notifHandler; this.callbackId = callbackId; this.service = NotificationServicesRegistry.SERVICE.DATA; this.cluster = cluster; this.pollingFrequencyInMillis = pollingFrequencyInMillis; this.timeoutInMillis = timeoutInMillis; this.locations = locations; this.accessTimeInMillis = System.currentTimeMillis(); this.createdTimeInMillis = accessTimeInMillis; this.isFirst = true; } public void accessed() { this.accessTimeInMillis = System.currentTimeMillis(); } public String getCluster() { return cluster; } public boolean isTimedout() { long currentTimeInMillis = System.currentTimeMillis(); if (currentTimeInMillis - createdTimeInMillis > timeoutInMillis) { return true; } return false; } /** * Obtain list of paths from locations map. * @return List of paths to check. */ public List<Path> getLocations() { if (this.locations == null) { return null; } List<Path> paths = new ArrayList<>(); for (Path path : this.locations.keySet()) { paths.add(path); } return paths; } /** * @return Map of locations and their availabilities. */ public Map<Path, Boolean> getLocationMap() { return this.locations; } @Override public long getDelay(TimeUnit unit) { if (isFirst) { this.isFirst = false; return 0; } long age = System.currentTimeMillis() - accessTimeInMillis; return unit.convert(pollingFrequencyInMillis - age, TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed other) { return (int) (this.getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS)); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } DataNotificationRequest that = (DataNotificationRequest) o; if (!StringUtils.equals(cluster, that.cluster)) { return false; } if (!locations.equals(that.locations)) { return false; } if (pollingFrequencyInMillis != (that.pollingFrequencyInMillis)) { return false; } if (timeoutInMillis != that.timeoutInMillis) { return false; } if (createdTimeInMillis != that.createdTimeInMillis) { return false; } return true; } @Override public int hashCode() { int result = cluster.hashCode(); result = 31 * result + (locations != null ? locations.hashCode() : 0); result = 31 * result + Long.valueOf(pollingFrequencyInMillis).hashCode(); result = 31 * result + Long.valueOf(timeoutInMillis).hashCode(); result = 31 * result + Long.valueOf(createdTimeInMillis).hashCode(); return result; } @Override public String toString() { return "cluster: " + this.getCluster() + " locations: " + this.locations + " createdTime: " + this.createdTimeInMillis; } }