001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.hadoop.yarn.api.records;
020
021import java.text.NumberFormat;
022import java.util.Iterator;
023import java.util.NoSuchElementException;
024
025import org.apache.hadoop.classification.InterfaceAudience.Private;
026import org.apache.hadoop.classification.InterfaceAudience.Public;
027import org.apache.hadoop.classification.InterfaceStability.Stable;
028import org.apache.hadoop.classification.InterfaceStability.Unstable;
029import org.apache.hadoop.yarn.util.Records;
030
031import com.google.common.base.Splitter;
032
033/**
034 * <p><code>ApplicationId</code> represents the <em>globally unique</em> 
035 * identifier for an application.</p>
036 * 
037 * <p>The globally unique nature of the identifier is achieved by using the 
038 * <em>cluster timestamp</em> i.e. start-time of the 
039 * <code>ResourceManager</code> along with a monotonically increasing counter
040 * for the application.</p>
041 */
042@Public
043@Stable
044public abstract class ApplicationId implements Comparable<ApplicationId> {
045  private static Splitter _spliter = Splitter.on('_').trimResults();
046
047  @Private
048  @Unstable
049  public static final String appIdStrPrefix = "application";
050
051  @Public
052  @Unstable
053  public static ApplicationId newInstance(long clusterTimestamp, int id) {
054    ApplicationId appId = Records.newRecord(ApplicationId.class);
055    appId.setClusterTimestamp(clusterTimestamp);
056    appId.setId(id);
057    appId.build();
058    return appId;
059  }
060
061  /**
062   * Get the short integer identifier of the <code>ApplicationId</code>
063   * which is unique for all applications started by a particular instance
064   * of the <code>ResourceManager</code>.
065   * @return short integer identifier of the <code>ApplicationId</code>
066   */
067  @Public
068  @Stable
069  public abstract int getId();
070  
071  @Private
072  @Unstable
073  protected abstract void setId(int id);
074  
075  /**
076   * Get the <em>start time</em> of the <code>ResourceManager</code> which is 
077   * used to generate globally unique <code>ApplicationId</code>.
078   * @return <em>start time</em> of the <code>ResourceManager</code>
079   */
080  @Public
081  @Stable
082  public abstract long getClusterTimestamp();
083  
084  @Private
085  @Unstable
086  protected abstract void setClusterTimestamp(long clusterTimestamp);
087
088  protected abstract void build();
089  
090  static final ThreadLocal<NumberFormat> appIdFormat =
091    new ThreadLocal<NumberFormat>() {
092      @Override
093      public NumberFormat initialValue() {
094        NumberFormat fmt = NumberFormat.getInstance();
095        fmt.setGroupingUsed(false);
096        fmt.setMinimumIntegerDigits(4);
097        return fmt;
098      }
099    };
100
101  @Override
102  public int compareTo(ApplicationId other) {
103    if (this.getClusterTimestamp() - other.getClusterTimestamp() == 0) {
104      return this.getId() - other.getId();
105    } else {
106      return this.getClusterTimestamp() > other.getClusterTimestamp() ? 1 : 
107        this.getClusterTimestamp() < other.getClusterTimestamp() ? -1 : 0;
108    }
109  }
110
111  @Override
112  public String toString() {
113    return appIdStrPrefix + "_" + this.getClusterTimestamp() + "_" + appIdFormat
114        .get().format(getId());
115  }
116  
117  private static ApplicationId toApplicationId(
118      Iterator<String> it) throws NumberFormatException {
119    ApplicationId appId = ApplicationId.newInstance(Long.parseLong(it.next()),
120        Integer.parseInt(it.next()));
121    return appId;
122  }
123  
124  @Public
125  @Stable
126  public static ApplicationId fromString(String appIdStr) {
127    Iterator<String> it = _spliter.split((appIdStr)).iterator();
128    if (!it.next().equals(appIdStrPrefix)) {
129      throw new IllegalArgumentException("Invalid ApplicationId prefix: "
130          + appIdStr + ". The valid ApplicationId should start with prefix "
131          + appIdStrPrefix);
132    }
133    try {
134      return toApplicationId(it);
135    } catch (NumberFormatException n) {
136      throw new IllegalArgumentException("Invalid ApplicationId: "
137          + appIdStr, n);
138    } catch (NoSuchElementException e) {
139      throw new IllegalArgumentException("Invalid ApplicationId: "
140          + appIdStr, e);
141    }
142  }
143
144  @Override
145  public int hashCode() {
146    // Generated by eclipse.
147    final int prime = 371237;
148    int result = 6521;
149    long clusterTimestamp = getClusterTimestamp();
150    result = prime * result
151        + (int) (clusterTimestamp ^ (clusterTimestamp >>> 32));
152    result = prime * result + getId();
153    return result;
154  }
155
156  @Override
157  public boolean equals(Object obj) {
158    if (this == obj)
159      return true;
160    if (obj == null)
161      return false;
162    if (getClass() != obj.getClass())
163      return false;
164    ApplicationId other = (ApplicationId) obj;
165    if (this.getClusterTimestamp() != other.getClusterTimestamp())
166      return false;
167    if (this.getId() != other.getId())
168      return false;
169    return true;
170  }
171}