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
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) {
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    }
075
076    public boolean equals(NodeDef other) {
077        return !(other == null || getClass() != other.getClass() || !getName().equals(other.getName()));
078    }
079
080    @Override
081    public int hashCode() {
082        return name.hashCode();
083    }
084
085    public String getName() {
086        return name;
087    }
088
089    public String getCred() {
090        return cred;
091    }
092
093    public Class<? extends NodeHandler> getHandlerClass() {
094        return handlerClass;
095    }
096
097    public List<String> getTransitions() {
098        return transitions;
099    }
100
101    public String getConf() {
102        return conf;
103    }
104
105    public String getUserRetryMax() {
106        return userRetryMax;
107    }
108
109    public String getUserRetryInterval() {
110        return userRetryInterval;
111    }
112
113    public String getNodeDefVersion() {
114        if (nodeDefVersion == null) {
115            try {
116                nodeDefVersion = LiteWorkflowStoreService.getNodeDefDefaultVersion();
117            }
118            catch (WorkflowException e) {
119                nodeDefVersion = LiteWorkflowStoreService.NODE_DEF_VERSION_1;
120            }
121        }
122        return nodeDefVersion;
123    }
124
125    @SuppressWarnings("unchecked")
126    private void readVersionZero(DataInput dataInput, String firstField) throws IOException {
127        if (firstField.equals(LiteWorkflowStoreService.NODE_DEF_VERSION_0)) {
128            name = dataInput.readUTF();
129        } else {
130            name = firstField;
131        }
132        nodeDefVersion = LiteWorkflowStoreService.NODE_DEF_VERSION_0;
133        cred = dataInput.readUTF();
134        String handlerClassName = dataInput.readUTF();
135        if ((handlerClassName != null) && (handlerClassName.length() > 0)) {
136            try {
137                handlerClass = (Class<? extends NodeHandler>) Class.forName(handlerClassName);
138            }
139            catch (ClassNotFoundException ex) {
140                throw new IOException(ex);
141            }
142        }
143        conf = readString(dataInput);
144        if (conf.equals("null")) {
145            conf = null;
146        }
147        int numTrans = dataInput.readInt();
148        transitions = new ArrayList<String>(numTrans);
149        for (int i = 0; i < numTrans; i++) {
150            transitions.add(dataInput.readUTF());
151        }
152    }
153    @SuppressWarnings("unchecked")
154    private void readVersionOne(DataInput dataInput, String firstField) throws IOException {
155        nodeDefVersion = LiteWorkflowStoreService.NODE_DEF_VERSION_1;
156        name = dataInput.readUTF();
157        cred = dataInput.readUTF();
158        if (cred.equals("null")) {
159            cred = null;
160        }
161        String handlerClassName = dataInput.readUTF();
162        if ((handlerClassName != null) && (handlerClassName.length() > 0)) {
163            try {
164                handlerClass = (Class<? extends NodeHandler>) Class.forName(handlerClassName);
165            }
166            catch (ClassNotFoundException ex) {
167                throw new IOException(ex);
168            }
169        }
170        conf = readString(dataInput);
171        if (conf.equals("null")) {
172            conf = null;
173        }
174        int numTrans = dataInput.readInt();
175        transitions = new ArrayList<String>(numTrans);
176        for (int i = 0; i < numTrans; i++) {
177            transitions.add(dataInput.readUTF());
178        }
179        userRetryMax = dataInput.readUTF();
180        userRetryInterval = dataInput.readUTF();
181    }
182
183    /* (non-Javadoc)
184     * @see org.apache.hadoop.io.Writable#readFields(java.io.DataInput)
185     */
186    @Override
187    public void readFields(DataInput dataInput) throws IOException {
188        String firstField = dataInput.readUTF();
189        if (!firstField.equals(LiteWorkflowStoreService.NODE_DEF_VERSION_1)) {
190            readVersionZero(dataInput, firstField);
191        } else {
192            //since oozie version 3.1
193            readVersionOne(dataInput, firstField);
194        }
195    }
196
197    private void writeVersionZero(DataOutput dataOutput) throws IOException {
198        dataOutput.writeUTF(nodeDefVersion);
199        dataOutput.writeUTF(name);
200        if (cred != null) {
201            dataOutput.writeUTF(cred);
202        }
203        else {
204            dataOutput.writeUTF("null");
205        }
206        dataOutput.writeUTF(handlerClass.getName());
207        if (conf != null) {
208            writeString(dataOutput, conf);
209        }
210        else {
211            dataOutput.writeUTF("null");
212        }
213        dataOutput.writeInt(transitions.size());
214        for (String transition : transitions) {
215            dataOutput.writeUTF(transition);
216        }
217    }
218
219    private void writeString(DataOutput dataOutput, String value) throws IOException {
220        StringSerializationUtil.writeString(dataOutput, value);
221    }
222
223    private String readString(DataInput dataInput) throws IOException {
224        return StringSerializationUtil.readString(dataInput);
225    }
226
227    /**
228     * Write as version one format, this version was since 3.1.
229     *
230     * @param dataOutput data output to serialize node def
231     * @throws IOException thrown if fail to write
232     */
233    private void writeVersionOne(DataOutput dataOutput) throws IOException {
234        dataOutput.writeUTF(nodeDefVersion);
235        dataOutput.writeUTF(name);
236        if (cred != null) {
237            writeString(dataOutput, cred);
238        }
239        else {
240            dataOutput.writeUTF("null");
241        }
242        writeString(dataOutput, handlerClass.getName());
243        if (conf != null) {
244            writeString(dataOutput, conf);
245        }
246        else {
247            dataOutput.writeUTF("null");
248        }
249        dataOutput.writeInt(transitions.size());
250        for (String transition : transitions) {
251            dataOutput.writeUTF(transition);
252        }
253        if (userRetryMax != null) {
254            dataOutput.writeUTF(userRetryMax);
255        }
256        else {
257            dataOutput.writeUTF("null");
258        }
259        if (userRetryInterval != null) {
260            dataOutput.writeUTF(userRetryInterval);
261        }
262        else {
263            dataOutput.writeUTF("null");
264        }
265    }
266
267    /* (non-Javadoc)
268     * @see org.apache.hadoop.io.Writable#write(java.io.DataOutput)
269     */
270    @Override
271    public void write(DataOutput dataOutput) throws IOException {
272        if (!getNodeDefVersion().equals(LiteWorkflowStoreService.NODE_DEF_VERSION_1)) {
273            writeVersionZero(dataOutput);
274        } else {
275            //since oozie version 3.1
276            writeVersionOne(dataOutput);
277        }
278    }
279
280}