/*
* 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.lot;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import com.aliyun.odps.FileResource;
import com.aliyun.odps.Instance;
import com.aliyun.odps.Odps;
import com.aliyun.odps.OdpsException;
import com.aliyun.odps.lot.common.ArgumentNullException;
import com.aliyun.odps.lot.common.TemporaryFunction;
import com.aliyun.odps.lot.operators.DataSource;
import com.aliyun.odps.lot.operators.Operator;
import com.aliyun.odps.task.LOTTask;
import apsara.odps.lot.Lot;
import apsara.odps.lot.Lottask;
//不支持不连通图
public class Task {
private Odps odps;
private String name;
private Map<String, String> hints = new HashMap<String, String>();
private Map<String, String> resourceAliasesForCurrentProject = new HashMap<String, String>();
private List<DataSource> roots = new ArrayList<DataSource>();
private Map<String, TemporaryFunction> tmpFunctions = new HashMap<String, TemporaryFunction>();
public Task(Odps odps, String name) {
if (odps == null) {
throw new ArgumentNullException("odps");
}
if (name == null) {
throw new ArgumentNullException("name");
}
this.odps = odps;
this.name = name;
}
public void addTemporaryFunction(TemporaryFunction function) {
if (tmpFunctions.containsKey(function.getName())) {
throw new IllegalArgumentException(
"You are adding temporary functions with the same name '" + function.getName() + "'.");
}
tmpFunctions.put(function.getName(), function);
}
//这个hint直接set到LOTTask.java的run参数中,安全起见,也生成在LOT pb中。
//有两条路输入settings,相当邪恶。
public void addHint(String key, String value) {
if (key == null) {
throw new ArgumentNullException("key");
}
if (value == null) {
throw new ArgumentNullException("value");
}
hints.put(key, value);
}
public void addResourceAliasesForCurrentProject(String source, String alias) {
if (source == null) {
throw new ArgumentNullException("source");
}
if (alias == null) {
throw new ArgumentNullException("alias");
}
resourceAliasesForCurrentProject.put(source, alias);
}
public void addRootOperator(DataSource root) {
if (root == null) {
throw new ArgumentNullException("root");
}
roots.add(root);
}
public Odps getOdps() {
return odps;
}
public String getCurrentProject() {
return odps.getDefaultProject();
}
public String getName() {
return name;
}
public Map<String, String> getHints() {
return hints;
}
public Map<String, String> getResourceAliasesForCurrentProject() {
return resourceAliasesForCurrentProject;
}
public List<DataSource> getRoots() {
return roots;
}
public Map<String, TemporaryFunction> getTmpFunctions() {
return tmpFunctions;
}
public ByteArrayInputStream getTaskInputStream() throws OdpsException {
validateGraph();
Lottask.LotTask.Builder task = Lottask.LotTask.newBuilder();
for (Map.Entry<String, String> item : hints.entrySet()) {
task.addEnvironmentBuilder().setKey(item.getKey()).setValue(item.getValue());
}
Set<Operator> visited = new HashSet<Operator>();
Lot.LogicalOperatorTree.Builder tree = Lot.LogicalOperatorTree.newBuilder();
for (Operator root : roots) {
genTree(tree, root, visited);
}
task.setLot(tree.build());
for (Map.Entry<String, TemporaryFunction> func : tmpFunctions.entrySet()) {
task.addTempFunctions(func.getValue().toProtoBuf());
}
Lottask.LotTask lotTask = task.build();
System.out.println(lotTask.toString());
return new ByteArrayInputStream(lotTask.toByteArray());
}
public Instance run() throws OdpsException {
String tmpRes = "lot-" + UUID.randomUUID().toString();
FileResource res = new FileResource();
res.setName(tmpRes);
res.setIsTempResource(true);
ByteArrayInputStream stream = getTaskInputStream();
odps.resources().create(odps.getDefaultProject(), res, stream);
return LOTTask.run(odps, getCurrentProject(), tmpRes, false, getHints(),
getResourceAliasesForCurrentProject());
}
private void genTree(Lot.LogicalOperatorTree.Builder tree, Operator root, Set<Operator> visited) {
if (!visited.contains(root)) {
tree.addOperators(root.toProtoBuf());
visited.add(root);
for (Operator child : root.getChildren()) {
genTree(tree, child, visited);
}
}
}
//对图做各种检查
private void validateGraph() throws OdpsException {
if (roots.size() == 0) {
throw new OdpsException(
"Invalid LOT task. You have to set one root operator at least for LOT.");
}
//omitted other validations.
}
}