/** * Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior * University * * Licensed 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 org.openflow.protocol.action; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.U16; /** * The base class for all OpenFlow Actions. * * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010 */ public class OFAction implements Cloneable { /** * Note the true minimum length for this header is 8 including a pad to 64 * bit alignment, however as this base class is used for demuxing an * incoming Action, it is only necessary to read the first 4 bytes. All * Actions extending this class are responsible for reading/writing the * first 8 bytes, including the pad if necessary. */ public static int MINIMUM_LENGTH = 4; public static int OFFSET_LENGTH = 2; public static int OFFSET_TYPE = 0; protected OFActionType type; protected short length; /** * Get the length of this message * * @return */ public short getLength() { return length; } /** * Get the length of this message, unsigned * * @return */ public int getLengthU() { return U16.f(length); } /** * Set the length of this message * * @param length */ public OFAction setLength(short length) { this.length = length; return this; } /** * Get the type of this message * * @return OFActionType enum */ public OFActionType getType() { return this.type; } /** * Set the type of this message * * @param type */ public void setType(OFActionType type) { this.type = type; } /** * Returns a summary of the message * @return "ofmsg=v=$version;t=$type:l=$len:xid=$xid" */ public String toString() { return "ofaction" + ";t=" + this.getType() + ";l=" + this.getLength(); } /** * Given the output from toString(), * create a new OFAction * @param val * @return */ public static OFAction fromString(String val) { String tokens[] = val.split(";"); if (!tokens[0].equals("ofaction")) throw new IllegalArgumentException("expected 'ofaction' but got '" + tokens[0] + "'"); String type_tokens[] = tokens[1].split("="); String len_tokens[] = tokens[2].split("="); OFAction action = new OFAction(); action.setLength(Short.valueOf(len_tokens[1])); action.setType(OFActionType.valueOf(type_tokens[1])); return action; } public void readFrom(ChannelBuffer data) { this.type = OFActionType.valueOf(data.readShort()); this.length = data.readShort(); // Note missing PAD, see MINIMUM_LENGTH comment for details } public void writeTo(ChannelBuffer data) { data.writeShort(type.getTypeValue()); data.writeShort(length); // Note missing PAD, see MINIMUM_LENGTH comment for details } @Override public int hashCode() { final int prime = 347; int result = 1; result = prime * result + length; result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof OFAction)) { return false; } OFAction other = (OFAction) obj; if (length != other.length) { return false; } if (type == null) { if (other.type != null) { return false; } } else if (!type.equals(other.type)) { return false; } return true; } /* (non-Javadoc) * @see java.lang.Object#clone() */ @Override public OFAction clone() throws CloneNotSupportedException { return (OFAction) super.clone(); } }