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.oozie.workflow.lite;
020
021import org.apache.hadoop.io.Writable;
022import org.apache.oozie.service.LiteWorkflowStoreService;
023import org.apache.oozie.util.StringSerializationUtil;
024import org.apache.oozie.util.ParamChecker;
025import org.apache.oozie.workflow.WorkflowException;
026
027import java.io.DataInput;
028import java.io.DataOutput;
029import java.io.IOException;
030import java.util.ArrayList;
031import java.util.Collections;
032import java.util.List;
033
034/**
035 * This node definition is serialized object and should provide readFields() and write() for read and write of fields in
036 * this class.
037 */
038public class NodeDef implements Writable {
039    private String nodeDefVersion = null;
040    private String name = null;
041    private Class<? extends NodeHandler> handlerClass;
042    private String conf = null;
043    private List<String> transitions = new ArrayList<String>();
044    private String cred = null;
045    private String userRetryMax = "null";
046    private String userRetryInterval = "null";
047    private String userRetryPolicy = "null";
048
049    NodeDef() {
050    }
051
052    NodeDef(String name, String conf, Class<? extends NodeHandler> handlerClass, List<String> transitions) {
053        this.name = ParamChecker.notEmpty(name, "name");
054        this.conf = conf;
055        this.handlerClass = ParamChecker.notNull(handlerClass, "handlerClass");
056        this.transitions = Collections.unmodifiableList(ParamChecker.notEmptyElements(transitions, "transitions"));
057    }
058
059    NodeDef(String name, String conf, Class<? extends NodeHandler> handlerClass, List<String> transitions, String cred) {
060        this(name, conf, handlerClass, transitions);
061        if (cred != null) {
062            this.cred = cred;
063        }
064    }
065
066    NodeDef(String name, String conf, Class<? extends NodeHandler> handlerClass, List<String> transitions, String cred,
067            String userRetryMax, String userRetryInterval, String userRetryPolicy) {
068        this(name, conf, handlerClass, transitions, cred);
069        if (userRetryMax != null) {
070            this.userRetryMax = userRetryMax;
071        }
072        if (userRetryInterval != null) {
073            this.userRetryInterval = userRetryInterval;
074        }
075        if (userRetryPolicy != null) {
076            this.userRetryPolicy = userRetryPolicy;
077        }
078    }
079
080    public boolean equals(NodeDef other) {
081        return !(other == null || getClass() != other.getClass() || !getName().equals(other.getName()));
082    }
083
084    @Override
085    public int hashCode() {
086        return name.hashCode();
087    }
088
089    public String getName() {
090        return name;
091    }
092
093    public String getCred() {
094        return cred;
095    }
096
097    public Class<? extends NodeHandler> getHandlerClass() {
098        return handlerClass;
099    }
100
101    public List<String> getTransitions() {
102        return transitions;
103    }
104
105    public String getConf() {
106        return conf;
107    }
108
109    public String getUserRetryMax() {
110        return userRetryMax;
111    }
112
113    public String getUserRetryInterval() {
114        return userRetryInterval;
115    }
116
117    public String getNodeDefVersion() {
118        if (nodeDefVersion == null) {
119            try {
120                nodeDefVersion = LiteWorkflowStoreService.getNodeDefDefaultVersion();
121            }
122            catch (WorkflowException e) {
123                nodeDefVersion = LiteWorkflowStoreService.NODE_DEF_VERSION_2;
124            }
125        }
126        return nodeDefVersion;
127    }
128
129    public String getUserRetryPolicy() {
130        return userRetryPolicy;
131    }
132
133    public void setUserRetryPolicy(String userRetryPolicy) {
134        this.userRetryPolicy = userRetryPolicy;
135    }
136
137    @SuppressWarnings("unchecked")
138    private void readVersionZero(DataInput dataInput, String firstField) throws IOException {
139        if (firstField.equals(LiteWorkflowStoreService.NODE_DEF_VERSION_0)) {
140            name = dataInput.readUTF();
141        } else {
142            name = firstField;
143        }
144        nodeDefVersion = LiteWorkflowStoreService.NODE_DEF_VERSION_0;
145        cred = dataInput.readUTF();
146        String handlerClassName = dataInput.readUTF();
147        if ((handlerClassName != null) && (handlerClassName.length() > 0)) {
148            try {
149                handlerClass = (Class<? extends NodeHandler>) Class.forName(handlerClassName);
150            }
151            catch (ClassNotFoundException ex) {
152                throw new IOException(ex);
153            }
154        }
155        conf = readString(dataInput);
156        if (conf.equals("null")) {
157            conf = null;
158        }
159        int numTrans = dataInput.readInt();
160        transitions = new ArrayList<String>(numTrans);
161        for (int i = 0; i < numTrans; i++) {
162            transitions.add(dataInput.readUTF());
163        }
164    }
165    @SuppressWarnings("unchecked")
166    private void readVersionOne(DataInput dataInput, String firstField) throws IOException {
167        readCommon(dataInput, firstField, LiteWorkflowStoreService.NODE_DEF_VERSION_1);
168    }
169
170    /*
171     * Reads according to version 2
172     */
173    @SuppressWarnings("unchecked")
174    private void readVersionTwo(DataInput dataInput, String firstField) throws IOException {
175        readCommon(dataInput, firstField, LiteWorkflowStoreService.NODE_DEF_VERSION_2);
176        userRetryPolicy = dataInput.readUTF();
177    }
178
179    /*
180     * Reads common part
181     */
182    @SuppressWarnings("unchecked")
183    private void readCommon(DataInput dataInput, String firstField, String nodeDefVer) throws IOException {
184        nodeDefVersion = nodeDefVer;
185        name = dataInput.readUTF();
186        cred = dataInput.readUTF();
187        if (cred.equals("null")) {
188            cred = null;
189        }
190        String handlerClassName = dataInput.readUTF();
191        if ((handlerClassName != null) && (handlerClassName.length() > 0)) {
192            try {
193                handlerClass = (Class<? extends NodeHandler>) Class.forName(handlerClassName);
194            }
195            catch (ClassNotFoundException ex) {
196                throw new IOException(ex);
197            }
198        }
199        conf = readString(dataInput);
200        if (conf.equals("null")) {
201            conf = null;
202        }
203        int numTrans = dataInput.readInt();
204        transitions = new ArrayList<String>(numTrans);
205        for (int i = 0; i < numTrans; i++) {
206            transitions.add(dataInput.readUTF());
207        }
208        userRetryMax = dataInput.readUTF();
209        userRetryInterval = dataInput.readUTF();
210    }
211
212    /* (non-Javadoc)
213     * @see org.apache.hadoop.io.Writable#readFields(java.io.DataInput)
214     */
215    @Override
216    public void readFields(DataInput dataInput) throws IOException {
217        String firstField = dataInput.readUTF();
218        if (firstField.equals(LiteWorkflowStoreService.NODE_DEF_VERSION_1)) {
219            // since oozie version 3.1
220            readVersionOne(dataInput, firstField);
221        }
222        else if (firstField.equals(LiteWorkflowStoreService.NODE_DEF_VERSION_2)) {
223            readVersionTwo(dataInput, firstField);
224        }
225        else {
226            readVersionZero(dataInput, firstField);
227        }
228    }
229
230    private void writeVersionZero(DataOutput dataOutput) throws IOException {
231        dataOutput.writeUTF(nodeDefVersion);
232        dataOutput.writeUTF(name);
233        if (cred != null) {
234            dataOutput.writeUTF(cred);
235        }
236        else {
237            dataOutput.writeUTF("null");
238        }
239        dataOutput.writeUTF(handlerClass.getName());
240        if (conf != null) {
241            writeString(dataOutput, conf);
242        }
243        else {
244            dataOutput.writeUTF("null");
245        }
246        dataOutput.writeInt(transitions.size());
247        for (String transition : transitions) {
248            dataOutput.writeUTF(transition);
249        }
250    }
251
252    private void writeString(DataOutput dataOutput, String value) throws IOException {
253        StringSerializationUtil.writeString(dataOutput, value);
254    }
255
256    private String readString(DataInput dataInput) throws IOException {
257        return StringSerializationUtil.readString(dataInput);
258    }
259
260    /**
261     * Write as version one format, this version was since 3.1.
262     *
263     * @param dataOutput data output to serialize node def
264     * @throws IOException thrown if fail to write
265     */
266    private void writeVersionOne(DataOutput dataOutput) throws IOException {
267        writeCommon(dataOutput);
268    }
269
270    /**
271     * Write as version two format, this version was since 4.4.4.1.
272     *
273     * @param dataOutput data output to serialize node def
274     * @throws IOException thrown if fail to write
275     */
276    private void writeVersionTwo(DataOutput dataOutput) throws IOException {
277        writeCommon(dataOutput);
278        if (userRetryPolicy != null) {
279            dataOutput.writeUTF(userRetryPolicy);
280        }
281        else {
282            dataOutput.writeUTF("null");
283        }
284    }
285
286    /*
287     * Write the common part
288     */
289    private void writeCommon(DataOutput dataOutput) throws IOException {
290        dataOutput.writeUTF(nodeDefVersion);
291        dataOutput.writeUTF(name);
292        if (cred != null) {
293            writeString(dataOutput, cred);
294        }
295        else {
296            dataOutput.writeUTF("null");
297        }
298        writeString(dataOutput, handlerClass.getName());
299        if (conf != null) {
300            writeString(dataOutput, conf);
301        }
302        else {
303            dataOutput.writeUTF("null");
304        }
305        dataOutput.writeInt(transitions.size());
306        for (String transition : transitions) {
307            dataOutput.writeUTF(transition);
308        }
309        if (userRetryMax != null) {
310            dataOutput.writeUTF(userRetryMax);
311        }
312        else {
313            dataOutput.writeUTF("null");
314        }
315        if (userRetryInterval != null) {
316            dataOutput.writeUTF(userRetryInterval);
317        }
318        else {
319            dataOutput.writeUTF("null");
320        }
321    }
322
323    /* (non-Javadoc)
324     * @see org.apache.hadoop.io.Writable#write(java.io.DataOutput)
325     */
326    @Override
327    public void write(DataOutput dataOutput) throws IOException {
328        if (getNodeDefVersion().equals(LiteWorkflowStoreService.NODE_DEF_VERSION_1)) {
329            // since oozie version 3.1
330            writeVersionOne(dataOutput);
331        }
332        else if (getNodeDefVersion().equals(LiteWorkflowStoreService.NODE_DEF_VERSION_2)) {
333            writeVersionTwo(dataOutput);
334        }
335        else {
336            writeVersionZero(dataOutput);
337        }
338    }
339
340}