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