/*
 * Copyright 2015 Open Networking Laboratory
 *
 * 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.onosproject.net.group;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.Objects;

import org.onosproject.core.GroupId;

/**
 * Group operation definition to be used between core and provider
 * layers of group subsystem.
 *
 */
public final class GroupOperation {
    private final Type opType;
    private final GroupId groupId;
    private final GroupDescription.Type groupType;
    private final GroupBuckets buckets;
    private final GroupMsgErrorCode failureCode;

    public enum Type {
        /**
         * Create a group in a device with the specified parameters.
         */
        ADD,
        /**
         * Modify a group in a device with the specified parameters.
         */
        MODIFY,
        /**
         * Delete a specified group.
         */
        DELETE
    }

    /**
     * Possible error codes for a failure of a group operation.
     *
     */
    public enum GroupMsgErrorCode {
        GROUP_EXISTS,
        INVALID_GROUP,
        WEIGHT_UNSUPPORTED,
        OUT_OF_GROUPS,
        OUT_OF_BUCKETS,
        CHAINING_UNSUPPORTED,
        WATCH_UNSUPPORTED,
        LOOP,
        UNKNOWN_GROUP,
        CHAINED_GROUP,
        BAD_TYPE,
        BAD_COMMAND,
        BAD_BUCKET,
        BAD_WATCH,
        EPERM;
    }

    /**
     * Group operation constructor with the parameters.
     *
     * @param opType group operation type
     * @param groupId group Identifier
     * @param groupType type of the group
     * @param buckets immutable list of group buckets to be part of group
     */
    private GroupOperation(Type opType,
                           GroupId groupId,
                           GroupDescription.Type groupType,
                           GroupBuckets buckets) {
        this.opType = checkNotNull(opType);
        this.groupId = checkNotNull(groupId);
        this.groupType = checkNotNull(groupType);
        this.buckets = buckets;
        this.failureCode = null;
    }

    /**
     * Group operation copy-constructor with additional field to set failure code.
     * Typically used by provider to return information to the core about
     * the failure reason for a group operation.
     *
     * @param groupOp the original group operation
     * @param failureCode failure code for a failed group operation
     */
    private GroupOperation(GroupOperation groupOp, GroupMsgErrorCode failureCode) {
        this.opType = groupOp.opType;
        this.groupId = groupOp.groupId;
        this.groupType = groupOp.groupType;
        this.buckets = groupOp.buckets;
        this.failureCode = failureCode;
    }

    /**
     * Creates ADD group operation object.
     *
     * @param groupId group Identifier
     * @param groupType type of the group
     * @param buckets immutable list of group buckets to be part of group
     * @return add group operation object
     */
    public static GroupOperation createAddGroupOperation(GroupId groupId,
                                     GroupDescription.Type groupType,
                                     GroupBuckets buckets) {
        checkNotNull(buckets);
        return new GroupOperation(Type.ADD, groupId, groupType, buckets);
    }

    /**
     * Creates MODIFY group operation object.
     *
     * @param groupId group Identifier
     * @param groupType type of the group
     * @param buckets immutable list of group buckets to be part of group
     * @return modify group operation object
     */
    public static GroupOperation createModifyGroupOperation(GroupId groupId,
                               GroupDescription.Type groupType,
                               GroupBuckets buckets) {
        checkNotNull(buckets);
        return new GroupOperation(Type.MODIFY, groupId, groupType, buckets);

    }

    /**
     * Creates DELETE group operation object.
     *
     * @param groupId group Identifier
     * @param groupType type of the group
     * @return delete group operation object
     */
    public static GroupOperation createDeleteGroupOperation(GroupId groupId,
                                  GroupDescription.Type groupType) {
        return new GroupOperation(Type.DELETE, groupId, groupType, null);

    }

    public static GroupOperation createFailedGroupOperation(GroupOperation groupOperation,
                                                            GroupMsgErrorCode failureCode) {
        checkNotNull(groupOperation);
        return new GroupOperation(groupOperation, failureCode);
    }

    /**
     * Returns group operation type.
     *
     * @return GroupOpType group operation type
     */
    public Type opType() {
        return this.opType;
    }

    /**
     * Returns group identifier attribute of the operation.
     *
     * @return GroupId group identifier
     */
    public GroupId groupId() {
        return this.groupId;
    }

    /**
     * Returns group type attribute of the operation.
     *
     * @return GroupType group type
     */
    public GroupDescription.Type groupType() {
        return this.groupType;
    }

    /**
     * Returns group buckets associated with the operation.
     *
     * @return GroupBuckets group buckets
     */
    public GroupBuckets buckets() {
        return this.buckets;
    }

    /**
     * Returns the failure code representing the failure of a group operation.
     *
     * @return error code for failure of group operation
     */
    public GroupMsgErrorCode failureCode() {
        return failureCode;
    }

    @Override
    /*
     * The deviceId, type and buckets are used for hash.
     *
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public int hashCode() {
        return (buckets != null) ? Objects.hash(groupId, opType, buckets) :
            Objects.hash(groupId, opType);
    }

    @Override
    /*
     * The deviceId, type and buckets should be same.
     *
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
       if (obj instanceof GroupOperation) {
           GroupOperation that = (GroupOperation) obj;
           return Objects.equals(groupId, that.groupId) &&
                   Objects.equals(groupType, that.groupType) &&
                   Objects.equals(opType, that.opType) &&
                   Objects.equals(buckets, that.buckets);

        }
        return false;
    }
}

@@ -4806,24 +4806,325 @@
 l);%0A%0A    %7D%0A%0A
+    /**%0A     * Creates failure group operation object by setting failure code%0A     * to inform the failure reason.%0A     *%0A     * @param groupOperation the original group operation%0A     * @param failureCode failure code for a failed group operation%0A     * @return failed group operation object%0A     */%0A
     public s

Add comment in GroupOperation for javadoc