在这个例子中,我们会对独立的邮件程序进行转换,并展现到自定义的email动作中[2](代码1)。
package com.navteq.assetmgmt.oozie.custom;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.apache.oozie.ErrorCode;
import org.apache.oozie.action.ActionExecutor;
import org.apache.oozie.action.ActionExecutorException;
import org.apache.oozie.action.ActionExecutorException.ErrorType;
import org.apache.oozie.client.WorkflowAction;
import org.apache.oozie.util.XmlUtils;
import org.jdom.Element;
import org.jdom.Namespace;
public class EmailActionExecutor extends ActionExecutor {
private static final String NODENAME = "eMail";
private static final String SUCCEEDED = "OK";
private static final String FAILED = "FAIL";
private static final String KILLED = "KILLED";
private static final String DEFAULMAILSERVER = "imailchi.navtech.com";
private static final String EMAILSERVER = "emailServer";
private static final String SUBJECT = "emailSubject";
private static final String MESSAGE = "emailBody";
private static final String FROM = "emailFrom";
private static final String TO = "emailTo";
public EmailActionExecutor() {
super(NODENAME);
}
@Override
public void check(Context context, WorkflowAction action) throws ActionExecutorException {
// Should not be called for synch operation
throw new UnsupportedOperationException();
}
@Override
public void end(Context context, WorkflowAction action)throws ActionExecutorException {
String externalStatus = action.getExternalStatus();
WorkflowAction.Status status = externalStatus.equals(SUCCEEDED) ?
WorkflowAction.Status.OK : WorkflowAction.Status.ERROR;
context.setEndData(status, getActionSignal(status));
}
@Override
public boolean isCompleted(String arg0) {
return true;
}
@Override
public void kill(Context context, WorkflowAction action) throws ActionExecutorException {
context.setExternalStatus(KILLED);
context.setExecutionData(KILLED, null);
}
@Override
public void start(Context context, WorkflowAction action) throws ActionExecutorException {
// Get parameters from Node configuration
try{
Element actionXml = XmlUtils.parseXml(action.getConf());
Namespace ns = Namespace.getNamespace("uri:custom:email-action:0.1");
String server = actionXml.getChildTextTrim(EMAILSERVER, ns);
String subject = actionXml.getChildTextTrim(SUBJECT, ns);
String message = actionXml.getChildTextTrim(MESSAGE, ns);
String from = actionXml.getChildTextTrim(FROM, ns);
String to = actionXml.getChildTextTrim(TO, ns);
// Check if all parameters are there
if(server == null)
server = DEFAULMAILSERVER;
if((message == null) || (from == null) || (to == null))
throw new ActionExecutorException(ErrorType.FAILED,
ErrorCode.E0000.toString(), "Not all parameters are defined");
// Execute action synchronously
SendMail(server, subject, message, from, to);
context.setExecutionData(SUCCEEDED, null);
}
catch(Exception e){
context.setExecutionData(FAILED, null);
throw new ActionExecutorException(ErrorType.FAILED,
ErrorCode.E0000.toString(), e.getMessage());
}
}
// Sending an email
public void SendMail(String server, String subject, String message,
String from, String to) throws Exception {
// create some properties and get the default Session
Properties props = new Properties();
props.setProperty("mail.smtp.host", server);
Session session = Session.getDefaultInstance(props, null);
// create a message
Message msg = new MimeMessage(session);
// set the from and to address
InternetAddress addressFrom = new InternetAddress(from);
msg.setFrom(addressFrom);
// To is a comma separated list
StringTokenizer st = new StringTokenizer(to, ",");
String [] recipients = new String[st.countTokens()];
int rc = 0;
while(st.hasMoreTokens())
recipients[rc++] = st.nextToken();
InternetAddress[] addressTo = new InternetAddress[recipients.length];
for (int i = 0; i < recipients.length; i++){
addressTo[i] = new InternetAddress(recipients[i]);
}
msg.setRecipients(Message.RecipientType.TO, addressTo);
// Setting the Subject and Content Type
msg.setSubject(subject);
msg.setContent(message, "text/plain");
Transport.send(msg);
}
}
代码1: Email自定义动作
实现了自定义的动作执行方式之后,我们需要为新的email动作定义XML模式[5](代码2)。
代码2: 为email组件所用的XML schema
自定义动作节点和XML schema文件都需要打包在单独的jar文件中,比方说emailAction.Jar。我们可以使用Oozie的oozie-setup.sh脚本执行下面的命令,从而把这个(以及其他所有)jar文件添加到Oozie的war文件中。
$ bin/oozie-setup.sh -jars emailAction.jar:mail.jar (See Adding Jars to Oozie)
码3: 部署命令
oozie.service.ActionService.executor.ext.classes
com.navteq.assetmgmt.oozie.custom. EmailActionExecutor
代码4: 自定义执行配置
oozie.service.SchemaService.wf.ext.schemas
emailAction.xsd
代码5: 自定义模式配置
test
mike.segel@.com
boris.lublinsky@.com
This is a test message, if you can see this, Mikey did something right! :)
Workflow failed, error message[${wf:errorMessage(wf:lastErrorNode())}]
[1] 这种类的例子可能是各种计数器操作、简单的计算等等。
nameNode=hdfs://master:9000
jobTracker=master:8032
queueName=default
examplesRoot=examples
oozie.use.system.libpath=true
oozie.libpath=hdfs://master:9000/user/hdfs/examples/thirdlib
oozie.wf.application.path=${nameNode}/user/${user.name}/${examplesRoot}/apps/sqoop-sqlserver-to-hdfs
mapred.child.java.opts
-Xmx4096m
mapred.map.child.java.opts
-Xmx4096m
mapred.reduce.child.java.opts
-Xmx4096m
或者增加map的数量
6关于oozie安装时数据库有问题的:8.oozie的节点分为 动作节点(action) 和控制节点(比如 start end fork merge) 其中控制节点下目前只可以放动作节点,分支节点下不支持在存放分支节点(即分支套分支的写法)
案例来自官网: http://oozie.apache.org/docs/4.0.0/WorkflowFunctionalSpec.html#a3.1.5_Fork_and_Join_Control_Nodes
...
foo:8021
bar:8020
job1.xml
foo:8021
bar:8020
job2.xml
...