All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aliyun.odps.Project Maven / Gradle / Ivy

The newest version!
/*
 * 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 com.aliyun.odps;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.aliyun.odps.commons.transport.Headers;
import com.aliyun.odps.commons.transport.Response;
import com.aliyun.odps.commons.util.DateUtils;
import com.aliyun.odps.rest.ResourceBuilder;
import com.aliyun.odps.rest.RestClient;
import com.aliyun.odps.rest.SimpleXmlUtils;
import com.aliyun.odps.security.SecurityManager;
import com.aliyun.odps.simpleframework.xml.Element;
import com.aliyun.odps.simpleframework.xml.ElementList;
import com.aliyun.odps.simpleframework.xml.Root;
import com.aliyun.odps.simpleframework.xml.convert.Convert;
import com.aliyun.odps.simpleframework.xml.convert.Converter;
import com.aliyun.odps.simpleframework.xml.stream.InputNode;
import com.aliyun.odps.simpleframework.xml.stream.OutputNode;
import com.aliyun.odps.utils.StringUtils;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

/**
 * ODPS项目空间
 */
public class Project extends LazyLoad {

  /**
   * 项目空间状态
   */
  public static enum Status {
    /**
     * 正常
     */
    AVAILABLE,
    /**
     * 只读
     */
    READONLY,
    /**
     * 删除
     */
    DELETING,
    /**
     * 冻结
     */
    FROZEN,
    /**
     * 未知
     */
    UNKOWN
  }

  /**
   * 项目类型
   */
  public static enum ProjectType {
    /**
     * 普通 Odps 项目
     */
    managed,
    /**
     * 映射到 Odps 的外部项目,例如 hive
     */
    external
  }

  /**
   * Project model
   */
  @Root(name = "Project", strict = false)
  static class ProjectModel {

    @Element(name = "Name", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String name;

    @Element(name = "Type", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String type;

    @Element(name = "Comment", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String comment;

    @Element(name = "Owner", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String owner;

    @Element(name = "SuperAdministrator", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String superAdministrator;

    @Element(name = "CreationTime", required = false)
    @Convert(SimpleXmlUtils.DateConverter.class)
    Date creationTime;

    @Element(name = "LastModifiedTime", required = false)
    @Convert(SimpleXmlUtils.DateConverter.class)
    Date lastModified;

    @Element(name = "ProjectGroupName", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String projectGroupName;

    @Element(name = "DefaultQuotaNickname", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String defaultQuotaNickname;

    @Element(name = "DefaultQuotaRegion", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String defaultQuotaRegion;

    @Element(name = "Properties", required = false)
    @Convert(PropertyConverter.class)
    LinkedHashMap properties;

    @Element(name = "Property", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String propertyJsonString;

    @Element(name = "ExtendedProperties", required = false)
    @Convert(PropertyConverter.class)
    LinkedHashMap extendedProperties;

    @Element(name = "State", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String state;

    @Element(name = "DefaultCluster", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String defaultCluster;

    @Element(name = "QuotaID", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String defaultQuotaID;

    @Element(name = "Clusters", required = false)
    Clusters clusters;

    @Element(name = "Region", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String regionId;

    @Element(name = "TenantId", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String tenantId;
    /**
     * 分层存储信息
     */
    StorageTierInfo storageTierInfo;

    @Element(name = "DefaultCtrlService", required = false)
    String defaultCtrlService;
  }

  public static class ExternalProjectProperties {

    private JsonObject rootObj;
    private JsonObject networkObj;

    public ExternalProjectProperties(String source) {
      rootObj = new JsonObject();
      networkObj = new JsonObject();
      rootObj.addProperty("source", source);
      rootObj.add("network", networkObj);
    }

    public void addNetworkProperty(String name, String value) {
      networkObj.addProperty(name, value);
    }

    public void addProperty(String name, String value) {
      rootObj.addProperty(name, value);
    }

    public void addProperty(String name, JsonObject object) {
      rootObj.add(name, object);
    }

    public String toJson() {
      Gson gson = new Gson();
      return gson.toJson(rootObj);
    }
  }

  @Root(name = "Cluster", strict = false)
  public static class Cluster {

    @Root(name = "OptionalQuota", strict = false)
    public static class OptionalQuota {

      // Required by SimpleXML
      OptionalQuota() {
      }

      public OptionalQuota(String quotaID, Map properties) {
        this.quotaID = quotaID;
        this.properties = new LinkedHashMap<>(properties);
      }

      @Element(name = "QuotaID", required = false)
      @Convert(SimpleXmlUtils.EmptyStringConverter.class)
      String quotaID;

      @Element(name = "Properties", required = false)
      @Convert(PropertyConverter.class)
      LinkedHashMap properties;

      public String getQuotaID() {
        return quotaID;
      }

      public Map getProperties() {
        return properties;
      }
    }

    // Required by SimpleXML
    Cluster() {
    }

    public Cluster(String name, String quotaID) {
      if (StringUtils.isNullOrEmpty(name) || null == quotaID) {
        // quotaId can be set to empty string.
        // In that case, project has no related compute quota
        throw new IllegalArgumentException("Missing arguments: name, quotaID");
      }
      this.name = name;
      this.quotaID = quotaID;
    }

    @Element(name = "Name", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String name;

    @Element(name = "QuotaID", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String quotaID;

    @Element(name = "RegionId", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String regionId;

    @Element(name = "ClusterRole", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String clusterRole;

    @Element(name = "JobDataPath", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String jobDataPath;

    @Element(name = "ZoneId", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String zoneId;

    @Element(name = "IsDefaultInRegion", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String defaultInRegion;

    @ElementList(name = "Quotas", entry = "Quota", required = false)
    List optionalQuotas;

    public String getName() {
      return name;
    }

    public String getQuotaID() {
      return quotaID;
    }

    public String getRegionId() {
      return regionId;
    }

    public String getClusterRole() {
      return clusterRole;
    }

    public String getJobDataPath() {
      return jobDataPath;
    }

    public String getZoneId() {
      return zoneId;
    }

    public boolean isDefaultInRegion() {
      return Boolean.parseBoolean(defaultInRegion);
    }

    public List getOptionalQuotas() {
      return optionalQuotas;
    }

    public void setOptionalQuotas(List optionalQuotas) {
      this.optionalQuotas = optionalQuotas;
    }
  }

  @Root(name = "Clusters", strict = false)
  static class Clusters {

    @ElementList(entry = "Cluster", inline = true, required = false)
    List entries = new ArrayList();
  }

  @Root(name = "Property", strict = false)
  static class Property {

    Property() {
    }

    Property(String name, String value) {
      this.name = name;
      this.value = value;
    }

    @Element(name = "Name", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String name;

    @Element(name = "Value", required = false)
    @Convert(SimpleXmlUtils.EmptyStringConverter.class)
    String value;
  }

  @Root(name = "Properties", strict = false)
  static class Properties {

    @ElementList(entry = "Property", inline = true, required = false)
    List entries = new ArrayList();
  }

  static class PropertyConverter implements Converter> {

    @Override
    public void write(OutputNode outputNode, LinkedHashMap properties)
        throws Exception {
      if (properties != null) {
        for (Entry entry : properties.entrySet()) {
          String name = entry.getKey();
          String value = entry.getValue();
          SimpleXmlUtils.marshal(new Property(name, value), outputNode);
        }
      }

      outputNode.commit();
    }

    @Override
    public LinkedHashMap read(InputNode inputNode) throws Exception {
      LinkedHashMap properties = new LinkedHashMap();
      Properties props = SimpleXmlUtils.unmarshal(inputNode, Properties.class);
      for (Property entry : props.entries) {
        properties.put(entry.name, entry.value);
      }
      return properties;
    }
  }

  private ProjectModel model;
  private RestClient client;

  private Map properties = new LinkedHashMap();
  private Map allProperties;
  private SecurityManager securityManager = null;
  private Clusters clusters;

  // For compatibility. The static class 'Cluster' had strict schema validation. Unmarshalling will
  // failed because of the new xml tag 'Quotas'.
  private boolean usedByGroupApi = false;

  Project(ProjectModel model, RestClient client) {
    this.model = model;
    this.client = client;
  }

  @SuppressWarnings("unchecked")
  @Override
  public void reload() throws OdpsException {
    String resource = ResourceBuilder.buildProjectResource(model.name);

    Map params = null;
    if (usedByGroupApi) {
      params = new HashMap<>();
      params.put("isGroupApi", "true");
    }

    Response resp = client.request(resource, "GET", params, null, null);
    try {
      model = SimpleXmlUtils.unmarshal(resp, ProjectModel.class);
      Map headers = resp.getHeaders();
      model.owner = headers.get(Headers.ODPS_OWNER);
      model.creationTime = DateUtils.parseRfc822Date(headers
                                                         .get(Headers.ODPS_CREATION_TIME));
      model.lastModified = DateUtils.parseRfc822Date(headers
                                                         .get(Headers.LAST_MODIFIED));

      properties = model.properties;
      clusters = model.clusters;
    } catch (Exception e) {
      throw new OdpsException("Can't bind xml to " + ProjectModel.class, e);
    }
    setLoaded(true);
  }

  /**
   * 获取Project名称
   *
   * @return Project名称
   */
  public String getName() {
    return model.name;
  }

  /**
   * 获取Project类型
   *
   * @return Project类型
   */
  public ProjectType getType() throws OdpsException {
    if (model.type == null) {
      lazyLoad();
    }

    if (model.type != null) {
      try {
        return ProjectType.valueOf(model.type.toLowerCase());
      } catch (Exception e) {
        throw new OdpsException("Unknown project type: " + model.type);
      }
    } else {
      // no 'type' returned by Odps Api - we are targeting an old version Odps.
      return ProjectType.managed;
    }
  }

  /**
   * 获取Project注释
   *
   * @return Project注释
   */
  public String getComment() {
    if (model.comment == null) {
      lazyLoad();
    }
    return model.comment;
  }

  /**
   * 设置Project注释
   *
   * @param comment Project注释
   */
  void setComment(String comment) {
    model.comment = comment;
  }

  /**
   * 获得Project所属用户
   *
   * @return Project所属用户
   */
  public String getOwner() {
    if (model.owner == null) {
      lazyLoad();
    }
    return model.owner;
  }

  /**
   * 获取 project 所属 region
   *
   * @return region id
   */
  public String getRegionId() {
    if (model.regionId == null) {
      lazyLoad();
    }

    return model.regionId;
  }

  /**
   * 获取Project创建时间
   *
   * @return Project创建时间
   */
  public Date getCreatedTime() {
    if (model.creationTime == null) {
      lazyLoad();
    }
    return model.creationTime;
  }

  /**
   * 获取Project最后修改时间
   *
   * @return Project最后修改时间
   */
  public Date getLastModifiedTime() {
    if (model.lastModified == null) {
      lazyLoad();
    }
    return model.lastModified;
  }

  String getProjectGroupName() {
    lazyLoad();
    return model.projectGroupName;
  }

  public String getDefaultQuotaNickname() {
    lazyLoad();
    return model.defaultQuotaNickname;
  }

  public String getDefaultQuotaRegion() {
    lazyLoad();
    return model.defaultQuotaRegion;
  }

  /**
   * 获取Project当前状态
   *
   * @return {@link Status}
   */
  public Status getStatus() {
    if (model.state == null) {
      lazyLoad();
    }

    Status status = null;

    try {
      status = Status.valueOf(model.state.toUpperCase());
    } catch (Exception e) {
      return Status.UNKOWN;
    }
    return status;
  }

  /**
   * 获取 Project 已配置的属性
   *
   * @return 以key, value保存的配置信息
   */
  public Map getProperties() {
    lazyLoad();
    return properties;
  }

  /**
   * 获取 Project 全部可配置的属性, 包含从 group 继承来的配置信息
   *
   * @return 以key, value报错的配置信息
   */
  public Map getAllProperties() throws OdpsException {
    if (allProperties == null) {

      String resource = ResourceBuilder.buildProjectResource(model.name);
      Map params = new LinkedHashMap();
      params.put("properties", "all");
      Response resp = client.request(resource, "GET", params, null, null);
      try {
        ProjectModel model = SimpleXmlUtils.unmarshal(resp, ProjectModel.class);

        allProperties = model.properties;
      } catch (Exception e) {
        throw new OdpsException("Can't bind xml to " + ProjectModel.class, e);
      }
    }

    return allProperties;
  }

  /**
   * 查询Project指定配置信息
   *
   * @param key 配置项
   * @return 配置项对应的值
   */
  public String getProperty(String key) {
    lazyLoad();
    return properties == null ? null : properties.get(key);
  }

  /**
   * Get default cluster. This is an internal method for group-api.
   *
   * @return Default cluster when called by group owner, otherwise ,null.
   */
  String getDefaultCluster() {
    usedByGroupApi = true;
    lazyLoad();
    return model.defaultCluster;
  }

  /**
   * Get information of clusters owned by this project. This is an internal method for group-api.
   *
   * @return List of {@link Cluster}
   */
  List getClusters() {
    usedByGroupApi = true;
    lazyLoad();
    return clusters == null ? null : clusters.entries;
  }

  /**
   * 获取 Project 扩展配置信息
   *
   * @return 以 key, value 保存的配置信息
   */
  public Map getExtendedProperties() throws OdpsException {
    if (model.extendedProperties == null) {
      reloadExtendInfo();
      return this.model.extendedProperties;
    }
    return model.extendedProperties;
  }

  /**
   * 获取分层存储相关信息
   * @return 分层存储信息的对象
   * @throws OdpsException
   */

  public StorageTierInfo getStorageTierInfo() throws OdpsException {
    if (model.extendedProperties == null) {
      reloadExtendInfo();
    }
    model.storageTierInfo = StorageTierInfo.getStorageTierInfo(model.extendedProperties);
    return model.storageTierInfo;
  }

  /**
   * 更新项目的 extend 信息
   */
  public void reloadExtendInfo() throws OdpsException {
    Map param = new HashMap<>();
    param.put("extended", null);
    String resource = ResourceBuilder.buildProjectResource(model.name);
    ProjectModel extendedModel = client.request(ProjectModel.class, resource, "GET", param);

    this.model.extendedProperties =
        (extendedModel == null) ? new LinkedHashMap()
                                : extendedModel.extendedProperties;
  }

  /**
   * 获取{@link SecurityManager}对象
   *
   * @return {@link SecurityManager}对象
   */
  public SecurityManager getSecurityManager() {
    if (securityManager == null) {
      securityManager = new SecurityManager(model.name, client);
    }
    return securityManager;
  }

  public String getTunnelEndpoint() throws OdpsException {
    return getTunnelEndpoint(null);
  }

  public String getTunnelEndpoint(String quotaName) throws OdpsException {
    String protocol;
    try {
      URI u = new URI(client.getEndpoint());
      protocol = u.getScheme();
    } catch (URISyntaxException e) {
      throw new OdpsException(e.getMessage(), e);
    }

    String resource = ResourceBuilder.buildProjectResource(model.name).concat("/tunnel");
    HashMap params = new HashMap();
    params.put("service", null);
    if (quotaName != null && quotaName.length() != 0) {
      params.put("quotaName", quotaName);
    }
    Response resp = client.request(resource, "GET", params, null, null);

    String tunnel;
    if (resp.isOK()) {
      tunnel = new String(resp.getBody());
    } else {
      throw new OdpsException("Can't get tunnel server address: " + resp.getStatus());
    }

    return protocol + "://" + tunnel;
  }

  public String getTenantId() {
    lazyLoad();
    return model.tenantId;
  }

  private String getAutoMvMeta() throws Exception {
    String resource = ResourceBuilder.buildProjectResource(model.name).concat("/automvmeta");
    HashMap paras = new HashMap<>();
    Response response = client.request(resource, "GET", paras, null, null);

    String autoMvMeta;
    if (response.isOK()) {
      autoMvMeta = new String(response.getBody());
    } else {
      throw new OdpsException("Can't get autoMvMeta: " + response.getStatus());
    }

    return SimpleXmlUtils.unmarshal(autoMvMeta.getBytes(StandardCharsets.UTF_8), String.class);
  }

  public boolean triggerAutoMvCreation() throws OdpsException {
    String resource = ResourceBuilder.buildProjectResource(model.name).concat("/automvcreation");
    HashMap paras = new HashMap<>();
    Response response = client.request(resource, "POST", paras, null, null);

    if (response.isOK()) {
      return true;
    } else {
      throw new OdpsException("Can't trigger autoMv: " + response.getStatus());
    }
  }

  public Map showAutoMvMeta() {
    Map autoMvMeta = new HashMap<>();

    try {
      JsonObject tree = new JsonParser().parse(getAutoMvMeta()).getAsJsonObject();

      if (tree.has("fileSize")) {
        autoMvMeta.put("fileSize", tree.get("fileSize").getAsString());
      }

      if (tree.has("tableNum")) {
        autoMvMeta.put("tableNum", tree.get("tableNum").getAsString());
      }

      if (tree.has("updateTime")) {
        autoMvMeta.put("updateTime", tree.get("updateTime").getAsString());
      }

      if (tree.has("lastAutoMvCreationStartTime")) {
        autoMvMeta.put("lastAutoMvCreationStartTime",
                       tree.get("lastAutoMvCreationStartTime").getAsString());
      }

      if (tree.has("lastAutoMvCreationFinishTime")) {
        autoMvMeta.put("lastAutoMvCreationFinishTime",
                       tree.get("lastAutoMvCreationFinishTime").getAsString());
      }

    } catch (Exception e) {
      throw new RuntimeException(e.getMessage(), e);
    }

    return autoMvMeta;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy