Added GateInfo to Op Ds and RPCs to support gate update requests 23/31523/6
authorRyan Vail <r.vail@cablelabs.com>
Tue, 1 Dec 2015 17:16:16 +0000 (11:16 -0600)
committerRyan Vail <r.vail@cablelabs.com>
Mon, 4 Jan 2016 17:12:12 +0000 (17:12 +0000)
Extended driver with GateState and GateInfo types.
Added GateInfo data to operationa datastore.
Added RPC to request GateState updating.
Updated cmts emulator to respond to gate info requests

Change-Id: I35bccb12636359c3613b4b06958a348037cef93b
Signed-off-by: Ryan Vail <r.vail@cablelabs.com>
34 files changed:
packetcable-driver/src/main/java/org/pcmm/PCMMPdpMsgSender.java
packetcable-driver/src/main/java/org/pcmm/PCMMPdpReqStateMan.java
packetcable-driver/src/main/java/org/pcmm/base/impl/PCMMBaseObject.java
packetcable-driver/src/main/java/org/pcmm/gates/IGateSpec.java
packetcable-driver/src/main/java/org/pcmm/gates/IGateState.java [new file with mode: 0644]
packetcable-driver/src/main/java/org/pcmm/gates/IGateTimeInfo.java [new file with mode: 0644]
packetcable-driver/src/main/java/org/pcmm/gates/IGateUsageInfo.java [new file with mode: 0644]
packetcable-driver/src/main/java/org/pcmm/gates/IPCMMError.java
packetcable-driver/src/main/java/org/pcmm/gates/IPCMMGate.java
packetcable-driver/src/main/java/org/pcmm/gates/ITrafficProfile.java
packetcable-driver/src/main/java/org/pcmm/gates/impl/AMID.java
packetcable-driver/src/main/java/org/pcmm/gates/impl/BEEnvelop.java
packetcable-driver/src/main/java/org/pcmm/gates/impl/BestEffortService.java
packetcable-driver/src/main/java/org/pcmm/gates/impl/GateState.java [new file with mode: 0644]
packetcable-driver/src/main/java/org/pcmm/gates/impl/GateTimeInfo.java [new file with mode: 0644]
packetcable-driver/src/main/java/org/pcmm/gates/impl/GateUsageInfo.java [new file with mode: 0644]
packetcable-driver/src/main/java/org/pcmm/gates/impl/PCMMError.java
packetcable-driver/src/main/java/org/pcmm/gates/impl/PCMMGateReq.java
packetcable-driver/src/main/java/org/pcmm/rcd/impl/AbstractPCMMServer.java
packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepConnection.java
packetcable-driver/src/test/java/org/pcmm/gates/impl/PCMMErrorTest.java
packetcable-emulator/conf/cmts.yaml
packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CMTS.java
packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CMTSConfig.java [new file with mode: 0644]
packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CmtsDataProcessor.java
packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CmtsPcmmClientHandler.java
packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CmtsPepReqStateMan.java
packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CmtsYmal.java [new file with mode: 0644]
packetcable-emulator/src/main/java/org/pcmm/rcd/impl/PcmmCmtsConnection.java
packetcable-policy-model/src/main/yang/packetcable.yang
packetcable-policy-server/src/main/java/org/opendaylight/controller/packetcable/provider/PCMMGateReqBuilder.java
packetcable-policy-server/src/main/java/org/opendaylight/controller/packetcable/provider/PCMMService.java
packetcable-policy-server/src/main/java/org/opendaylight/controller/packetcable/provider/PacketcableProvider.java
packetcable-policy-server/src/test/java/org/opendaylight/controller/packetcable/provider/PCMMServiceTest.java

index 91303b1232ce6126ab0e386feb4d9a94389cdbf6..d1560646928fb2a7f04e8dd1530ac2d3502be0c2 100644 (file)
@@ -98,7 +98,7 @@ public class PCMMPdpMsgSender extends COPSMsgSender {
         final ITransactionID trID = new TransactionID(_transactionID, GateCommandType.GATE_SET);
 
         gate.setTransactionID(trID);
-        // retain the transactionId to gate request mapping for gateID recovery after response
+        // retain the transactitrIDnumonId to gate request mapping for gateID recovery after response
         // see PCMMPdpReqStateMan.processReport()
         final Short trIDnum = trID.getTransactionIdentifier();
         logger.info("Adding gate to cache - " + gate + " with key - " + trIDnum);
@@ -227,13 +227,43 @@ public class PCMMPdpMsgSender extends COPSMsgSender {
      *
      * @throws COPSPdpException
      */
-    public void sendGateInfo() throws COPSPdpException {
+    public void sendGateInfo(final IPCMMGate gate) throws COPSPdpException {
         /*
          * <Gate-Info> ::= <Common Header> [<Client Handle>] [<Integrity>]
          */
-        final COPSSyncStateMsg msg = new COPSSyncStateMsg(getClientType(), _handle, null);
+       
+       // added 
+        final ITransactionID trID = new TransactionID(_transactionID, GateCommandType.GATE_INFO);
+        gate.setTransactionID(trID);
+        // retain the transactionId to gate request mapping for gateID recovery after response
+        // see PCMMPdpReqStateMan.processReport()
+        final Short trIDnum = trID.getTransactionIdentifier();
+        logger.info("Adding gate to cache - " + gate + " with key - " + trIDnum);
+        PCMMGlobalConfig.transactionGateMap.put(trIDnum, gate);
+        
+        // gateDelete only requires AMID, subscriberID, and gateID
+        // remove the gateSpec, traffic profile, and classifiers from original gate request
+        gate.setGateSpec(null);
+        gate.setTrafficProfile(null);
+        gate.setClassifiers(null);
+        // clear the error object
+        gate.setError(null);
+        
+        
+        // XXX - GateID
+        final byte[] data = gate.getData();
+        final Set<COPSDecision> decisionSet = new HashSet<>();
+        decisionSet.add(new COPSDecision(CType.DEF, Command.INSTALL, DecisionFlag.REQERROR));
+        final Map<COPSContext, Set<COPSDecision>> decisionMap = new HashMap<>();
+        decisionMap.put(new COPSContext(RType.CONFIG, (short)0), decisionSet);
+        final COPSClientSI clientSD = new COPSClientSI(CNum.DEC, CType.CSI, new COPSData(data, 0, data.length));
+       
+        //final COPSSyncStateMsg msg = new COPSSyncStateMsg(getClientType(), _handle, null);
+        final COPSDecisionMsg decisionMsg = new COPSDecisionMsg(getClientType(), _handle, decisionMap, null, clientSD);
+        
         try {
-            msg.writeData(_sock);
+            //msg.writeData(_sock);
+            decisionMsg.writeData(_sock);
         } catch (IOException e) {
             throw new COPSPdpException("Failed to send the GateInfo request", e);
         }
index b80bf686c1fc050d4ec19b771bbea120047b3e3d..9c7ee19d5eb009722d1e7532db69b5f30177ab8f 100644 (file)
@@ -9,6 +9,9 @@
 package org.pcmm;
 
 import org.pcmm.gates.IGateID;
+import org.pcmm.gates.IGateState;
+import org.pcmm.gates.IGateTimeInfo;
+import org.pcmm.gates.IGateUsageInfo;
 import org.pcmm.gates.IPCMMError.ErrorCode;
 import org.pcmm.gates.IPCMMGate;
 import org.pcmm.gates.ITransactionID;
@@ -125,8 +128,17 @@ public class PCMMPdpReqStateMan extends COPSPdpReqStateMan {
                 logger.info("rtypemsg success");
                 _status = Status.ST_REPORT;
                 final IGateID gateID = gateMsg.getGateID();
-                logger.info("Setting gate ID on gate object - " + gateID);
+                //logger.info("Setting gate ID on gate object - " + gateID);
                 gate.setGateID(gateID);
+                
+                //setting the Gate State, Time Info and Usage Info
+                final IGateState igateState = gateMsg.getGateState();
+                gate.setGateState(igateState);
+                final IGateTimeInfo gateTimeInfo = gateMsg.getGateTimeInfo();
+                gate.setGateTimeInfo(gateTimeInfo);
+                final IGateUsageInfo gateUsageInfo = gateMsg.getGateUsageInfo();
+                gate.setGateUsageInfo(gateUsageInfo);
+                
                 if (_thisProcess != null)
                     _thisProcess.successReport(this, gateMsg);
             } else {
@@ -135,12 +147,17 @@ public class PCMMPdpReqStateMan extends COPSPdpReqStateMan {
                     cmdType = "GateDeleteAck";
                 } else if (trID.getGateCommandType().equals(GateCommandType.GATE_SET_ACK)) {
                     cmdType = "GateSetAck";
+                } else if (trID.getGateCommandType().equals(GateCommandType.GATE_INFO_ACK)) {
+                    cmdType = "GateInfoAck";
                 } else cmdType = null;
                 // capture the gateId from the response message
                 final IGateID gateID = gateMsg.getGateID();
                 logger.info("Setting gate ID on gate object - " + gateID);
                 gate.setGateID(gateID);
-
+                // capture the gate state from the response message
+                final IGateState igateState = gateMsg.getGateState();
+                logger.info("Setting gate ID on gate object - " + gateID);
+                gate.setGateState(igateState);
                 if (gateID != null) {
                     int gateIdInt = gateID.getGateID();
                     String gateIdHex = String.format("%08x", gateIdInt);
index 3aaf34cd93181b6b41bdab6f9edbc5c040658e09..cebd2c4a706819c69d7b49c2c61e6b96c7777add 100644 (file)
@@ -123,7 +123,7 @@ public abstract class PCMMBaseObject implements IPCMMBaseObject {
                USER_ID((byte) 20),
                SHARED_RES_ID((byte) 21);
 
-               private byte value;
+               private final byte value;
 
                SNum(byte value) {
                        this.value = value;
index f54303db5e376d0564453e3bace6bf54a33dd4bf..b24ff4f9968c69205d6f2c0254ae72c9e8b55645 100644 (file)
@@ -20,8 +20,8 @@ import org.pcmm.base.IPCMMBaseObject;
  *
  * * SessionClassID
  * * Direction
- * * Authorized Timer
- * * Reserved Timer
+ * * AUTHORIZED Timer
+ * * RESERVED Timer
  * * Committed Timer
  * * Committed Recovery Timer
  * * DSCP/TOS Overwrite
@@ -36,10 +36,10 @@ import org.pcmm.base.IPCMMBaseObject;
  * MUST reserve and activate the DOCSIS flows accordingly. For Multicast Gates the CMTS needs to only support
  * flows or gates in the downstream direction.
  *
- * Authorized Timer limits the amount of time the authorization must remain valid before it is reserved (see
+ * AUTHORIZED Timer limits the amount of time the authorization must remain valid before it is reserved (see
  * Section 6.2).
  *
- * Reserved Timer limits the amount of time the reservation must remain valid before the resources are committed (see
+ * RESERVED Timer limits the amount of time the reservation must remain valid before the resources are committed (see
  * Section 6.2).
  *
  * Committed Timer limits the amount of time a committed service flow may remain idle.
@@ -129,7 +129,7 @@ public interface IGateSpec extends IPCMMBaseObject {
     Direction getDirection();
 
     /**
-     * Authorized Timer limits the amount of time the authorization must remain
+     * AUTHORIZED Timer limits the amount of time the authorization must remain
      * valid before it is reserved
      *
      * @return time in ms;
@@ -137,7 +137,7 @@ public interface IGateSpec extends IPCMMBaseObject {
     short getTimerT1();
 
     /**
-     * Reserved Timer limits the amount of time the reservation must remain
+     * RESERVED Timer limits the amount of time the reservation must remain
      * valid before the resources are committed
      *
      * @return time in ms;
diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IGateState.java b/packetcable-driver/src/main/java/org/pcmm/gates/IGateState.java
new file mode 100644 (file)
index 0000000..33db544
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015 CableLabs and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates;
+
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Converter;
+import org.pcmm.base.IPCMMBaseObject;
+
+/**
+ * From the Packetcable Multimedia specification section 6.4.2.15
+ * <p>
+ * The information in the Gate State object reflects the current state of the Gate. The CMTS MUST include the Gate
+ * State object in any unsolicited messages that it sends to the Policy Server. The Policy Server may use this
+ * information to report state to the Application Manager, or for enforcing complex rules that might require state
+ * knowledge of the Gate.
+ */
+public interface IGateState extends IPCMMBaseObject {
+
+    static final Converter<String, String> converter = CaseFormat.UPPER_UNDERSCORE.converterTo(CaseFormat.UPPER_CAMEL);
+    /**
+     * The S-Type for Gate State
+     */
+    byte STYPE = 1;
+
+    /**
+     * Returns the gate State value
+     *
+     * @return - the State (2 bytes unsigned integer)
+     */
+    //short getGateState();
+    GateStateType getGateState();
+
+    GateStateReasonType getGateStateReason();
+
+    /**
+     * Gate State Types types
+     */
+    enum GateStateType {
+
+        IDLE_CLOSED((short) 1),
+        AUTHORIZED((short) 2),
+        RESERVED((short) 3),
+        COMMITTED((short) 4),
+        COMMITTED_RECOVERY((short) 5);
+
+        GateStateType(short value) {
+            this.value = value;
+            this.displayName = converter.convert(name());
+        }
+
+        public short getValue() {
+            return value;
+        }
+
+        public static GateStateType valueOf(short v) {
+            switch (v) {
+                case 1:
+                    return GateStateType.IDLE_CLOSED;
+                case 2:
+                    return GateStateType.AUTHORIZED;
+                case 3:
+                    return GateStateType.RESERVED;
+                case 4:
+                    return GateStateType.COMMITTED;
+                case 5:
+                    return GateStateType.COMMITTED_RECOVERY;
+                default:
+                    throw new IllegalArgumentException("not supported value");
+            }
+        }
+
+        private final short value;
+        private final String displayName;
+
+        public String toString() {
+            return displayName + "(" + getValue() + ")";
+        }
+    }
+
+
+    /**
+     * From PCMM Spec section 6.4.2.15
+     * Reason is a 2-byte unsigned integer field which MUST indicate one of the following reasons for this update:<pre>
+     * 1 = Close initiated by CMTS due to reservation reassignment
+     * 2 = Close initiated by CMTS due to lack of DOCSIS MAC-layer responses
+     * 3 = Close initiated by CMTS due to timer T1 expiration
+     * 4 = Close initiated by CMTS due to timer T2 expiration
+     * 5 = Inactivity timer expired due to Service Flow inactivity (timer T3 expiration)
+     * 6 = Close initiated by CMTS due to lack of Reservation Maintenance
+     * 7 = Gate state unchanged, but volume limit reached
+     * 8 = Close initiated by CMTS due to timer T4 expiration
+     * 9 = Gate state unchanged, but timer T2 expiration caused reservation reduction
+     * 10 = Gate state unchanged, but time limit reached
+     * 11 = Close initiated by Policy Server or CMTS, volume limit reached
+     * 12 = Close initiated by Policy Server or CMTS, time limit reached
+     * 13 = Close initiated by CMTS, other
+     * 14 = Gate state unchanged, but SharedResourceID updated
+     * 15 = Close initiated by CMTS due to loss of shared resource
+     * 65535 = Other
+     * </pre>
+     */
+    enum GateStateReasonType {
+        ZERO((short)0),
+        RESERVATION_REASSIGNMENT((short) 1),
+        LACK_OF_DOCSIS_MAC_LAYER_RESPONSES((short) 2),
+        T1_EXPIRATION((short)3),
+        T2_EXPIRATION((short)4),
+        T3_EXPIRATION((short)5),
+        LACK_OF_RESERVATION_MAINTENANCE((short)6),
+        UNCHANGED_BUT_VOLUME_LIMIT_REACHED((short)7),
+        T4_EXPIRATION((short)8),
+        UNCHANGED_BUT_T2_EXPIRATION_CAUSED_RESERVATION_REDUCTION((short)9),
+        UNCHANGED_BUT_TIME_LIMIT_REACHED((short)10),
+        VOLUME_LIMIT_REACHED((short)11),
+        TIME_LIMIT_REACHED((short)12),
+        CMTS_OTHER((short)13),
+        UNCHANGED_BUT_SHARED_RESOURCE_ID_CHANGED((short)14),
+        LOSS_OF_SHARED_RESOURCE((short)15),
+        OTHER((short) 65535);
+
+        GateStateReasonType(short value) {
+            this.value = value;
+            this.displayName = converter.convert(name());
+        }
+
+        public short getValue() {
+            return value;
+        }
+
+        public static GateStateReasonType valueOf(short v) {
+            for (GateStateReasonType type : GateStateReasonType.values()) {
+                if (type.getValue() == v) {
+                    return type;
+                }
+            }
+            throw new IllegalArgumentException("not supported value: " + v);
+        }
+
+        private final short value;
+        private final String displayName;
+
+        public String toString() {
+            return displayName + "(" + getValue() + ")";
+        }
+    }
+
+}
diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IGateTimeInfo.java b/packetcable-driver/src/main/java/org/pcmm/gates/IGateTimeInfo.java
new file mode 100644 (file)
index 0000000..75f8ab3
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 CableLabs and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates;
+
+import org.pcmm.base.IPCMMBaseObject;
+
+/**
+ *
+ * From the Packetcable Multimedia specification section 6.4.2.12
+ *
+ *The Gate Time Info object contains the total amount of time the Gate has been in the Committed and
+ * Committed Recovery states. This counter MUST be stopped upon the Gate transitioning out of the
+ * Committed or Committed Recovery states to either the RESERVED state or AUTHORIZED state. If the
+ * Gate subsequently transitions back to the Committed state, this counter MUST be restarted where
+ * it last stopped, i.e., when transitioning out of the Committed or Committed Recovery states.
+ */
+public interface IGateTimeInfo extends IPCMMBaseObject {
+
+    /**
+     * The S-Type for Gate Time Info
+     */
+    byte STYPE = 1;
+
+
+    /**
+     * Time Committed total amount of time the Gate has been in the Committed and Committed
+     * Recovery states
+     *
+     * @return time in seconds;
+     */
+    int getGateTimeInfo();
+}
diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IGateUsageInfo.java b/packetcable-driver/src/main/java/org/pcmm/gates/IGateUsageInfo.java
new file mode 100644 (file)
index 0000000..dddf88e
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 CableLabs and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates;
+
+import org.pcmm.base.IPCMMBaseObject;
+
+/**
+ *
+ * From the Packetcable Multimedia specification section 6.4.2.13
+ *
+ * The Gate Usage Info object contains a counter indicating the number of kilobytes transmitted
+ * over this Gate.
+ */
+public interface IGateUsageInfo extends IPCMMBaseObject {
+
+    /**
+     * The S-Type for Gate Time Info
+     */
+    byte STYPE = 1;
+
+
+    /**
+     * Time Committed total amount of time the Gate has been in the Committed and Committed
+     * Recovery states
+     *
+     * @return usage in kbps;
+     */
+   long getGateUsageInfo();
+}
\ No newline at end of file
index 75af85bde6c82a4888f351d14e63d989333b15b2..001817da9f5d1e794d89c6379f9a786ea39e6d19 100644 (file)
@@ -26,9 +26,9 @@ public interface IPCMMError extends IPCMMBaseObject {
 
        /**
         * Returns the error sub-code
-        * @return - not null (mostly will be NA)
+        * @return - the sub error code
         */
-       ErrorCode getErrorSubcode();
+       short getErrorSubcode();
 
        /**
         * Returns the error's description
index 5f8cbe183c3fbd9656ca0cb3957adf871dc1908f..99acee0b681258c8465042b069d7a48bc1e3c260 100644 (file)
@@ -47,6 +47,12 @@ public interface IPCMMGate {
      */
     void setGateID(IGateID gateid);
 
+    /**
+     * gateState is the handle for the Gate State.
+     *
+     */
+    void setGateState(IGateState gateState);
+    
     /**
      * (i.e., QoS limits, timers, etc.).
      *
@@ -69,6 +75,10 @@ public interface IPCMMGate {
     void setTransactionID(ITransactionID transactionID);
 
     void setError(IPCMMError error);
+    
+    void setGateTimeInfo(IGateTimeInfo gateTimeInfo);
+    
+    void setGateUsageInfo(IGateUsageInfo gateUsageInfo);
 
     ITransactionID getTransactionID();
 
@@ -79,6 +89,14 @@ public interface IPCMMGate {
      */
     IGateID getGateID();
 
+    /**
+     * GateState is the handle for the GateState.
+     *
+     * @return gateSTATE
+     */
+    IGateState getGateState();
+    
+    
     /**
      * AMID is the handle that identifies the Application Manager and
      * Application Type
@@ -121,6 +139,9 @@ public interface IPCMMGate {
      */
     IPCMMError getError();
 
+       IGateTimeInfo getGateTimeInfo();
+       
+       IGateUsageInfo getGateUsageInfo();
 
     /**
      *
index 80f6ea3391c1e4126f3b4717ff71fcdf1107ebf6..f887240255f0872d1f6857f72e527b742abbe899 100644 (file)
@@ -12,7 +12,7 @@ import org.pcmm.base.IPCMMBaseObject;
 
 public interface ITrafficProfile extends IPCMMBaseObject {
 
-    // Authorized
+    // AUTHORIZED
     byte DEFAULT_ENVELOP = 0x7;
 
     byte getEnvelop();
index f2124c9e9afc4f271b277933012af276a2f168a6..cfcab5e172080aee0bf0d4b28f7c1d9cb4b8acee 100644 (file)
@@ -85,6 +85,14 @@ public class AMID extends PCMMBaseObject implements IAMID {
         return result;
     }
 
+    @Override
+    public String toString() {
+        return "AMID{" +
+                "appType=" + appType +
+                ", appMgrTag=" + appMgrTag +
+                '}';
+    }
+
     /**
      * Returns an AMID object from a byte array
      * @param data - the data to parse
index 220e92a6e0a1370b7258dbfd00bbe1e2f9780ed2..361ba1fcf7a71c557a3048a2588662af89647d2b 100644 (file)
@@ -52,17 +52,17 @@ public class BEEnvelop {
     private final int maxTrafficBurst;
 
     /**
-     * Minimum Reserved Traffic Rate is a 4-byte unsigned integer field specifying the minimum rate, in bits/sec,
+     * Minimum RESERVED Traffic Rate is a 4-byte unsigned integer field specifying the minimum rate, in bits/sec,
      * reserved for this Service Flow. This field is fully defined in section C.2.2.5.4. A default Mini Rate of 0 SHOULD
-     * be used if a specific Minimum Reserved Traffic Rate is not required.
+     * be used if a specific Minimum RESERVED Traffic Rate is not required.
      */
     private final int minResTrafficRate;
 
     /**
-     * Assumed Minimum Reserved Traffic Rate Packet Size is a 2-byte unsigned integer field specifying an assumed
-     * minimum packet size, in bytes, for which the Minimum Reserved Traffic Rate will be provided for this flow. This
-     * field is fully defined in section C.2.2.5.5. A default Assumed Minimum Reserved Traffic Rate Packet Size of
-     * 0 SHOULD be used if a specific Assumed Minimum Reserved Traffic Rate Packet size is not required. Upon receip
+     * Assumed Minimum RESERVED Traffic Rate Packet Size is a 2-byte unsigned integer field specifying an assumed
+     * minimum packet size, in bytes, for which the Minimum RESERVED Traffic Rate will be provided for this flow. This
+     * field is fully defined in section C.2.2.5.5. A default Assumed Minimum RESERVED Traffic Rate Packet Size of
+     * 0 SHOULD be used if a specific Assumed Minimum RESERVED Traffic Rate Packet size is not required. Upon receip
      * of a value of 0 the CMTS MUST utilize its implementation-specific default size for this parameter, not 0 bytes.
      */
     private final short assumedMinConcatBurst;
@@ -144,8 +144,8 @@ public class BEEnvelop {
      * @param transPolicy - the Requested Transmission Policy
      * @param maxSusTrafficRate - the Maximum Sustained Traffic Rate
      * @param maxTrafficBurst - the Maximum Traffic Burst Rate
-     * @param minResTrafficRate - the Minimum Reserved Traffic Rate
-     * @param assumedMinConcatBurst - the Assumed Minimum Reserved Traffic Rate Packet Size
+     * @param minResTrafficRate - the Minimum RESERVED Traffic Rate
+     * @param assumedMinConcatBurst - the Assumed Minimum RESERVED Traffic Rate Packet Size
      * @param maxConcatBurst - the Maximum Concatenated Burst
      * @param upPeakTrafficRate - the Upstream Peak Traffic Rate
      * @param reqAttrMask - the Required Attribute Mask
index 2b9b55b6efc481a951523308822d118cb6daeec3..cc1c706d4db43ca916905ab74b0262444086fd0a 100644 (file)
@@ -69,7 +69,7 @@ public class BestEffortService extends PCMMBaseObject implements ITrafficProfile
        protected BestEffortService(final byte envelope, final BEEnvelop auth, final BEEnvelop reserved,
                                                         final BEEnvelop committed) {
                super(SNum.TRAFFIC_PROFILE, STYPE);
-               if (auth == null) throw new IllegalArgumentException("Authorized envelope must not be null");
+               if (auth == null) throw new IllegalArgumentException("AUTHORIZED envelope must not be null");
 
                // TODO - Cannot figure out any other means to parse the bytes unless this is true. Determine if correct???
                if (reserved == null && committed != null)
diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateState.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateState.java
new file mode 100644 (file)
index 0000000..92006ed
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2015 CableLabs and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates.impl;
+
+import com.google.common.base.Objects;
+import org.pcmm.base.impl.PCMMBaseObject;
+import org.pcmm.gates.IGateState;
+import org.umu.cops.stack.COPSMsgParser;
+
+/**
+ * Implementation of the IGateID interface
+ */
+public class GateState extends PCMMBaseObject implements IGateState {
+
+    /**
+     * The Gate State value (unsigned 32 bit integer)
+     */
+    final GateStateType gateState;
+
+    /**
+     * The Gate State value (unsigned 32 bit integer)
+     */
+    final GateStateReasonType gateStateReason;
+
+    /**
+     * Constructor
+     */
+    public GateState(final GateStateType gateState, final GateStateReasonType gateStateReason) {
+        super(SNum.GATE_STATE, STYPE);
+        this.gateState = gateState;
+        this.gateStateReason = gateStateReason;
+    }
+
+    @Override
+    public GateStateType getGateState() {
+        return gateState;
+    }
+
+       @Override
+       public GateStateReasonType getGateStateReason() {
+               return gateStateReason;
+       }
+
+    @Override
+    protected byte[] getBytes() {
+        return COPSMsgParser.shortToBytes(gateState.getValue());
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof GateID)) {
+            return false;
+        }
+        if (!super.equals(o)) {
+            return false;
+        }
+        final GateState gateSTATE = (GateState) o;
+        return gateState == gateSTATE.gateState;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(super.hashCode(), gateState, gateStateReason);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s/%s", gateState.toString(), gateStateReason.toString());
+    }
+
+    /**
+     * Returns a GateState object from a byte array
+     * @param data - the data to parse
+     * @return - the object
+     * TODO - make me more robust as RuntimeExceptions can be thrown here.
+     */
+    public static GateState parse(final byte[] data) {
+        return new GateState(GateStateType.valueOf(COPSMsgParser.bytesToShort(data[0], data[1])),
+                       GateStateReasonType.valueOf(COPSMsgParser.bytesToShort(data[2], data[3])));
+    }
+
+
+}
diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateTimeInfo.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateTimeInfo.java
new file mode 100644 (file)
index 0000000..e48a7ce
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 CableLabs and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates.impl;
+
+import org.pcmm.base.impl.PCMMBaseObject;
+import org.pcmm.gates.IGateTimeInfo;
+import org.umu.cops.stack.COPSMsgParser;
+
+/**
+ * Implementation of the IGateSpec interface
+ */
+public class GateTimeInfo extends PCMMBaseObject implements IGateTimeInfo {
+
+       final int gateTimeInfo;
+
+       public GateTimeInfo(final int gateTimeInfo) {
+               super(SNum.GATE_TIME_INFO, STYPE);
+               this.gateTimeInfo = gateTimeInfo;
+       }
+
+    @Override
+    public int getGateTimeInfo() {
+        return gateTimeInfo;
+    }
+
+
+    @Override
+    protected byte[] getBytes() {
+        return COPSMsgParser.intToBytes(gateTimeInfo);
+    }
+
+    public static GateTimeInfo parse(final byte[] data) {
+        return new GateTimeInfo((COPSMsgParser.bytesToInt(data[0], data[1],data[2], data[3])));
+    }
+}
diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateUsageInfo.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateUsageInfo.java
new file mode 100644 (file)
index 0000000..39c2a71
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 CableLabs and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.gates.impl;
+
+import org.pcmm.base.impl.PCMMBaseObject;
+import org.pcmm.gates.IGateUsageInfo;
+import org.umu.cops.stack.COPSMsgParser;
+
+/**
+ * Implementation of the IGateSpec interface
+ */
+public class GateUsageInfo extends PCMMBaseObject implements IGateUsageInfo {
+
+       final long gateUsageInfo;
+
+       public GateUsageInfo(final long gateUsageInfo) {
+
+               super(SNum.GATE_USAGE_INFO, STYPE);
+               this.gateUsageInfo = gateUsageInfo;
+       }
+
+    @Override
+    public long getGateUsageInfo() {
+        return gateUsageInfo;
+    }
+
+
+
+    @Override
+    protected byte[] getBytes() {
+       byte[] first = COPSMsgParser.intToBytes((int)gateUsageInfo>>32);
+       byte[] second = COPSMsgParser.intToBytes((int)gateUsageInfo);
+       return new byte[first.length+second.length];
+    }
+
+    public static GateUsageInfo parse(final byte[] data) {
+        return new GateUsageInfo(
+                       (long)(COPSMsgParser.bytesToInt(data[0], data[1],data[2], data[3]))<<32
+                       | (COPSMsgParser.bytesToInt(data[4], data[5],data[6], data[7]))& 0xFFFFFFFFL);
+    }
+}
index 39137471d0b5e22d9cff1fb8b3a56876c35dacca..3a550b9c93716d28284da04c7f1b8e84297d9141 100644 (file)
@@ -25,14 +25,14 @@ public class PCMMError extends PCMMBaseObject implements IPCMMError {
     /**
      * The error sub-code (defaults to NA)
      */
-    private final ErrorCode subErrCode;
+    private final short subErrCode;
 
     /**
      * Constructor without a sub-code which will then be set to NA
      * @param errorCode - the error code (required and not NA)
      */
     public PCMMError(final ErrorCode errorCode) {
-        this(errorCode, null);
+        this(errorCode, (short)0);
     }
 
     /**
@@ -40,13 +40,12 @@ public class PCMMError extends PCMMBaseObject implements IPCMMError {
      * @param errorCode - the error code (required and not NA)
      * @param subErrCode - the sub-code (defaults to NA when null)
      */
-    public PCMMError(final ErrorCode errorCode, final ErrorCode subErrCode) {
+    public PCMMError(final ErrorCode errorCode, final short subErrCode) {
         super(SNum.PCMM_ERROR, STYPE);
         if (errorCode == null || errorCode.equals(ErrorCode.NA))
             throw new IllegalArgumentException("ErrorCode is required and must not be NA");
         this.errorCode = errorCode;
-        if (subErrCode == null) this.subErrCode = ErrorCode.NA;
-        else this.subErrCode = subErrCode;
+        this.subErrCode = subErrCode;
     }
 
     @Override
@@ -55,7 +54,7 @@ public class PCMMError extends PCMMBaseObject implements IPCMMError {
     }
 
     @Override
-    public ErrorCode getErrorSubcode() {
+    public short getErrorSubcode() {
         return subErrCode;
     }
 
@@ -66,8 +65,22 @@ public class PCMMError extends PCMMBaseObject implements IPCMMError {
      */
     @Override
     public String getDescription() {
-        String hex = Integer.toHexString(subErrCode.getCode() & 0xFFFF);
-        return "Error Code: " + errorCode.getCode() + " Error Subcode : " + hex + "  " + errorCode.getDescription();
+        //Error-Subcode is a 2-byte unsigned integer field used to provide further information about the error.
+        // In the case of Error-Codes 6, 7 and 17, this 16-bit field MUST contain, as two 8-bit values the
+        // S-Num and S-Type of the object that is missing or in error.
+        String subcode;
+        switch (errorCode) {
+            case MISSING_REQ_OBJ:
+            case INVALID_OBJ:
+            case INVALID_FIELD:
+                byte[] sParts = COPSMsgParser.shortToBytes(subErrCode);
+                subcode = String.format("S-Num: %d, S-Type: %d", sParts[0], sParts[1]);
+                break;
+            default:
+                subcode = "Subcode: " + Integer.toHexString(subErrCode & 0xFFFF);
+        }
+
+        return "Error Code: " + errorCode.getCode() + " " + subcode + "  " + errorCode.getDescription();
     }
 
     @Override
@@ -78,7 +91,7 @@ public class PCMMError extends PCMMBaseObject implements IPCMMError {
     @Override
     protected byte[] getBytes() {
         final byte[] errorCodeBytes = COPSMsgParser.shortToBytes(errorCode.getCode());
-        final byte[] subErrCodeBytes = COPSMsgParser.shortToBytes(subErrCode.getCode());
+        final byte[] subErrCodeBytes = COPSMsgParser.shortToBytes(subErrCode);
         final byte[] data = new byte[errorCodeBytes.length + subErrCodeBytes.length];
         System.arraycopy(errorCodeBytes, 0, data, 0, errorCodeBytes.length);
         System.arraycopy(subErrCodeBytes, 0, data, errorCodeBytes.length, subErrCodeBytes.length);
@@ -104,7 +117,7 @@ public class PCMMError extends PCMMBaseObject implements IPCMMError {
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + errorCode.hashCode();
-        result = 31 * result + subErrCode.hashCode();
+        result = 31 * result + subErrCode;
         return result;
     }
 
@@ -116,7 +129,7 @@ public class PCMMError extends PCMMBaseObject implements IPCMMError {
      */
     public static PCMMError parse(final byte[] data) {
         return new PCMMError(ErrorCode.valueOf(COPSMsgParser.bytesToShort(data[0], data[1])),
-                ErrorCode.valueOf((COPSMsgParser.bytesToShort(data[2], data[3]))));
+                (COPSMsgParser.bytesToShort(data[2], data[3])));
 
     }
 
index eda3da0c68ca2a61cc781bcb071a6054962dcfd7..af3fac1120d53ba74135c69605ddb41937609519 100644 (file)
@@ -44,6 +44,9 @@ public class PCMMGateReq implements IPCMMGate {
     // synchronization purposes
     private IGateID gateID;
     private IPCMMError error;
+    private IGateState igateState;
+    private IGateTimeInfo gateTimeInfo;
+    private IGateUsageInfo gateUsageInfo;
 
     /**
      * Constructor
@@ -57,8 +60,9 @@ public class PCMMGateReq implements IPCMMGate {
      * @param error - the error
      */
     public PCMMGateReq(IAMID iamid, ISubscriberID subscriberID, ITransactionID transactionID,
-                       IGateSpec gateSpec, ITrafficProfile trafficProfile, List<IClassifier> classifiers, IGateID gateID,
-                       IPCMMError error) {
+                       IGateSpec gateSpec, ITrafficProfile trafficProfile, List<IClassifier> classifiers,
+                       IGateID gateID,IPCMMError error,IGateState igateState,
+                       IGateTimeInfo gateTimeInfo,IGateUsageInfo gateUsageInfo ) {
         // TODO - determine if and when this attribute should be used
         this.multicast = false;
 
@@ -70,6 +74,9 @@ public class PCMMGateReq implements IPCMMGate {
         this.classifiers = Lists.newArrayList(classifiers);
         this.gateID = gateID;
         this.error = error;
+        this.igateState = igateState;
+        this.gateTimeInfo = gateTimeInfo;
+        this.gateUsageInfo = gateUsageInfo;
     }
 
     /**
@@ -86,6 +93,10 @@ public class PCMMGateReq implements IPCMMGate {
         ITrafficProfile trafficProfile = null;
         List<IClassifier> classifiers = Lists.newArrayListWithExpectedSize(4);
         PCMMError error = null;
+        GateState gateState = null;
+        GateTimeInfo gateTimeInfo = null;
+        GateUsageInfo gateUsageInfo = null;
+
 
         short offset = 0;
         while (offset + 5 < data.length) {
@@ -138,6 +149,20 @@ public class PCMMGateReq implements IPCMMGate {
                 case PCMM_ERROR:
                     error = PCMMError.parse(dataBuffer);
                     break;
+                //adding GATE_STATE
+                case GATE_STATE:
+                        gateState = GateState.parse(dataBuffer);
+                     break;
+                //adding GATE_TIME_INFO
+                     case GATE_TIME_INFO:
+                        gateTimeInfo = GateTimeInfo.parse(dataBuffer);
+                       logger.info("Gate Time Info: "+gateTimeInfo);
+                     break;
+                //adding GATE_USAGE_INFO
+                case GATE_USAGE_INFO:
+                        gateUsageInfo = GateUsageInfo.parse(dataBuffer);
+                        logger.info("Gate Usage Info: "+gateUsageInfo);
+                     break;
             default:
                 logger.warn("Unhandled Object skept : S-NUM=" + sNum
                                    + "  S-TYPE=" + sType + "  LEN=" + len);
@@ -145,7 +170,8 @@ public class PCMMGateReq implements IPCMMGate {
             offset += len;
         }
 
-        return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile, classifiers, gateID, error);
+        return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile,
+                       classifiers, gateID, error, gateState, gateTimeInfo,gateUsageInfo);
     }
 
     @Override
@@ -160,6 +186,11 @@ public class PCMMGateReq implements IPCMMGate {
 
     }
 
+    @Override
+    public void setGateState(IGateState gatestate) {
+        this.igateState = gatestate;
+    }
+
     @Override
     public void setTransactionID(ITransactionID transactionID) {
         this.transactionID = transactionID;
@@ -186,11 +217,28 @@ public class PCMMGateReq implements IPCMMGate {
         this.trafficProfile = profile;
     }
 
+    @Override
+    public void setGateTimeInfo(IGateTimeInfo gateTimeInfo) {
+        this.gateTimeInfo = gateTimeInfo;
+    }
+
+    @Override
+    public void setGateUsageInfo(IGateUsageInfo gateUsageInfo) {
+        this.gateUsageInfo = gateUsageInfo;
+    }
+
+
     @Override
     public IGateID getGateID() {
         return gateID;
     }
 
+   @Override
+   public IGateState getGateState() {
+        return igateState;
+   }
+
+
     @Override
     public IAMID getAMID() {
         return iamid;
@@ -228,6 +276,16 @@ public class PCMMGateReq implements IPCMMGate {
         return error;
     }
 
+    @Override
+    public IGateTimeInfo getGateTimeInfo() {
+         return gateTimeInfo;
+    }
+
+    @Override
+    public IGateUsageInfo getGateUsageInfo() {
+         return gateUsageInfo;
+    }
+
     public void setError(IPCMMError error) {
         this.error = error;
     }
@@ -258,6 +316,15 @@ public class PCMMGateReq implements IPCMMGate {
                 byteList.addAll(Bytes.asList(classifier.getAsBinaryArray()));
             }
         }
+        if (getGateState() != null) {
+            byteList.addAll(Bytes.asList(getGateState().getAsBinaryArray()));
+        }
+        if (getGateTimeInfo() != null) {
+            byteList.addAll(Bytes.asList(getGateTimeInfo().getAsBinaryArray()));
+        }
+        if (getGateUsageInfo() != null) {
+            byteList.addAll(Bytes.asList(getGateUsageInfo().getAsBinaryArray()));
+        }
         return Bytes.toArray(byteList);
     }
 
index c6808c842d9de69a47802d4b2cde9b108eb6e0c7..943d7443e267a4b0ef60d0bcf43d8f819fffff01 100644 (file)
@@ -32,7 +32,7 @@ import java.util.concurrent.Executors;
  */
 public abstract class AbstractPCMMServer implements IPCMMServer {
 
-       private final static Logger logger = LoggerFactory.getLogger(AbstractPCMMServer.class);
+       private static final Logger logger = LoggerFactory.getLogger(AbstractPCMMServer.class);
 
        /*
         * A ServerSocket to accept messages ( OPN requests)
index af9645e65b47ef05617c8e0a789e283fb7460dd4..d312648a752d1d34348c2760d57e36c6bdcd4be8 100644 (file)
@@ -197,18 +197,24 @@ public class COPSPepConnection extends COPSConnection {
                     return;
                 }
 
+
                 // Check message type
                 // TODO FIXME - Use of manager object could result in a NPE
                 if (decision.getFlag().equals(DecisionFlag.REQSTATE)) {
-                    if (decision.getCommand().equals(Command.REMOVE))
+                    if (decision.getCommand().equals(Command.REMOVE)) {
                         // Delete Request State
                         manager.processDeleteRequestState(dMsg);
-                    else
+                    } else if (decision.getCommand().equals(Command.INSTALL)) {
                         // Open new Request State
                         handleOpenNewRequestStateMsg(handle);
-                } else
+                    }
+                    else {
+                        logger.error("Unknown command");
+                    }
+                } else {
                     // Decision
                     manager.processDecision(dMsg);
+                }
             }
         }
     }
@@ -220,10 +226,11 @@ public class COPSPepConnection extends COPSConnection {
      */
     private void handleOpenNewRequestStateMsg(final COPSHandle handle) throws COPSPepException {
         final COPSPepReqStateMan manager = _managerMap.get(handle);
-        if (manager == null)
+        if (manager == null) {
             logger.warn("Unable to find state manager with key - " + handle.getId().str());
-        else
+        } else {
             manager.processOpenNewRequestState();
+        }
     }
 
     /**
@@ -236,10 +243,11 @@ public class COPSPepConnection extends COPSConnection {
         }
 
         final COPSPepReqStateMan manager = _managerMap.get(cMsg.getClientHandle());
-        if (manager == null)
+        if (manager == null) {
             logger.warn("Unable to find state manager with key - " + cMsg.getClientHandle().getId().str());
-        else
+        } else {
             manager.processSyncStateRequest(cMsg);
+        }
     }
 
     /**
index 689680562b6c017c9a475ae22af65a80bb1e97a0..4a72fed5376e8ceb0f27e271b77379b913375b67 100644 (file)
@@ -17,12 +17,12 @@ public class PCMMErrorTest {
 
     @Test(expected = IllegalArgumentException.class)
     public void nullErrorAndSubCodes() {
-        new PCMMError(null, null);
+        new PCMMError(null, (short)0);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void nullErrorCode() {
-        new PCMMError(null, ErrorCode.DOCSIS_1_CM);
+        new PCMMError(null, (short)0);
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -32,9 +32,9 @@ public class PCMMErrorTest {
 
     @Test
     public void construction() {
-        final PCMMError error = new PCMMError(ErrorCode.TRANSPORT_ERROR, null);
+        final PCMMError error = new PCMMError(ErrorCode.TRANSPORT_ERROR, (short)0);
         Assert.assertEquals(ErrorCode.TRANSPORT_ERROR, error.getErrorCode());
-        Assert.assertEquals(ErrorCode.NA, error.getErrorSubcode());
+        Assert.assertEquals(ErrorCode.NA.getCode(), error.getErrorSubcode());
 
         final byte[] dataBytes = error.getBytes();
         Assert.assertEquals(4, dataBytes.length);
@@ -47,7 +47,7 @@ public class PCMMErrorTest {
 
     @Test
     public void byteParsing() {
-        final PCMMError error = new PCMMError(ErrorCode.INVALID_FIELD, ErrorCode.INVALID_SUB_ID);
+        final PCMMError error = new PCMMError(ErrorCode.INVALID_FIELD, ErrorCode.INVALID_SUB_ID.getCode());
         final PCMMError parsed = PCMMError.parse(error.getBytes());
         Assert.assertEquals(error, parsed);
     }
index 5d9147e75c2ded2941af3452303ef1a860616c0c..c31e06a5ed48f3cadf05141f6ff3a18f6862212a 100644 (file)
@@ -1,13 +1,14 @@
 # The CMTS Emulator's communications port number
 port: 3918
+numberOfSupportedClassifiers: 4
 
-# The configured gates
-gates:
-  - type: UPSTREAM
+# The configured service class names
+serviceClassNames:
+  - direction: UPSTREAM
     names:
       - extrm_up
       - foo_up
-  - type: DOWNSTREAM
+  - direction: DOWNSTREAM
     names:
       - extrm_dn
       - foo_dn
index 4f1770a791b831c8561ca901aa1c1badf28ed95a..12052fdccdabfc3243ef94c8f8664fd95ff03106 100644 (file)
@@ -8,57 +8,38 @@
 
 package org.pcmm.rcd.impl;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
-import org.pcmm.gates.IGateSpec.Direction;
-import org.pcmm.rcd.ICMTS;
+import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.io.FileInputStream;
+import com.google.common.collect.Maps;
 import java.io.IOException;
 import java.net.Socket;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
+import org.pcmm.rcd.ICMTS;
 
 /**
  * Mock CMTS that can be used for testing. startServer() is called to start required threads after instantiation.
  */
 public class CMTS extends AbstractPCMMServer implements ICMTS {
 
+    /**
+     * Emulator configuration
+     */
+    private final CMTSConfig config;
+
        /**
         * Receives messages from the COPS client
         */
        private final Map<String, IPCMMClientHandler> handlerMap;
 
-       /**
-        * The configured gates
-        */
-       private final Map<Direction, Set<String>> gateConfig;
-
-       /**
-        * The connected CMTSs and whether or not they are up
-        */
-       private final Map<String, Boolean> cmStatus;
-
        /**
         * Constructor for having the server port automatically assigned
         * Call getPort() after startServer() is called to determine the port number of the server
         */
-       public CMTS(final Map<Direction, Set<String>> gateConfig, final Map<String, Boolean> cmStatus) {
-               this(0, gateConfig, cmStatus);
-       }
-
-       /**
-        * Constructor for starting the server to a pre-defined port number
-        * @param port - the port number on which to start the server.
-        */
-       public CMTS(final int port, final Map<Direction, Set<String>> gateConfig, final Map<String, Boolean> cmStatus) {
-               super(port);
-               if (gateConfig == null || cmStatus == null) throw new IllegalArgumentException("Config must not be null");
-               this.gateConfig = Collections.unmodifiableMap(gateConfig);
-               this.cmStatus = Collections.unmodifiableMap(cmStatus);
-               handlerMap = new ConcurrentHashMap<>();
-       }
+       public CMTS(final CMTSConfig config) {
+        super(checkNotNull(config, "config must not be null").getPort());
+        this.config = config;
+        handlerMap = Maps.newConcurrentMap();
+    }
 
        @Override
        public void stopServer() {
@@ -72,11 +53,13 @@ public class CMTS extends AbstractPCMMServer implements ICMTS {
        protected IPCMMClientHandler getPCMMClientHandler(final Socket socket) throws IOException {
                final String key = socket.getLocalAddress().getHostName() + ':' + socket.getPort();
                if (handlerMap.get(key) == null) {
-                       final IPCMMClientHandler handler = new CmtsPcmmClientHandler(socket, gateConfig, cmStatus);
+                       final IPCMMClientHandler handler = new CmtsPcmmClientHandler(socket, config);
                        handler.connect();
                        handlerMap.put(key, handler);
                        return handler;
-               } else return handlerMap.get(key);
+               } else {
+            return handlerMap.get(key);
+        }
        }
 
        /**
@@ -85,83 +68,13 @@ public class CMTS extends AbstractPCMMServer implements ICMTS {
         * @throws IOException - should the server fail to start for reasons such as port contention.
         */
        public static void main(final String[] args) throws IOException {
-               final CmtsYaml config = getConfig(args[0]);
-               final CMTS cmts = new CMTS(config.port, config.getGates(), config.getCmStatus());
-               cmts.startServer();
-       }
-
-       /**
-        * Returns the object that represents the YAML file
-        * @param uri - the location of the YAML file
-        * @return - the config object
-        * @throws IOException - when the URI does not contain the proper YAML file
-        */
-       private static CmtsYaml getConfig(final String uri) throws IOException {
-               final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
-               return mapper.readValue(new FileInputStream(uri), CmtsYaml.class);
-       }
-
-       /**
-        * Class to hold configuration settings in a YAML file
-        */
-       public static class CmtsYaml {
-               @JsonProperty("port")
-               private int port;
-
-               @JsonProperty("gates")
-               private Collection<GateConfigYaml> gateConfigs;
-
-               @JsonProperty("cmStatuses")
-               private Collection<CmStatusYaml> cmStatuses;
-
-               public Map<Direction, Set<String>> getGates() {
-                       final Map<Direction, Set<String>> out = new HashMap<>();
-
-                       for (final GateConfigYaml gateConfig : gateConfigs) {
-                               final Direction direction;
-                               if (gateConfig.gateType.equalsIgnoreCase("UPSTREAM")) {
-                                       direction = Direction.UPSTREAM;
-                               } else if (gateConfig.gateType.equalsIgnoreCase("DOWNSTREAM")) {
-                                       direction = Direction.DOWNSTREAM;
-                               } else direction = null;
+               if (args.length != 1) {
+            throw new IllegalArgumentException("expected arguments: <cmts_yaml_config_file>");
+        }
 
-                               if (direction != null) {
-                                       out.put(direction, gateConfig.gateNames);
-                               }
-                       }
-                       return out;
-               }
-
-               public Map<String, Boolean> getCmStatus() {
-                       final Map<String, Boolean> out = new HashMap<>();
-
-                       for (final CmStatusYaml cmStatus : cmStatuses) {
-                               out.put(cmStatus.hostIp, cmStatus.status);
-                       }
-                       return out;
-               }
-       }
-
-       /**
-        * Class to hold the YAML gate configuration values
-        */
-       public static class GateConfigYaml {
-               @JsonProperty("type")
-               private String gateType;
-
-               @JsonProperty("names")
-               private Set<String> gateNames;
-       }
-
-       /**
-        * Class to hold the YAML Cable Modem configuration values
-        */
-       public static class CmStatusYaml {
-               @JsonProperty("host")
-               private String hostIp;
-
-               @JsonProperty("status")
-               private boolean status;
+               final CMTSConfig config = CMTSConfig.loadConfig(args[0]);
+               final CMTS cmts = new CMTS(config);
+               cmts.startServer();
        }
 
 }
diff --git a/packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CMTSConfig.java b/packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CMTSConfig.java
new file mode 100644 (file)
index 0000000..894df26
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015 CableLabs and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.rcd.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import org.pcmm.gates.IGateSpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class to hold configuration settings in a YAML file
+ */
+public class CMTSConfig {
+
+    private static final Logger logger = LoggerFactory.getLogger(CMTSConfig.class);
+
+    /**
+     * Returns the object that represents the YAML file
+     * @param uri - the location of the YAML file
+     * @return - the config object
+     * @throws IOException - when the URI does not contain the proper YAML file
+     */
+    public static CMTSConfig loadConfig(final String uri) throws IOException {
+        final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+        final CmtsYmal cmtsYmal = mapper.readValue(new FileInputStream(uri), CmtsYmal.class);
+
+        final Map<IGateSpec.Direction, Set<String>> scns = cmtsYmal.getServiceClassNames();
+
+        final Set<String> upstreamSCNs = scns.containsKey(IGateSpec.Direction.UPSTREAM)
+                ? scns.get(IGateSpec.Direction.UPSTREAM)
+                : Collections.<String>emptySet();
+
+        final Set<String> downstreamSCNs = scns.containsKey(IGateSpec.Direction.DOWNSTREAM)
+                ? scns.get(IGateSpec.Direction.DOWNSTREAM)
+                : Collections.<String>emptySet();
+
+        if (upstreamSCNs.isEmpty() && downstreamSCNs.isEmpty()) {
+            logger.error("No upstream or downstream service class names defined in config");
+        }
+
+        return new CMTSConfig(cmtsYmal.getPort(),
+                cmtsYmal.getNumberOfSupportedClassifiers(),
+                upstreamSCNs,
+                downstreamSCNs,
+                cmtsYmal.getCmStatus());
+    }
+
+    private final int port;
+
+    private final short numberOfSupportedClassifiers;
+
+    private final ImmutableSet<String> upstreamServiceClassNames;
+
+    private final ImmutableSet<String> downstreamServiceClassNames;
+
+    private final ImmutableMap<String, Boolean> modemStatus;
+
+    public CMTSConfig(final int port, final short numberOfSupportedClassifiers,
+            final Set<String> upstreamServiceClassNames, final Set<String> downstreamServiceClassNames,
+            final Map<String, Boolean> modemStatus) {
+        checkNotNull(upstreamServiceClassNames, "upstreamServiceClassNames must not be null");
+        checkNotNull(downstreamServiceClassNames, "downstreamServiceClassNames must not be null");
+        checkNotNull(modemStatus, "modemStatus must not be null");
+
+        this.port = port;
+        this.numberOfSupportedClassifiers = numberOfSupportedClassifiers;
+        this.upstreamServiceClassNames =  ImmutableSet.copyOf(upstreamServiceClassNames);
+        this.downstreamServiceClassNames = ImmutableSet.copyOf(downstreamServiceClassNames);
+        this.modemStatus = ImmutableMap.copyOf(modemStatus);
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public short getNumberOfSupportedClassifiers() {
+        return numberOfSupportedClassifiers;
+    }
+
+    public ImmutableSet<String> getUpstreamServiceClassNames() {
+        return upstreamServiceClassNames;
+    }
+
+    public ImmutableSet<String> getDownstreamServiceClassNames() {
+        return downstreamServiceClassNames;
+    }
+
+    public ImmutableMap<String, Boolean> getModemStatus() {
+        return modemStatus;
+    }
+}
index b11abbf73433135061569d55f5d21238814c2def..585df414e33883e05db40c54385770e94d8318af 100644 (file)
@@ -58,7 +58,7 @@ class CmtsDataProcessor implements COPSPepDataProcess {
                 final ITransactionID transactionID = PCMMGateReq.parse(new COPSData(data).getData()).getTransactionID();
 
                 // TODO - Determine how and why a response gate request can have only a transaction ID???
-                final IPCMMGate responseGate = new PCMMGateReq(null, null, transactionID, null, null, null, null, null);
+                final IPCMMGate responseGate = new PCMMGateReq(null, null, transactionID, null, null, null, null, null, null, null, null);
 
                 // TODO FIXME - Why is the key always null??? What value should be used here???
                 final String key = null;
index f2e549a23f6ae6e2c7e52cb337a478df998adfb5..85c8a22d2ca811af084feadf906a4f512cc8ff08 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.pcmm.rcd.impl;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import org.pcmm.gates.IGateSpec.Direction;
 import org.pcmm.messages.impl.MessageFactory;
 import org.pcmm.rcd.IPCMMServer.IPCMMClientHandler;
@@ -30,7 +32,7 @@ import java.util.concurrent.Callable;
  */
 public class CmtsPcmmClientHandler extends AbstractPCMMClient implements IPCMMClientHandler {
 
-    private final static Logger logger = LoggerFactory.getLogger(CmtsPcmmClientHandler.class);
+    private static final Logger logger = LoggerFactory.getLogger(CmtsPcmmClientHandler.class);
 
     /**
      * The thread accepting PEP COPS messages
@@ -38,40 +40,29 @@ public class CmtsPcmmClientHandler extends AbstractPCMMClient implements IPCMMCl
     private transient Thread thread;
 
     /**
-     * The configured gates
-     */
-    private final Map<Direction, Set<String>> gateConfig;
-
-    /**
-     * The connected cable modems and whether or not they are up
+     * Emulator configuration
      */
-    private final Map<String, Boolean> cmStatus;
+    private final CMTSConfig config;
 
     /**
      * Constructor when a socket connection has not been established
      * @param host - the host to connect
      * @param port - the port to connect
-     * @param gateConfig - the configured gates
-     * @param cmStatus - the configured cable modem and their state
+     * @param config - emulator configuration
      */
-    public CmtsPcmmClientHandler(final String host, final int port, final Map<Direction, Set<String>> gateConfig,
-                                 final Map<String, Boolean> cmStatus) {
+    public CmtsPcmmClientHandler(final String host, final int port, final CMTSConfig config) {
         super(host, port);
-        this.gateConfig = Collections.unmodifiableMap(gateConfig);
-        this.cmStatus = Collections.unmodifiableMap(cmStatus);
+        this.config = checkNotNull(config);
     }
 
     /**
      * Constructor with a connected socket.
      * @param socket - the socket connection
-     * @param gateConfig - the configured gates
-     * @param cmStatus - the configured cable modem and their state
+     * @param config - emulator configuration
      */
-    public CmtsPcmmClientHandler(final Socket socket, final Map<Direction, Set<String>> gateConfig,
-                                 final Map<String, Boolean> cmStatus) {
+    public CmtsPcmmClientHandler(final Socket socket, final CMTSConfig config) {
         super(socket);
-        this.gateConfig = Collections.unmodifiableMap(gateConfig);
-        this.cmStatus = Collections.unmodifiableMap(cmStatus);
+        this.config = checkNotNull(config);
     }
 
     public void stop() {
@@ -107,7 +98,7 @@ public class CmtsPcmmClientHandler extends AbstractPCMMClient implements IPCMMCl
                     final COPSKATimer kt = acceptMsg.getKATimer();
                     if (kt == null)
                         throw new COPSPepException("Mandatory COPS object missing (KA Timer)");
-                    short kaTimeVal = kt.getTimerVal();
+                    final short kaTimeVal = kt.getTimerVal();
 
                     // ACTimer
                     final COPSAcctTimer at = acceptMsg.getAcctTimer();
@@ -122,8 +113,7 @@ public class CmtsPcmmClientHandler extends AbstractPCMMClient implements IPCMMCl
                     sendRequest(reqMsg);
 
                     // Create the connection manager
-                    final PcmmCmtsConnection conn = new PcmmCmtsConnection(CLIENT_TYPE, getSocket(), gateConfig,
-                            cmStatus);
+                    final PcmmCmtsConnection conn = new PcmmCmtsConnection(CLIENT_TYPE, getSocket(), config);
                     conn.addRequestState(handle, new CmtsDataProcessor());
                     conn.setKaTimer(kaTimeVal);
                     conn.setAcctTimer(acctTimer);
index 959b7a29711c725f46be8f2c595e0a9acf6bef90..f2bb2be3aebc163d0e01200dbf07fc9113d4d67f 100644 (file)
 
 package org.pcmm.rcd.impl;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Objects;
+import com.google.common.primitives.Bytes;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+import java.util.Vector;
+import org.pcmm.base.impl.PCMMBaseObject;
+import org.pcmm.gates.IAMID;
+import org.pcmm.gates.IClassifier;
+import org.pcmm.gates.IGateID;
+import org.pcmm.gates.IGateSpec;
 import org.pcmm.gates.IGateSpec.Direction;
+import org.pcmm.gates.IGateState;
 import org.pcmm.gates.IPCMMError;
 import org.pcmm.gates.IPCMMError.ErrorCode;
+import org.pcmm.gates.ISubscriberID;
+import org.pcmm.gates.ITransactionID;
+import org.pcmm.gates.impl.AMID;
+import org.pcmm.gates.impl.DOCSISServiceClassNameTrafficProfile;
 import org.pcmm.gates.impl.GateID;
+import org.pcmm.gates.impl.GateSpec;
+import org.pcmm.gates.impl.GateState;
+import org.pcmm.gates.impl.GateTimeInfo;
+import org.pcmm.gates.impl.GateUsageInfo;
 import org.pcmm.gates.impl.PCMMError;
 import org.pcmm.gates.impl.PCMMGateReq;
+import org.pcmm.gates.impl.TransactionID;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.umu.cops.prpep.COPSPepException;
 import org.umu.cops.prpep.COPSPepMsgSender;
 import org.umu.cops.prpep.COPSPepReqStateMan;
-import org.umu.cops.stack.*;
+import org.umu.cops.stack.COPSClientSI;
+import org.umu.cops.stack.COPSContext;
+import org.umu.cops.stack.COPSData;
+import org.umu.cops.stack.COPSDecision;
 import org.umu.cops.stack.COPSDecision.DecisionFlag;
+import org.umu.cops.stack.COPSDecisionMsg;
+import org.umu.cops.stack.COPSException;
+import org.umu.cops.stack.COPSHandle;
+import org.umu.cops.stack.COPSMsgParser;
 import org.umu.cops.stack.COPSObjHeader.CNum;
 import org.umu.cops.stack.COPSObjHeader.CType;
+import org.umu.cops.stack.COPSReportMsg;
+import org.umu.cops.stack.COPSReportType;
 import org.umu.cops.stack.COPSReportType.ReportType;
 
-import java.io.IOException;
-import java.net.Socket;
-import java.util.*;
-
 /**
  * PEP State manager implementation for use in a CMTS.
  */
 public class CmtsPepReqStateMan extends COPSPepReqStateMan {
 
-    private final static Logger logger = LoggerFactory.getLogger(CmtsPepReqStateMan.class);
+    private static final Logger logger = LoggerFactory.getLogger(CmtsPepReqStateMan.class);
 
-    /**
-     * The configured gates
-     */
-    private final Map<Direction, Set<String>> gateConfig;
+    private final CMTSConfig config;
 
-    /**
-     * The connected CMTSs and whether or not they are up
-     */
-    private final Map<String, Boolean> cmStatus;
+    private final Map<IGateID, GateMetaData> gateStateMap;
 
-    /**
-     * Contains the gates that have been set where the key is the gate name and the value is a Set of subIds
-     * that are using this gate
-     */
-    private final Map<String, Set<String>> gatesSetMap;
+    private static class GateMetaData {
+
+        private final PCMMGateReq gateReq;
+        private long commitTime;
+        private long kiloBytesTransmitted;
+
+        private Random random;
+
+        public GateMetaData(final PCMMGateReq gateReq) {
+            this.gateReq = checkNotNull(gateReq);
+            updateCommitTime();
+            kiloBytesTransmitted = 0;
+            this.random = new Random(gateReq.getGateID().getGateID());
+        }
+
+        public long updateCommitTime() {
+            commitTime = System.currentTimeMillis() / 1000L;
+            return commitTime;
+        }
+
+        public PCMMGateReq getGateReq() {
+            return gateReq;
+        }
+
+        public long getCommitTime() {
+            return commitTime;
+        }
+
+        public int getCommitDuration() {
+            return (int)((System.currentTimeMillis() / 1000L) - commitTime);
+        }
+
+        public long updateKiloBytesTransmitted() {
+            kiloBytesTransmitted += random.nextInt(2000);
+            return kiloBytesTransmitted;
+        }
+
+        public long getKiloBytesTransmitted() {
+            return kiloBytesTransmitted;
+        }
+    }
+
+    private static class GateKey {
+        private IAMID amID;
+        private ISubscriberID subscriberID;
+        private IGateID gateID;
+
+        public GateKey(final IAMID amID, final ISubscriberID subscriberID, final IGateID gateID) {
+            this.amID = checkNotNull(amID);
+            this.subscriberID = checkNotNull(subscriberID);
+            this.gateID = checkNotNull(gateID);
+        }
+
+        public IAMID getAmID() {
+            return amID;
+        }
+
+        public ISubscriberID getSubscriberID() {
+            return subscriberID;
+        }
+
+        public IGateID getGateID() {
+            return gateID;
+        }
+
+        public boolean matches(final AMID otherAMID, final ISubscriberID otherSubscriberID) {
+            checkNotNull(otherAMID);
+            checkNotNull(otherSubscriberID);
+
+            return Objects.equal(amID, otherAMID) && Objects.equal(subscriberID, otherSubscriberID);
+
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            final GateKey otherGateKey = (GateKey) o;
+            return Objects.equal(amID, otherGateKey.amID) &&
+                    Objects.equal(subscriberID, otherGateKey.subscriberID) &&
+                    Objects.equal(gateID, otherGateKey.gateID);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(amID, subscriberID, gateID);
+        }
+    }
 
     /**
      * Create a State Request Manager
      *
-     * @param clientType - the client type for this connection
-     * @param clientHandle - the client-handle for this connection
-     * @param process - the data processor
-     * @param socket - the socket connection
-     * @param gateConfig - the configured service class names (gates)
+     * @param clientType
+     *         - the client type for this connection
+     * @param clientHandle
+     *         - the client-handle for this connection
+     * @param process
+     *         - the data processor
+     * @param socket
+     *         - the socket connection
      */
     public CmtsPepReqStateMan(final short clientType, final COPSHandle clientHandle, final CmtsDataProcessor process,
-                              final Socket socket, final Map<Direction, Set<String>> gateConfig,
-                              final Map<String, Boolean> cmStatus) {
+            final Socket socket, final CMTSConfig config) {
         super(clientType, clientHandle, process, socket, new COPSPepMsgSender(clientType, clientHandle, socket));
-        this.gateConfig = Collections.unmodifiableMap(gateConfig);
-        this.cmStatus = Collections.unmodifiableMap(cmStatus);
-
-        this.gatesSetMap = new HashMap<>();
-        for (final Set<String> gateIdSet: gateConfig.values()) {
-            for (final String gateId : gateIdSet) {
-                gatesSetMap.put(gateId, new HashSet<String>());
-            }
-        }
+        this.config = checkNotNull(config);
+        gateStateMap = new HashMap<>();
     }
 
     @Override
@@ -84,19 +194,23 @@ public class CmtsPepReqStateMan extends COPSPepReqStateMan {
         final Map<String, String> removeDecs = new HashMap<>();
         final Map<String, String> installDecs = new HashMap<>();
 
-        for (final Set<COPSDecision> copsDecisions: decisions.values()) {
+        for (final Set<COPSDecision> copsDecisions : decisions.values()) {
             final COPSDecision cmddecision = copsDecisions.iterator().next();
+            logger.debug("decision command: " + cmddecision.getCommand());
             switch (cmddecision.getCommand()) {
                 case INSTALL:
                     for (final COPSDecision decision : copsDecisions) {
                         if (decision.getFlag().equals(DecisionFlag.REQERROR)) {
-                            logger.info("processing decision");
+                            logger.info("processing decision: " + dMsg.getDecSI());
                             // This is assuming a gate set right or wrong
                             if (dMsg.getDecisions().size() == 1 && dMsg.getDecSI() != null) {
                                 final PCMMGateReq gateReq = PCMMGateReq.parse(dMsg.getDecSI().getData().getData());
-                                if (gateReq.getGateSpec() != null) {
+                                if (gateReq != null) {
                                     processGateReq(gateReq, _socket);
                                 }
+                                else {
+                                    logger.error("gateReq failed to parse");
+                                }
                             }
                         }
                     }
@@ -137,72 +251,321 @@ public class CmtsPepReqStateMan extends COPSPepReqStateMan {
         // TODO - Check and/or Set state here
         // Gate ADD gateReq.getTrafficProfile() != null
         // Gate REMOVE gateReq.getTrafficProfile() == null
-        final String subId = gateReq.getSubscriberID().getSourceIPAddress().getHostAddress();
 
-        // Get direction here
+        switch (gateReq.getTransactionID().getGateCommandType()) {
+            case GATE_SET:
+                processGateSet(gateReq, socket);
+                break;
+            case GATE_INFO:
+                processGateInfo(gateReq, socket);
+                break;
+            default:
+                logger.error("Emulator does not support gate command: {}",
+                        gateReq.getTransactionID().getGateCommandType());
+        }
+
+    }
+
+
+    private IPCMMError checkForMissingObjects(final PCMMGateReq gateReq) {
+        // In cases where multiple valid alternatives exist for the S-Type of a missing object,
+        // this portion of the Error-Subcode MUST be set to zero.
+
+        if (gateReq.getTransactionID() == null) {
+            final short subCode =
+                    COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.TRANSACTION_ID.getValue(), TransactionID.STYPE);
+            return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+        }
+
+        final ITransactionID.GateCommandType gateCommand = gateReq.getTransactionID().getGateCommandType();
+
+        if (gateCommand == ITransactionID.GateCommandType.GATE_SET) {
+            // Gate set does not allow gateID
+            if (gateReq.getGateID() != null) {
+                final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.GATE_ID.getValue(), GateID.STYPE);
+                return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+            }
+
+            if (gateReq.getTrafficProfile() == null) {
+                final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.TRAFFIC_PROFILE.getValue(), (byte) 0);
+                return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+            }
+
+            if (gateReq.getClassifiers() == null || gateReq.getClassifiers().isEmpty()) {
+                final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.CLASSIFIERS.getValue(), (byte) 0);
+                return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+            }
+
+            if (gateReq.getGateSpec() == null) {
+                final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.GATE_SPEC.getValue(), GateSpec.STYPE);
+                return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+            }
+
+            final IGateSpec gateSpec = gateReq.getGateSpec();
+            if (gateSpec.getDirection() == null) {
+                return new PCMMError(ErrorCode.INVALID_FIELD);
+            }
+
+        }
+        else {
+
+            if (gateReq.getGateID() == null) {
+                final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.GATE_ID.getValue(), GateID.STYPE);
+                return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+            }
+        }
+
+        if (gateReq.getAMID() == null) {
+            final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.AMID.getValue(), AMID.STYPE);
+            return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+        }
+
+        if (gateReq.getSubscriberID() == null || gateReq.getSubscriberID().getSourceIPAddress() == null
+                || gateReq.getSubscriberID().getSourceIPAddress().getHostAddress() == null) {
+            final short subCode = COPSMsgParser.bytesToShort(PCMMBaseObject.SNum.SUBSCRIBER_ID.getValue(), (byte) 0);
+            return new PCMMError(ErrorCode.MISSING_REQ_OBJ, subCode);
+        }
+
+
+        return null;
+    }
+
+    private IPCMMError checkForInvalidObjects(final PCMMGateReq gateReq) {
+        final ITransactionID.GateCommandType gateCommand = gateReq.getTransactionID().getGateCommandType();
+
+        // GateID
+        if (gateCommand == ITransactionID.GateCommandType.GATE_INFO) {
+            if (!gateStateMap.containsKey(gateReq.getGateID())) {
+                return new PCMMError(ErrorCode.UNK_GATE_ID);
+            }
+        }
+        else {
+            // Traffic profile
+
+            if (gateReq.getTrafficProfile() instanceof DOCSISServiceClassNameTrafficProfile) {
+                final DOCSISServiceClassNameTrafficProfile scnTrafficProfile =
+                        (DOCSISServiceClassNameTrafficProfile) gateReq.getTrafficProfile();
+
+                Set<String> directionSCNs;
+                if (gateReq.getGateSpec().getDirection().equals(Direction.DOWNSTREAM)) {
+                    directionSCNs = config.getDownstreamServiceClassNames();
+                } else {
+                    directionSCNs = config.getUpstreamServiceClassNames();
+                }
+                if (!directionSCNs.contains(scnTrafficProfile.getScnName())) {
+                    return new PCMMError(ErrorCode.UNDEF_SCN_NAME);
+                }
+            } else {
+                // TODO remote this after other profiles are supported
+                logger.error("Currently only DOCSIS Service Class Name Traffic Profiles are supported: attempted {}",
+                        gateReq.getTrafficProfile().getClass().getName());
+                return new PCMMError(ErrorCode.OTHER_UNSPECIFIED);
+            }
+
+            // number of classifiers
+            if (config.getNumberOfSupportedClassifiers() < gateReq.getClassifiers().size()) {
+                return new PCMMError(ErrorCode.NUM_CLASSIFIERS, config.getNumberOfSupportedClassifiers());
+            }
+        }
+
+
+
+        // SubscriberID
+        String subId = gateReq.getSubscriberID().getSourceIPAddress().getHostAddress();
+        if(!config.getModemStatus().containsKey(subId) || !config.getModemStatus().get(subId)) {
+            return new PCMMError(ErrorCode.INVALID_SUB_ID);
+        }
+
+        // Iff the gate exists
+        if (gateReq.getGateID() != null
+                && gateStateMap.containsKey(gateReq.getGateID())) {
+            GateMetaData existingGate = gateStateMap.get(gateReq.getGateID());
+
+            // Unauthorized AMID - only the AM that created a gate may change it
+            if (!existingGate.getGateReq().getAMID().equals(gateReq.getAMID())) {
+                return new PCMMError(ErrorCode.UNAUTH_AMID);
+            }
+        }
+
+
+
+
+        return null;
+    }
+
+    private IPCMMError getGateError(final PCMMGateReq gateReq) {
+
+        IPCMMError error = null;
+        error = checkForMissingObjects(gateReq);
+        if (error != null) {
+            return error;
+        }
+
+        error = checkForInvalidObjects(gateReq);
+        if (error != null) {
+            return error;
+        }
+
+
+        return null;
+    }
+
+    private void processGateSet(final PCMMGateReq gateReq, final Socket socket) throws COPSException {
+
+        final String subId = gateReq.getSubscriberID().getSourceIPAddress().getHostAddress();
         final Direction gateDir = gateReq.getGateSpec().getDirection();
-        final Set<String> gateNames = gateConfig.get(gateDir);
-        // TODO - Determine if this is the best means to derive the gate name???
-        final String gateName = new String(gateReq.getTrafficProfile().getAsBinaryArray());
-
-        final IPCMMError error;
-        if (subId == null || gateDir == null || gateNames == null) {
-            // Missing required object
-            // TODO - Determine if this is the correct code. 3 was being used previously and I don't see any corresponding code.
-            error = new PCMMError(ErrorCode.UNK_GATE_ID);
-        } else if (!cmStatus.keySet().contains(subId)
-                || (cmStatus.keySet().contains(subId) && !cmStatus.get(subId))) {
-            // Invalid Object
-            // TODO - Determine if this code is correct
-            error = new PCMMError(ErrorCode.INVALID_SUB_ID);
-        } else if (!gateNames.contains(gateName.trim())) {
-            // TODO - Determine if this code is correct
-            error = new PCMMError(ErrorCode.UNDEF_SCN_NAME);
+
+        final String serviceClassName;
+        if ((gateReq.getTrafficProfile() instanceof DOCSISServiceClassNameTrafficProfile)) {
+            serviceClassName = ((DOCSISServiceClassNameTrafficProfile) gateReq.getTrafficProfile()).getScnName();
         } else {
-            error = null;
-            gatesSetMap.get(gateName.trim()).add(subId);
+            serviceClassName = null;
         }
-        gateReq.setError(error);
 
-        logger.info("Processing gate request [" + gateName + "] with direction [" + gateDir + ']');
+        final IPCMMError error = getGateError(gateReq);
+        gateReq.setError(error);
 
-        // Get gate name
+        logger.info("Processing gate set request [" + serviceClassName + "] with direction [" + gateDir + ']');
 
         // Set response
+
+        final ITransactionID.GateCommandType gateCommand = (error == null)
+                ? ITransactionID.GateCommandType.GATE_SET_ACK
+                : ITransactionID.GateCommandType.GATE_SET_ERR;
+
+        final TransactionID transactionID =
+                new TransactionID(gateReq.getTransactionID().getTransactionIdentifier(), gateCommand);
+
         final List<Byte> data = new ArrayList<>();
-        for (final byte val : gateReq.getTransactionID().getAsBinaryArray())
-            data.add(val);
-        for (final byte val : gateReq.getAMID().getAsBinaryArray())
-            data.add(val);
-        for (final byte val : gateReq.getSubscriberID().getAsBinaryArray())
-            data.add(val);
-        if (error != null) for (final byte val : gateReq.getError().getAsBinaryArray())
-            data.add(val);
+        addBytesToList(transactionID.getAsBinaryArray(), data);
+        addBytesToList(gateReq.getAMID().getAsBinaryArray(), data);
+        addBytesToList(gateReq.getSubscriberID().getAsBinaryArray(), data);
 
-        // Assign a gate ID
-        final GateID gateID = new GateID(UUID.randomUUID().hashCode());
-        for (final byte val : gateID.getAsBinaryArray())
-            data.add(val);
 
+        if (error == null) {
+            // Assign a gate ID
+            final GateID gateID = new GateID(UUID.randomUUID().hashCode());
+            for (final byte val : gateID.getAsBinaryArray()) {
+                data.add(val);
+            }
+            gateReq.setGateID(gateID);
+
+            int timeStamp = (int)(System.currentTimeMillis() / 1000L);
+            gateReq.setGateTimeInfo(new GateTimeInfo(timeStamp));
 
-        final byte[] csiArr = new byte[data.size()];
-        for (int i = 0; i < data.size(); i++) {
-            csiArr[i] = data.get(i);
+            gateStateMap.put(gateID, new GateMetaData(gateReq));
+        }
+        else {
+            addBytesToList(error.getAsBinaryArray(), data);
         }
+
+        final byte[] csiArr = Bytes.toArray(data);
         final COPSClientSI si = new COPSClientSI(CNum.CSI, CType.DEF, new COPSData(csiArr, 0, csiArr.length));
 
         final ReportType reportType;
-        if (gateReq.getError() == null) reportType = ReportType.SUCCESS; else reportType = ReportType.FAILURE;
+        if (gateReq.getError() == null) {
+            reportType = ReportType.SUCCESS;
+        } else {
+            reportType = ReportType.FAILURE;
+        }
 
-        logger.info("Returning " + reportType + " for gate request [" + gateName + "] direction [" + gateDir
+        logger.info("Returning " + reportType + " for gate request [" + serviceClassName + "] direction [" + gateDir
                 + "] for host - " + subId);
-        final COPSReportMsg reportMsg = new COPSReportMsg(_clientType, getClientHandle(),
-                    new COPSReportType(reportType), si, null);
+        sendReport(reportType, si, socket);
+
+    }
+
+    private void processGateInfo(final PCMMGateReq gateReq, final Socket socket) throws COPSException {
+        logger.info("GateInfo");
+
+        IPCMMError error = getGateError(gateReq);
+
+        final TransactionID transactionID;
+        final ReportType reportType;
+        if (error != null) {
+             transactionID = new TransactionID(gateReq.getTransactionID().getTransactionIdentifier(),
+                            ITransactionID.GateCommandType.GATE_INFO_ERR);
+            reportType = ReportType.FAILURE;
+        }
+        else {
+            transactionID = new TransactionID(gateReq.getTransactionID().getTransactionIdentifier(),
+                    ITransactionID.GateCommandType.GATE_INFO_ACK);
+            reportType = ReportType.SUCCESS;
+        }
+
+        final List<Byte> data = new ArrayList<>();
+        addBytesToList(transactionID.getAsBinaryArray(), data);
+        addBytesToList(gateReq.getAMID().getAsBinaryArray(), data);
+        addBytesToList(gateReq.getSubscriberID().getAsBinaryArray(), data);
+        addBytesToList(gateReq.getGateID().getAsBinaryArray(), data);
+
+        if (error != null) {
+            addBytesToList(error.getAsBinaryArray(), data);
+        }
+        else {
+            GateMetaData exisitingGate = gateStateMap.get(gateReq.getGateID());
+
+            addBytesToList(exisitingGate.getGateReq().getGateSpec().getAsBinaryArray(), data);
+
+            for (IClassifier classifier : exisitingGate.getGateReq().getClassifiers()) {
+                addBytesToList(classifier.getAsBinaryArray(), data);
+            }
+
+            addBytesToList(exisitingGate.getGateReq().getTrafficProfile().getAsBinaryArray(), data);
+
+            GateTimeInfo timeInfo = new GateTimeInfo(exisitingGate.getCommitDuration());
+            addBytesToList(timeInfo.getAsBinaryArray(), data);
+
+            GateUsageInfo gateUsageInfo = new GateUsageInfo(exisitingGate.updateKiloBytesTransmitted());
+            addBytesToList(gateUsageInfo.getAsBinaryArray(), data);
+
+            GateState gateState = new GateState(IGateState.GateStateType.COMMITTED,
+                    IGateState.GateStateReasonType.OTHER);
+            addBytesToList(gateState.getAsBinaryArray(), data);
+
+            logger.info("Returning " + reportType + " for gate info request on gate " + exisitingGate.getGateReq().getGateID() );
+        }
+
+        final byte[] csiArr = Bytes.toArray(data);
+        COPSClientSI copsClientSI = new COPSClientSI(CNum.CSI, CType.DEF, new COPSData(csiArr, 0, csiArr.length));
+
+        sendReport(reportType, copsClientSI, socket);
+    }
+
+    private void sendReport(ReportType reportType, COPSClientSI copsClientSI, final Socket socket)
+            throws COPSPepException {
+        logger.info("Returning {} for gate request", reportType);
+
+        final COPSReportMsg reportMsg =
+                new COPSReportMsg(_clientType, getClientHandle(), new COPSReportType(reportType), copsClientSI, null);
         try {
             reportMsg.writeData(socket);
         } catch (IOException e) {
             throw new COPSPepException("Error writing gate set SUCCESS Report", e);
         }
+
+    }
+
+    private static void addBytesToList(byte[] array, List<Byte> list) {
+        checkNotNull(array);
+        checkNotNull(list);
+
+        if (array.length == 0) return;
+
+        // if list supports resizing do so
+        if (list instanceof ArrayList) {
+            ArrayList<Byte> arrayList = (ArrayList<Byte>) list;
+            arrayList.ensureCapacity(list.size() + array.length);
+        }
+        else if (list instanceof Vector){
+            Vector<Byte> vector = (Vector<Byte>) list;
+            vector.ensureCapacity(vector.size() + array.length);
+        }
+
+        // Add all
+        for (byte b : array) {
+            list.add(b);
+        }
     }
 
 }
diff --git a/packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CmtsYmal.java b/packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CmtsYmal.java
new file mode 100644 (file)
index 0000000..13b5413
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015 CableLabs and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.pcmm.rcd.impl;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.pcmm.gates.IGateSpec;
+
+/**
+ * @author rvail
+ */
+public class CmtsYmal {
+    @JsonProperty("port")
+    private int port;
+
+    @JsonProperty("numberOfSupportedClassifiers")
+    private short numberOfSupportedClassifiers;
+
+    @JsonProperty("serviceClassNames")
+    private Collection<ServiceClassNamesYaml> serviceClassNames;
+
+    @JsonProperty("cmStatuses")
+    private Collection<CmStatusYaml> cmStatuses;
+
+    public int getPort() {
+        return port;
+    }
+
+    public short getNumberOfSupportedClassifiers() {
+        return numberOfSupportedClassifiers;
+    }
+
+    public Map<IGateSpec.Direction, Set<String>> getServiceClassNames() {
+        final Map<IGateSpec.Direction, Set<String>> out = new HashMap<>();
+
+        for (final ServiceClassNamesYaml scns : serviceClassNames) {
+            Set<String> names;
+            if (out.containsKey(scns.direction)) {
+                names = out.get(scns.direction);
+            } else {
+                names = new HashSet<>(scns.gateNames.size());
+                out.put(scns.direction, names);
+            }
+            names.addAll(scns.gateNames);
+        }
+        return out;
+    }
+
+    public Map<String, Boolean> getCmStatus() {
+        final Map<String, Boolean> out = new HashMap<>();
+
+        for (final CmStatusYaml cmStatus : cmStatuses) {
+            out.put(cmStatus.hostIp, cmStatus.status);
+        }
+
+        return out;
+    }
+
+
+    /**
+     * Class to hold the YAML gate configuration values
+     */
+    public static class ServiceClassNamesYaml {
+        @JsonProperty("direction")
+        private IGateSpec.Direction direction;
+
+        @JsonProperty("names")
+        private Set<String> gateNames;
+
+        public IGateSpec.Direction getDirection() {
+            return direction;
+        }
+
+        public Set<String> getGateNames() {
+            return Collections.unmodifiableSet(gateNames);
+        }
+    }
+
+
+    /**
+     * Class to hold the YAML Cable Modem configuration values
+     */
+    public static class CmStatusYaml {
+        @JsonProperty("host")
+        private String hostIp;
+
+        @JsonProperty("status")
+        private boolean status;
+    }
+}
index ee11316847903dedcdc68e6443c4a79fd2cc2f4d..f9a49a31c51acf966dfc5874d972b121641ac945 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.pcmm.rcd.impl;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import org.pcmm.gates.IGateSpec.Direction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -28,37 +30,26 @@ import java.util.Set;
  */
 class PcmmCmtsConnection extends COPSPepConnection {
 
-    private final static Logger logger = LoggerFactory.getLogger(COPSPepConnection.class);
-
-    /**
-     * The configured gates
-     */
-    private final Map<Direction, Set<String>> gateConfig;
+    private static final Logger logger = LoggerFactory.getLogger(COPSPepConnection.class);
 
-    /**
-     * The connected CMTSs and whether or not they are up
-     */
-    private final Map<String, Boolean> cmStatus;
+    private final CMTSConfig config;
 
     /**
      * Constructor
      * @param clientType - the client-type
      * @param sock - the socket connection
-     * @param gateConfig - the configured gates
-     * @param cmStatus - the configured CMs and whether or each is connected
+     * @param config - emulator configuration
      */
-    public PcmmCmtsConnection(final short clientType, final Socket sock, final Map<Direction, Set<String>> gateConfig,
-                              final Map<String, Boolean> cmStatus) {
+    public PcmmCmtsConnection(final short clientType, final Socket sock, final CMTSConfig config) {
         super(clientType, sock);
-        this.gateConfig = Collections.unmodifiableMap(gateConfig);
-        this.cmStatus = Collections.unmodifiableMap(cmStatus);
+        this.config = checkNotNull(config);
     }
 
     @Override
     public COPSPepReqStateMan addRequestState(final COPSHandle clientHandle, final COPSPepDataProcess process)
             throws COPSException {
         final COPSPepReqStateMan manager = new CmtsPepReqStateMan(_clientType, clientHandle, (CmtsDataProcessor)process,
-                _sock, gateConfig, cmStatus);
+                _sock, config);
         if (_managerMap.get(clientHandle) != null)
             throw new COPSPepException("Duplicate Handle, rejecting " + clientHandle);
 
index df2f0e5071fb42e6589c3abc17b49c358ac86a9e..ba8553241914d42070bdc25300474384b316c382 100644 (file)
@@ -209,23 +209,35 @@ module packetcable
     }
 
     grouping gate-operational-attributes {
-        leaf gatePath {
-            config false;
-            type string;
-            description "FQ Gate path app/subscriber/gate";
-            mandatory true;
-        }
-        leaf ccapId {
-            config false;
-            type string;
-            description "CCAP Identity";
-            mandatory true;
-        }
-        leaf cops-state {
-            config false;
-            type string;
-            description "Gate operational COPS state";
-            mandatory true;
+               leaf gatePath {
+                       config false;
+                   type string;
+                   description "FQ Gate path app/subscriber/gate";
+                   mandatory true;
+               }
+               leaf ccapId {
+                       config false;
+                   type string;
+                   description "CCAP Identity";
+                   mandatory true;
+               }
+               leaf cops-gate-state {
+                       config false;
+                       type string;
+                       description "Operational COPS Gate state";
+                       mandatory true;
+               }
+               leaf cops-gate-time-info {
+                       config false;
+                       type string;
+                       description "Operational COPS Gate time info";
+                       mandatory true;
+               }
+               leaf cops-gate-usage-info {
+          config false;
+          type string;
+          description "Operational COPS gate usage info";
+          mandatory true;
         }
         leaf cops-gateId {
             config false;
@@ -450,5 +462,95 @@ module packetcable
            }
     }
 
-}
+           //RPCs
+    rpc ccap-set-connection {
+               input {
+            leaf ccapId {
+                       type instance-identifier;
+                       ext:context-reference ccap-context;
+               }
+               container connection {
+                       leaf connected {
+                               type boolean;
+                               description "COPS session state";
+                       }
+//                     leaf idle-detect {
+//                                     type uint8;             
+//                                     description "COPS connection idle timer";
+//                             }
+               }
+        }
+        output {
+               container ccap {
+                       leaf ccapId {
+                               type string;
+                       }
+                       container connection {
+                                       uses ccap-connection;
+                               }
+               }
+               leaf response {
+                       type string;
+               }
+                       leaf timestamp {
+                               type yang:date-and-time;
+                               description "RPC timestamp";
+               }
+        }
+    }
+    
+    rpc ccap-poll-connection {
+               input {
+            leaf ccapId {
+                       type instance-identifier;
+                       ext:context-reference ccap-context;
+               }
+        }
+        output {
+               container ccap {
+                       leaf ccapId {
+                               type string;
+                       }
+                       container connection {
+                                       uses ccap-connection;
+                               }
+               }
+               leaf response {
+                       type string;
+               }
+                       leaf timestamp {
+                               type yang:date-and-time;
+                               description "RPC timestamp";
+               }
+        }
+    }
 
+       rpc qos-poll-gates {
+               input {
+            leaf appId {
+               type instance-identifier;
+                       ext:context-reference app-context;
+               }
+               leaf subscriberId {
+               type string;
+               description "Subscriber Identity -- must be a CM or CPE IP address";
+               }
+               leaf gateId {
+               type string;
+               description "Qos Gate Identity";
+               }
+        }
+        output {
+                       container gate {
+                               uses gate-operational-attributes;
+                       }
+                       leaf response {
+                       type string;
+               }
+                       leaf timestamp {
+                       type yang:date-and-time;
+                       description "RPC timestamp";
+               }
+        }
+    }
+}
\ No newline at end of file
index f944c1d9707d3f3289be7fa80b662e7c86c8d0fb..98e1d276d95b029282c835d46376cfa7a119f1a9 100644 (file)
@@ -39,6 +39,9 @@ import org.pcmm.gates.ITrafficProfile;
 import org.pcmm.gates.impl.AMID;
 import org.pcmm.gates.impl.DOCSISServiceClassNameTrafficProfile;
 import org.pcmm.gates.impl.GateID;
+import org.pcmm.gates.impl.GateState;
+import org.pcmm.gates.impl.GateTimeInfo;
+import org.pcmm.gates.impl.GateUsageInfo;
 import org.pcmm.gates.impl.PCMMError;
 import org.pcmm.gates.impl.PCMMGateReq;
 import org.pcmm.gates.impl.SubscriberID;
@@ -61,9 +64,13 @@ public class PCMMGateReqBuilder {
     private ITrafficProfile trafficProfile = null;
     private final List<IClassifier> classifiers = Lists.newArrayListWithExpectedSize(4);
     private PCMMError error = null;
+    private GateState gateState = null;
+    private GateTimeInfo gateTimeInfo = null;
+    private GateUsageInfo gateUsageInfo = null;
 
     public PCMMGateReq build() {
-        return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile, classifiers, gateID, error);
+        return new PCMMGateReq(amid, subscriberID, transactionID, gateSpec, trafficProfile, classifiers,
+                       gateID, error, gateState, gateTimeInfo, gateUsageInfo);
     }
 
     public void setAmId(final AmId qosAmId) {
@@ -140,7 +147,7 @@ public class PCMMGateReqBuilder {
             final Short index = container.getClassifierId();
 
             if (choice instanceof QosClassifierChoice) {
-                addClassifier(((QosClassifierChoice) choice).getClassifier());
+                addClassifier(index, ((QosClassifierChoice) choice).getClassifier());
             }
             else if (choice instanceof ExtClassifierChoice) {
                 addExtClassifier(index, ((ExtClassifierChoice) choice).getExtClassifier());
@@ -154,7 +161,7 @@ public class PCMMGateReqBuilder {
         }
     }
 
-    private void addClassifier(final Classifier qosClassifier) {
+    private void addClassifier(final Short index,final Classifier qosClassifier) {
         // TODO - try and make these variables immutable
         Protocol protocol = null;
         byte tosOverwrite = 0;
@@ -164,7 +171,9 @@ public class PCMMGateReqBuilder {
         short srcPort = (short) 0;
         short dstPort = (short) 0;
         byte priority = (byte) 64;
-
+        //byte priority = index.byteValue();
+        
+        
         // Legacy classifier
         if (qosClassifier.getProtocol() != null) {
             protocol = Protocol.valueOf(qosClassifier.getProtocol().getValue().shortValue());
index 16d633b4911b8eca605d38e23d7aa0f07dd5cb5a..0368e5452c5115d2b79cd01ad83508eb5596fc28 100644 (file)
@@ -20,7 +20,10 @@ import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.app
 import org.pcmm.PCMMPdpAgent;
 import org.pcmm.PCMMPdpDataProcess;
 import org.pcmm.PCMMPdpMsgSender;
+import org.pcmm.gates.IGateState;
+import org.pcmm.gates.ITransactionID;
 import org.pcmm.gates.impl.PCMMGateReq;
+import org.pcmm.gates.impl.TransactionID;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.umu.cops.prpdp.COPSPdpException;
@@ -47,6 +50,7 @@ public class PCMMService {
         this.ccap = ccap;
         ipAddr = ccap.getConnection().getIpAddress();
         portNum = ccap.getConnection().getPort();
+
         ccapClient = new CcapClient(ipAddr, portNum);
         logger.info("Attempting to add CCAP with ID {} @ {}:{}", ccap.getCcapId(), ipAddr.getIpv4Address().getValue(),
                 portNum.getValue());
@@ -70,10 +74,14 @@ public class PCMMService {
         }
     }
 
-    public class GateSetStatus {
+    public class GateSendStatus {
         private boolean didSucceed = false;
         private String message = "";
         private String copsGateId = "";
+        private String copsGateState = "";
+        private String copsGateStateReason = "";
+        private String copsGateTimeInfo = "";
+        private String copsGateUsageInfo = "";
 
         public boolean didSucceed() {
             return didSucceed;
@@ -99,12 +107,39 @@ public class PCMMService {
             this.copsGateId = copsGateId;
         }
 
+        public String getCopsGateState() {
+            return copsGateState;
+        }
+        void setCopsGateState(final String copsGateState) {
+            this.copsGateState = copsGateState;
+        }
+
+        public String getCopsGateStateReason() {
+            return copsGateStateReason;
+        }
+        void setCopsGateStateReason(final String copsGateStateReason) {
+            this.copsGateStateReason = copsGateStateReason;
+        }
+
+        public String getCopsGateTimeInfo() {
+            return copsGateTimeInfo;
+        }
+        void setCopsGateTimeInfo(final String copsGateTimeInfo) {
+            this.copsGateTimeInfo = copsGateTimeInfo;
+        }
+
+        public String getCopsGateUsageInfo() {
+            return copsGateUsageInfo;
+        }
+        void setCopsGateUsageInfo(final String copsGateUsageInfo) {
+            this.copsGateUsageInfo = copsGateUsageInfo;
+        }
     }
 
-    public GateSetStatus sendGateSet(final String gatePathStr, final InetAddress subId, final Gate qosGate,
+    public GateSendStatus sendGateSet(final String gatePathStr, final InetAddress subId, final Gate qosGate,
             final ServiceFlowDirection scnDir) {
 
-        GateSetStatus status = new GateSetStatus();
+        GateSendStatus status = new GateSendStatus();
 
         logger.info("Sending gate to CCAP with ID - " + ccap.getCcapId());
 
@@ -220,7 +255,110 @@ public class PCMMService {
         } else {
             logger.warn("Attempt to delete non-existent gate with path - " + gatePathStr);
             return false;
+               }
         }
+
+       public Boolean getPcmmPdpSocket() {
+               try {
+                       return ccapClient.pcmmPdp.getSocket().isClosed();
+               } catch (Exception e) {
+                       logger.error("getPcmmPdpSocket: {} FAILED: {}", ccapClient, e.getMessage());
+                       return true;
+               }
+       }
+
+       public Boolean getPcmmCcapClientIsConnected() {
+               try {
+                       return ccapClient.isConnected;
+               } catch (Exception e) {
+                       logger.error("getPcmmCcapClientIsConnected: {} FAILED: {}", ccapClient, e.getMessage());
+                       return false;
+               }
+       }
+
+       public String getPcmmCcapClientConnectErrMsg() {
+               try {
+                       return ccapClient.errMessage;
+               } catch (Exception e) {
+                       logger.error("getPcmmCcapClientIsConnected: {} FAILED: {}", ccapClient, e.getMessage());
+                       return e.getMessage();
+               }
+       }
+
+        //new gate-info method
+       public GateSendStatus sendGateInfo(final String gatePathStr) {
+
+               logger.info("sendGateInfo() - " + ccap);
+
+               GateSendStatus status = new GateSendStatus();
+
+            // recover the original gate request
+            final PCMMGateReq gateReq = gateRequests.get(gatePathStr);
+
+            // is the ccap socket open?
+            final Boolean socketIsClosed = getPcmmPdpSocket();
+
+            if ((gateReq != null) && (!socketIsClosed)) {
+                gateReq.setTransactionID(new TransactionID(gateReq.getTransactionID().getTransactionIdentifier(),
+                        ITransactionID.GateCommandType.GATE_INFO));
+
+                ccapClient.sendGateInfo(gateReq);
+                // and wait for the response to complete
+                try {
+                    // TODO - see PCMMPdpReqStateMan#processReport() gate.notify(). Should determine a better means to
+                    // TODO - handle this synchronization.
+                    synchronized (gateReq) {
+                        logger.info("Waiting 5000ms for gate request to be updated");
+                        gateReq.wait(5000);
+                        logger.debug("Gate request error - " + gateReq.getError());
+                        logger.debug("Gate request ID - " + gateReq.getGateID());
+                    }
+                } catch (InterruptedException e) {
+                    status.setDidSucceed(false);
+                    status.setMessage(String.format("Gate-Info Request Timeout for %s", ccap.getCcapId()));
+                    return status;
+                }
+                if (gateReq.getError() != null) {
+                    status.setDidSucceed(false);
+                    status.setMessage(
+                            String.format("%s reports '%s'", ccap.getCcapId(), gateReq.getError().toString()));
+                    logger.error("PCMMService: sendGateInfo(): returned error: {}", gateReq.getError().toString());
+                } else {
+                    if (gateReq.getGateID() != null) {
+                        status.setDidSucceed(true);
+                        status.setCopsGateId(String.format("%08x", gateReq.getGateID().getGateID()));
+                        //status.setMessage(String.format("200 OK - sendGateInfo for %s/%s returned GateId %08x",
+                        //        ccap.getCcapId(), gatePathStr, gateReq.getGateID().getGateID()) );
+
+                        final IGateState gateState = gateReq.getGateState();
+                        status.setCopsGateState(gateState.getGateState().toString());
+                        status.setCopsGateStateReason(gateState.getGateStateReason().toString());
+                        status.setCopsGateTimeInfo(String.format("%d", gateReq.getGateTimeInfo().getGateTimeInfo()));
+                        status.setCopsGateUsageInfo(String.format("%d", gateReq.getGateUsageInfo().getGateUsageInfo()));
+                        logger.info(String.format("PCMMService: sendGateInfo(): returned GateId %08x: ",
+                                gateReq.getGateID().getGateID()));
+                    } else {
+                        status.setDidSucceed(false);
+                        status.setMessage(
+                                String.format("404 Not Found - sendGateInfo for %s/%s no gateId returned", ccap.getCcapId(),
+                                        gatePathStr));
+
+                        logger.info("PCMMService: sendGateInfo(): no gateId returned:");
+                    }
+                    return status;
+                }
+            } else {
+               status.setDidSucceed(false);
+                if (socketIsClosed) {
+                       status.setMessage(String.format("%s: CCAP Cops Socket is closed",ccap.getCcapId()));
+                }
+                else {
+                       status.setMessage( String.format("Attempt to get info of non-existent gate with path - " + gatePathStr));
+                }
+               return status;
+            }
+                       return status;
+
     }
 
     /**
@@ -266,6 +404,7 @@ public class PCMMService {
          */
         public void connect() {
             logger.info("Attempting to connect to host: " + ipv4 + " port: " + port);
+            errMessage = null;
             try {
                 pcmmPdp.connect();
 
@@ -316,6 +455,17 @@ public class PCMMService {
             }
             return true;
         }
+
+        public Boolean sendGateInfo(final PCMMGateReq gateReq) {
+            logger.info("CcapClient: sendGateInfo(): {}:{} => {}", ipv4, port);
+            try {
+                pcmmSender.sendGateInfo(gateReq);
+            } catch (COPSPdpException e) {
+                logger.error("CcapClient: sendGateInfo(): {}:{} => {} FAILED: {}", ipv4, port,
+                        e.getMessage());
+            }
+            return true;
+        }
     }
 }
 
index 9c1b690206057bd44cf959ab5f03e2f26e97477b..d27b9e9c1e46452c8c313641ad78179f970e4cf8 100644 (file)
@@ -14,19 +14,28 @@ import com.google.common.base.Optional;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
 import javax.annotation.Nonnull;
 import javax.annotation.concurrent.ThreadSafe;
+
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
@@ -38,11 +47,25 @@ import org.opendaylight.controller.packetcable.provider.validation.Validator;
 import org.opendaylight.controller.packetcable.provider.validation.impl.CcapsValidatorProviderFactory;
 import org.opendaylight.controller.packetcable.provider.validation.impl.QosValidatorProviderFactory;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.DateAndTime;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.AppContext;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapContext;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapPollConnectionInput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapPollConnectionOutput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapPollConnectionOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapSetConnectionInput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapSetConnectionOutput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.CcapSetConnectionOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.Ccaps;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.PacketcableService;
 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.Qos;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.QosPollGatesInput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.QosPollGatesOutput;
+import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.QosPollGatesOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ServiceClassName;
 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ServiceFlowDirection;
 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.attributes.ConnectionBuilder;
@@ -65,6 +88,8 @@ import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.app
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.pcmm.rcd.IPCMMClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -74,9 +99,10 @@ import org.slf4j.LoggerFactory;
  * <p>
  * This class is responsible for processing messages received from ODL's restconf interface.
  * TODO - Remove some of these state maps and move some of this into the PCMMService
+ * TODO Don't implement PacketcableService, move that into an inner class
  */
 @ThreadSafe
-public class PacketcableProvider implements BindingAwareProvider, AutoCloseable {
+public class PacketcableProvider implements BindingAwareProvider, AutoCloseable, PacketcableService {
 
     private static final Logger logger = LoggerFactory.getLogger(PacketcableProvider.class);
 
@@ -105,6 +131,9 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
     private DataBroker dataBroker;
     private MdsalUtils mdsalUtils;
 
+    //Routed RPC Registration
+    private RoutedRpcRegistration<PacketcableService> rpcRegistration;
+
     // Data change listeners/registrations
     private final CcapsDataChangeListener ccapsDataChangeListener = new CcapsDataChangeListener();
     private final QosDataChangeListener qosDataChangeListener = new QosDataChangeListener();
@@ -129,13 +158,17 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
 
         mdsalUtils = new MdsalUtils(dataBroker);
 
-        ccapsDataChangeListenerRegistration = dataBroker
-                .registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, ccapsIID.child(Ccap.class),
+        ccapsDataChangeListenerRegistration =
+                dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, ccapsIID.child(Ccap.class),
                         ccapsDataChangeListener, DataBroker.DataChangeScope.SUBTREE);
 
-        qosDataChangeListenerRegistration = dataBroker
-                .registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, PacketcableProvider.qosIID.child(Apps.class).child(App.class),
-                        qosDataChangeListener, DataBroker.DataChangeScope.SUBTREE);
+        qosDataChangeListenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                PacketcableProvider.qosIID.child(Apps.class).child(App.class), qosDataChangeListener,
+                DataBroker.DataChangeScope.SUBTREE);
+
+        rpcRegistration = session.addRoutedRpcImplementation(PacketcableService.class, this);
+        logger.info("onSessionInitiated().rpcRgistration: {}", rpcRegistration);
+
     }
 
     /**
@@ -294,44 +327,35 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
 
 
                 // type match between iid and badData is done at start of loop
-                @SuppressWarnings("unchecked")
-                final InstanceIdentifier<Ccap> ccapIID = (InstanceIdentifier<Ccap>) iid;
+                @SuppressWarnings("unchecked") final InstanceIdentifier<Ccap> ccapIID = (InstanceIdentifier<Ccap>) iid;
                 writeTransaction.put(LogicalDatastoreType.OPERATIONAL, ccapIID, opperationalCcap);
-            }
-            else if (badData instanceof Gate) {
+            } else if (badData instanceof Gate) {
                 final Gate gate = (Gate) badData;
 
                 final Gate operationalGate =
-                        new GateBuilder()
-                        .setGateId(gate.getGateId())
-                        .setError(exception.getErrorMessages())
-                        .build();
+                        new GateBuilder().setGateId(gate.getGateId()).setError(exception.getErrorMessages()).build();
 
-                final Gates operationalGates = new GatesBuilder()
-                        .setGate(Collections.singletonList(operationalGate))
-                        .build();
+                final Gates operationalGates =
+                        new GatesBuilder().setGate(Collections.singletonList(operationalGate)).build();
 
                 final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(iid.firstIdentifierOf(Subscriber.class));
-                final Subscriber operationalSubscriber = new SubscriberBuilder()
-                        .setSubscriberId(subscriberKey.getSubscriberId())
-                        .setGates(operationalGates)
-                        .build();
+                final Subscriber operationalSubscriber =
+                        new SubscriberBuilder().setSubscriberId(subscriberKey.getSubscriberId())
+                                .setGates(operationalGates)
+                                .build();
 
-                final Subscribers operationalSubscribers = new SubscribersBuilder()
-                        .setSubscriber(Collections.singletonList(operationalSubscriber))
-                        .build();
+                final Subscribers operationalSubscribers =
+                        new SubscribersBuilder().setSubscriber(Collections.singletonList(operationalSubscriber))
+                                .build();
 
                 final InstanceIdentifier<App> appIID = iid.firstIdentifierOf(App.class);
                 final AppKey appKey = InstanceIdentifier.keyOf(appIID);
-                final App operationalApp = new AppBuilder()
-                        .setAppId(appKey.getAppId())
-                        .setSubscribers(operationalSubscribers)
-                        .build();
+                final App operationalApp =
+                        new AppBuilder().setAppId(appKey.getAppId()).setSubscribers(operationalSubscribers).build();
 
 
                 writeTransaction.put(LogicalDatastoreType.OPERATIONAL, appIID, operationalApp);
-            }
-            else {
+            } else {
                 // If you get here a developer forgot to add a type above
                 logger.error("Unexpected type requested for error saving: {}", badData);
                 throw new IllegalStateException("Unsupported type for error saving");
@@ -364,6 +388,7 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
         }
     }
 
+
     /**
      * Removes Subscriber if all Gate instances are removed
      */
@@ -401,6 +426,9 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
 
         @Override
         void postRemove(final InstanceIdentifier<App> appIID) {
+            //unregister app rpc path
+            logger.info("Un-Registering App Routed RPC Path...");
+            rpcRegistration.unregisterPath(AppContext.class, appIID);
             executor.execute(new AppsCleaner(appIID));
         }
     }
@@ -409,7 +437,7 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
     /**
      * Removes Apps if all App instances are removed.
      */
-    private class AppsCleaner extends  AbstractCleaner<Apps> {
+    private class AppsCleaner extends AbstractCleaner<Apps> {
 
         public AppsCleaner(InstanceIdentifier<App> removedAppIID) {
             super(removedAppIID, Apps.class, LogicalDatastoreType.OPERATIONAL);
@@ -424,12 +452,14 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
 
     /**
      * Helper class to do the heavy lifting in removing object. Lets subclasses decide with
-     *  {@link #shouldClean(DataObject)}. <br>
-     *
+     * {@link #shouldClean(DataObject)}. <br>
+     * <p>
      * Subclasses can react after an instance is removed by overriding {@link #postRemove(InstanceIdentifier)}
-     * @param <T> The type that will be removed
+     *
+     * @param <T>
+     *         The type that will be removed
      */
-    private abstract class AbstractCleaner <T extends DataObject> implements Runnable {
+    private abstract class AbstractCleaner<T extends DataObject> implements Runnable {
         final InstanceIdentifier<?> removedIID;
         final Class<T> tClass;
         final LogicalDatastoreType datastoreType;
@@ -450,30 +480,32 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
                     if (shouldClean(optional.get())) {
                         if (mdsalUtils.delete(datastoreType, tIID)) {
                             postRemove(tIID);
-                        }
-                        else {
+                        } else {
                             removeFailed(tIID);
                         }
                     }
 
                 }
-            }
-            else {
-                logger.error("Expected to find InstanceIdentifier<{}> but was not found: {}",
-                        tClass.getSimpleName(), removedIID);
+            } else {
+                logger.error("Expected to find InstanceIdentifier<{}> but was not found: {}", tClass.getSimpleName(),
+                        removedIID);
             }
         }
 
         /**
          * If returns true the object will be removed from the datastore
-         * @param object The object that might be removed.
+         *
+         * @param object
+         *         The object that might be removed.
          * @return true if it should be removed.
          */
         abstract boolean shouldClean(final T object);
 
         /**
          * Called after an instance is removed.
-         * @param tIID the InstanceIdentifier of the removed object
+         *
+         * @param tIID
+         *         the InstanceIdentifier of the removed object
          */
         void postRemove(InstanceIdentifier<T> tIID) {
 
@@ -548,6 +580,7 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
                     updateCcapMaps(ccap);
                     logger.info("Created CCAP: {}/{} : {}", iid, ccap, message);
                     logger.info("Created CCAP: {} : {}", iid, message);
+
                     connectionBuilder.setConnected(true).setError(Collections.<String>emptyList());
                 } else {
                     logger.error("Create CCAP Failed: {} : {}", iid, message);
@@ -555,6 +588,10 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
                     connectionBuilder.setConnected(false).setError(Collections.singletonList(message));
                 }
 
+                //register rpc
+                logger.info("Registering CCAP Routed RPC Path...");
+                rpcRegistration.registerPath(CcapContext.class, iid);
+
                 Optional<Ccap> optionalCcap = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, iid);
 
                 final CcapBuilder responseCcapBuilder;
@@ -594,6 +631,10 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
                 final Ccap originalCcap = originalCcaps.get(entry.getKey());
                 //final Ccap updatedCcap = entry.getValue();
 
+                //register rpc
+                logger.info("Registering CCAP Routed RPC Path...");
+                rpcRegistration.registerPath(CcapContext.class, entry.getKey());
+
                 // restore the original data
                 updateQueue.add(entry.getKey());
                 mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, entry.getKey(), originalCcap);
@@ -609,6 +650,10 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
                 final Ccap nukedCcap = originalCcaps.get(iid);
                 removeCcapFromAllMaps(nukedCcap);
 
+                //unregister ccap rpc path
+                logger.info("Un-Registering CCAP Routed RPC Path...");
+                rpcRegistration.unregisterPath(CcapContext.class, iid);
+
                 mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, iid);
 
                 // clean up ccaps level if it is now empty
@@ -660,6 +705,14 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
 
                 final String newGatePathStr = makeGatePathString(gateIID);
 
+                // if a new app comes along add RPC registration
+                final InstanceIdentifier<App> appIID = gateIID.firstIdentifierOf(App.class);
+                // TBD verify if App ID exists first
+
+                //register appID RPC path
+                logger.info("Registering App Routed RPC Path...");
+                rpcRegistration.registerPath(AppContext.class, appIID);
+
                 final InstanceIdentifier<Subscriber> subscriberIID = gateIID.firstIdentifierOf(Subscriber.class);
                 final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(subscriberIID);
                 final InetAddress subscriberAddr = getInetAddress(subscriberKey.getSubscriberId());
@@ -683,8 +736,8 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
                 final ServiceClassName scn = newGate.getTrafficProfile().getServiceClassName();
                 final ServiceFlowDirection scnDirection = findScnOnCcap(scn, ccap);
                 if (scnDirection == null) {
-                    final String msg = String.format("SCN %s not found on CCAP %s for %s",
-                            scn, ccap.getCcapId(), newGatePathStr);
+                    final String msg =
+                            String.format("SCN %s not found on CCAP %s for %s", scn, ccap.getCcapId(), newGatePathStr);
                     logger.error(msg);
                     saveGateError(gateIID, newGatePathStr, msg);
                     continue;
@@ -692,14 +745,16 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
 
                 final PCMMService pcmmService = pcmmServiceMap.get(ccap.getCcapId());
                 if (pcmmService == null) {
-                    final String msg = String.format("Unable to locate PCMM Service for CCAP: %s ; with subscriber: %s",
-                            ccap, subscriberKey.getSubscriberId());
+                    final String msg =
+                            String.format("Unable to locate PCMM Service for CCAP: %s ; with subscriber: %s", ccap,
+                                    subscriberKey.getSubscriberId());
                     logger.error(msg);
                     saveGateError(gateIID, newGatePathStr, msg);
                     continue;
                 }
 
-                PCMMService.GateSetStatus status = pcmmService.sendGateSet(newGatePathStr, subscriberAddr, newGate, scnDirection);
+                PCMMService.GateSendStatus status =
+                        pcmmService.sendGateSet(newGatePathStr, subscriberAddr, newGate, scnDirection);
                 if (status.didSucceed()) {
                     gateMap.put(newGatePathStr, newGate);
                     gateCcapMap.put(newGatePathStr, ccap.getCcapId());
@@ -709,9 +764,34 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
                         .setGatePath(newGatePathStr)
                         .setCcapId(ccap.getCcapId())
                         .setCopsGateId(status.getCopsGateId())
-                        .setCopsState(status.didSucceed() ? "success" : "failure");
+                        .setCopsGateState("")
+                        .setTimestamp(getNowTimeStamp())
+                        .setCopsGateTimeInfo("")
+                        .setCopsGateUsageInfo("")
+                        .setTimestamp(getNowTimeStamp());
+
                 if (!status.didSucceed()) {
                     gateBuilder.setError(Collections.singletonList(status.getMessage()));
+                } else {
+                    PCMMService.GateSendStatus infoStatus = pcmmService.sendGateInfo(newGatePathStr);
+
+                    if (infoStatus.didSucceed()) {
+                        gateBuilder.setCopsGateState(
+                                infoStatus.getCopsGateState() + "/" + infoStatus.getCopsGateStateReason())
+                                .setCopsGateTimeInfo(infoStatus.getCopsGateTimeInfo())
+                                .setCopsGateUsageInfo(infoStatus.getCopsGateUsageInfo());
+                    } else {
+                        List<String> errors = new ArrayList<>(2);
+
+                        // Keep GateSetErrors
+                        if (gateBuilder.getError() != null) {
+                            errors.addAll(gateBuilder.getError());
+                        }
+
+                        errors.add(infoStatus.getMessage());
+                        gateBuilder.setError(errors);
+                    }
+
                 }
 
                 Gate operationalGate = gateBuilder.build();
@@ -731,9 +811,9 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
             gateBuilder.setGateId(InstanceIdentifier.keyOf(gateIID).getGateId())
                     .setGatePath(gatePathStr)
                     .setCopsGateId("")
-                    .setCopsState("N/A");
+                    .setCopsGateState("N/A");
 
-                gateBuilder.setError(Collections.singletonList(error));
+            gateBuilder.setError(Collections.singletonList(error));
 
             Gate operationalGate = gateBuilder.build();
 
@@ -782,21 +862,21 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
 
                 final String gatePathStr = makeGatePathString(removedGateIID);
 
-                    if (gateMap.containsKey(gatePathStr)) {
-                        final Gate thisGate = gateMap.remove(gatePathStr);
-                        final String gateId = thisGate.getGateId();
-                        final String ccapId = gateCcapMap.remove(gatePathStr);
-                        final Ccap thisCcap = ccapMap.get(ccapId);
-                        final PCMMService service = pcmmServiceMap.get(thisCcap.getCcapId());
-                        if (service != null) {
-                            service.sendGateDelete(gatePathStr);
-                            logger.info("onDataChanged(): removed QoS gate {} for {}/{}/{}: ", gateId, ccapId, gatePathStr,
-                                    thisGate);
-                        } else {
-                            logger.warn(
-                                    "Unable to send to locate PCMMService to send gate delete message with CCAP - " + thisCcap);
-                        }
+                if (gateMap.containsKey(gatePathStr)) {
+                    final Gate thisGate = gateMap.remove(gatePathStr);
+                    final String gateId = thisGate.getGateId();
+                    final String ccapId = gateCcapMap.remove(gatePathStr);
+                    final Ccap thisCcap = ccapMap.get(ccapId);
+                    final PCMMService service = pcmmServiceMap.get(thisCcap.getCcapId());
+                    if (service != null) {
+                        service.sendGateDelete(gatePathStr);
+                        logger.info("onDataChanged(): removed QoS gate {} for {}/{}/{}: ", gateId, ccapId, gatePathStr,
+                                thisGate);
+                    } else {
+                        logger.warn("Unable to send to locate PCMMService to send gate delete message with CCAP - "
+                                + thisCcap);
                     }
+                }
 
 
             }
@@ -812,10 +892,431 @@ public class PacketcableProvider implements BindingAwareProvider, AutoCloseable
 
             final GateKey gateKey = InstanceIdentifier.keyOf(iid);
 
-            return appKey.getAppId()
-                    + "/" + subscriberKey.getSubscriberId()
-                    + "/" + gateKey.getGateId();
+            return appKey.getAppId() + "/" + subscriberKey.getSubscriberId() + "/" + gateKey.getGateId();
+        }
+    }
+
+
+    @Override
+    public Future<RpcResult<CcapSetConnectionOutput>> ccapSetConnection(CcapSetConnectionInput input) {
+        // TODO refactor this method into smaller parts
+
+        InstanceIdentifier<Ccap> ccapIid = (InstanceIdentifier<Ccap>) input.getCcapId();
+        List<String> outputError = new ArrayList<String>();
+        String rpcResponse = null;
+        Boolean inputIsConnected = input.getConnection().isConnected();
+        Boolean effectiveIsConnected = null;
+        String ccapId = input.getCcapId().firstIdentifierOf(Ccap.class).firstKeyOf(Ccap.class).getCcapId();
+        PCMMService pcmmService = pcmmServiceMap.get(ccapId);
+
+        if (!inputIsConnected) {
+            // set connected false
+            if (pcmmService.getPcmmPdpSocket()) {
+                outputError.add(ccapId + ": CCAP COPS socket is already closed");
+                effectiveIsConnected = false;
+            } else {
+                //if (!pcmmService.getPcmmCcapClientIsConnected()) {
+                outputError.add(ccapId + ": CCAP client is disconnected with error: "
+                        + pcmmService.getPcmmCcapClientConnectErrMsg());
+                //}
+                pcmmService.ccapClient.disconnect();
+                effectiveIsConnected = false;
+            }
+        } else {
+            // set connected true
+            if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
+                outputError.add(ccapId + ": CCAP COPS socket is already open");
+                outputError.add(ccapId + ": CCAP client is connected");
+                effectiveIsConnected = true;
+            } else {
+                if (pcmmService.getPcmmCcapClientIsConnected()) {
+                    pcmmService.ccapClient.disconnect();
+                }
+                pcmmService.ccapClient.connect();
+                if (pcmmService.getPcmmCcapClientIsConnected()) {
+                    effectiveIsConnected = true;
+                    outputError.add(ccapId + ": CCAP client is connected");
+                } else {
+                    effectiveIsConnected = false;
+                    outputError.add(ccapId + ": CCAP client is disconnected with error: "
+                            + pcmmService.getPcmmCcapClientConnectErrMsg());
+                }
+            }
+        }
+
+        DateAndTime connectionDateAndTime = getNowTimeStamp();
+        org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.ccap.ConnectionBuilder
+                connectionRpcOutput =
+                new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.ccap.ConnectionBuilder()
+                        .setConnected(effectiveIsConnected)
+                        .setError(outputError)
+                        .setTimestamp(connectionDateAndTime);
+
+        org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.CcapBuilder ccapRpcOutput =
+                new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.set.connection.output.CcapBuilder().setCcapId(
+                        ccapId).setConnection(connectionRpcOutput.build());
+
+
+        ConnectionBuilder connectionOps = new ConnectionBuilder().setConnected(effectiveIsConnected)
+                .setError(outputError)
+                .setTimestamp(connectionDateAndTime);
+
+        CcapBuilder responseCcapBuilder = new CcapBuilder().setCcapId(ccapId).setConnection(connectionOps.build());
+
+
+        mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, ccapIid, responseCcapBuilder.build());
+
+
+        DateAndTime rpcDateAndTime = getNowTimeStamp();
+        rpcResponse = ccapId + ": CCAP set complete";
+        CcapSetConnectionOutputBuilder outputBuilder =
+                new CcapSetConnectionOutputBuilder().setCcap(ccapRpcOutput.build())
+                        .setResponse(rpcResponse)
+                        .setTimestamp(rpcDateAndTime);
+
+        return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
+    }
+
+
+
+    @Override
+    public Future<RpcResult<CcapPollConnectionOutput>> ccapPollConnection(CcapPollConnectionInput input) {
+        // TODO refactor this method into smaller parts
+
+        InstanceIdentifier<Ccap> ccapIid = (InstanceIdentifier<Ccap>) input.getCcapId();
+        List<String> outputError = new ArrayList<String>();
+
+        String ccapId = input.getCcapId().firstIdentifierOf(Ccap.class).firstKeyOf(Ccap.class).getCcapId();
+        PCMMService pcmmService = pcmmServiceMap.get(ccapId);
+        Boolean effectiveIsConnected = true;
+        String response = null;
+        org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.ccap.ConnectionBuilder
+                connectionRpcOutput =
+                new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.ccap.ConnectionBuilder();
+
+        if (pcmmService != null) {
+            if (pcmmService.getPcmmPdpSocket()) {
+                outputError.add(ccapId + ": CCAP Cops socket is closed");
+                if (!pcmmService.getPcmmCcapClientIsConnected()) {
+                    outputError.add(ccapId + ": CCAP client is disconnected with error: "
+                            + pcmmService.getPcmmCcapClientConnectErrMsg());
+                }
+                effectiveIsConnected = false;
+            } else {
+                //outputError.add(String.format(ccapId+": CCAP Cops socket is open"));
+                if (!pcmmService.getPcmmCcapClientIsConnected()) {
+                    outputError.add(ccapId + ": CCAP client is disconnected with error: "
+                            + pcmmService.getPcmmCcapClientConnectErrMsg());
+                    effectiveIsConnected = false;
+                } else {
+                    outputError.add(ccapId + ": CCAP client is connected");
+                }
+            }
+            DateAndTime connectionDateAndTime = getNowTimeStamp();
+
+
+            ConnectionBuilder connectionOps = new ConnectionBuilder().setConnected(effectiveIsConnected)
+                    .setError(outputError)
+                    .setTimestamp(connectionDateAndTime);
+
+            CcapBuilder responseCcapBuilder = new CcapBuilder().setCcapId(ccapId).setConnection(connectionOps.build());
+
+            connectionRpcOutput =
+                    new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.ccap.ConnectionBuilder()
+                            .setConnected(effectiveIsConnected)
+                            .setError(outputError)
+                            .setTimestamp(connectionDateAndTime);
+
+            mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, ccapIid, responseCcapBuilder.build());
+            response = ccapId + ": CCAP poll complete";
+        } else {
+            //pcmmService is null, do not poll
+            response = ccapId + ": CCAP connection null; no poll performed";
+        }
+
+        DateAndTime rpcDateAndTime = getNowTimeStamp();
+
+        org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.CcapBuilder ccapRpcOutput =
+                new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.ccap.poll.connection.output.CcapBuilder().setCcapId(
+                        ccapId).setConnection(connectionRpcOutput.build());
+
+        CcapPollConnectionOutputBuilder outputBuilder =
+                new CcapPollConnectionOutputBuilder().setCcap(ccapRpcOutput.build())
+                        .setResponse(response)
+                        .setTimestamp(rpcDateAndTime);
+
+        return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
+    }
+
+
+
+    private App readAppFromOperationalDatastore(InstanceIdentifier<App> appIid) {
+        Optional<App> optionalApp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, appIid);
+        AppBuilder thisAppBuilder = new AppBuilder(optionalApp.get());
+        App thisApp = thisAppBuilder.build();
+        logger.info("readAppFromConfigDatastore() retrived App: " + thisApp.getAppId());
+        return thisApp;
+    }
+
+    private Gate readGateFromOperationalDatastore(InstanceIdentifier<Gate> gateIid) {
+        Optional<Gate> optionalGate = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, gateIid);
+        if (optionalGate.isPresent()) {
+            GateBuilder gateBuilder = new GateBuilder(optionalGate.get());
+            Gate thisGate = gateBuilder.build();
+            return thisGate;
+        } else {
+            return null;
+        }
+    }
+
+    private Subscriber readSubscriberFromOperationalDatastore(InstanceIdentifier<Subscriber> subscriberIid) {
+        Optional<Subscriber> optionalSubscriber = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, subscriberIid);
+        if (optionalSubscriber.isPresent()) {
+            SubscriberBuilder subscriberBuilder = new SubscriberBuilder(optionalSubscriber.get());
+            Subscriber thisSubscriber = subscriberBuilder.build();
+            return thisSubscriber;
+        } else {
+            return null;
         }
     }
 
+
+
+    @Override
+    public Future<RpcResult<QosPollGatesOutput>> qosPollGates(QosPollGatesInput input) {
+        // TODO refactor this method into smaller parts
+
+        InstanceIdentifier<App> appIid = (InstanceIdentifier<App>) input.getAppId();
+        //logger.info("qospollgates appIid : "+appIid.toString());
+        App app = readAppFromOperationalDatastore(appIid);
+        //logger.info("qospollgates app : "+app.toString());
+        AppKey appKey = InstanceIdentifier.keyOf(appIid);
+        String inputSubscriberId = input.getSubscriberId();
+        String inputGateId = input.getGateId();
+        List<String> gateOutputError = Collections.emptyList();
+        String subscriberId = null;
+        String gateId = null;
+        String ccapId = null;
+        String gatePathStr = null;
+        String opsCopsGateId = null;
+        Gate opsGate = null;
+
+        String rpcResponse = null;
+
+        org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.qos.poll.gates.output.GateBuilder gateOutputBuilder =
+                new org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.qos.poll.gates.output.GateBuilder();
+
+        GateBuilder gateBuilder = new GateBuilder();
+
+        if (inputSubscriberId != null) {
+            if (inputGateId != null) {
+                //Subscriber Id and Gate Id provided, only one gate to be poolled
+
+                //generate the gateiid
+                InstanceIdentifier<Gate> gateIid = appIid.builder()
+                        .child(Subscribers.class)
+                        .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
+                        .child(Gates.class)
+                        .child(Gate.class, new GateKey(inputGateId))
+                        .build();
+
+
+                opsGate = readGateFromOperationalDatastore(gateIid);
+
+                //does the gate exists in the Operational DS?
+                if (opsGate == null) {
+                    gatePathStr = appKey.getAppId() + "/" + inputSubscriberId + "/" + inputGateId;
+                    rpcResponse = gatePathStr + ": gate does not exist in the system; gate poll not performed";
+                } else {
+                    opsCopsGateId = opsGate.getCopsGateId();
+                    gatePathStr = opsGate.getGatePath();
+
+                    if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
+                        ccapId = findCcapForSubscriberId(getInetAddress(inputSubscriberId)).getCcapId();
+                        PCMMService pcmmService = pcmmServiceMap.get(ccapId);
+                        //is the CCAP socket open?
+                        if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
+                            PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
+                            DateAndTime gateDateAndTime = getNowTimeStamp();
+                            //logger.info("qospollgates Gate Status : GateID/"+status.getCopsGateId());
+                            //logger.info("qospollgates Gate Status : Message/"+status.getMessage());
+                            //logger.info("qospollgates Gate Status : DidSucceed/"+status.didSucceed());
+                            gateOutputError = Collections.singletonList(status.getMessage());
+
+                            gateOutputBuilder.setGatePath(gatePathStr)
+                                    .setCcapId(ccapId)
+                                    .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
+                                    .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
+                                    .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
+                                    .setCopsGateId(status.getCopsGateId())
+                                    .setError(gateOutputError)
+                                    .setTimestamp(gateDateAndTime);
+
+                            gateBuilder.setGateId(inputGateId)
+                                    .setGatePath(gatePathStr)
+                                    .setCcapId(ccapId)
+                                    .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
+                                    .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
+                                    .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
+                                    .setCopsGateId(status.getCopsGateId())
+                                    .setError(gateOutputError)
+                                    .setTimestamp(gateDateAndTime);
+
+                            mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
+                            rpcResponse = gatePathStr + ": gate poll complete";
+                        } else {
+                            rpcResponse =
+                                    ccapId + ": CCAP socket is down or client disconnected; gate poll not performed";
+                        }
+                    } else {
+                        rpcResponse = gatePathStr + ": gate not active; gate poll not performed";
+                    }
+                }
+            } else {
+                //inputGateId is null; pool all gates for the subscriber if the sub exists
+
+                //generate active subIid
+                InstanceIdentifier<Subscriber> subIid = appIid.builder()
+                        .child(Subscribers.class)
+                        .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
+                        .build();
+                //does the subscriber provided exists in the Operational Datastore?
+                Subscriber sub = readSubscriberFromOperationalDatastore(subIid);
+                if (sub != null) {
+                    //If Subscriber exsits poll all gates for the subscriber
+                    subscriberId = sub.getSubscriberId();
+                    List<Gate> gateList = sub.getGates().getGate();
+                    for (Gate gate : gateList) {
+                        //generate active gateIid
+                        gateId = gate.getGateId();
+                        InstanceIdentifier<Gate> gateIid =
+                                subIid.builder().child(Gates.class).child(Gate.class, new GateKey(gateId)).build();
+
+                        opsGate = readGateFromOperationalDatastore(gateIid);
+                        opsCopsGateId = opsGate.getCopsGateId();
+                        //generate active gatePathStr
+                        gatePathStr = appKey.getAppId() + "/" + subscriberId + "/" + gateId;
+
+                        if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
+                            ccapId = findCcapForSubscriberId(getInetAddress(subscriberId)).getCcapId();
+                            PCMMService pcmmService = pcmmServiceMap.get(ccapId);
+                            //is the CCAP socket open?
+                            if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
+                                PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
+                                DateAndTime gateDateAndTime = getNowTimeStamp();
+
+                                gateBuilder.setGateId(gateId)
+                                        .setGatePath(gatePathStr)
+                                        .setCcapId(ccapId)
+                                        .setCopsGateState(
+                                                status.getCopsGateState() + "/" + status.getCopsGateStateReason())
+                                        .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
+                                        .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
+                                        .setCopsGateId(status.getCopsGateId())
+                                        .setError(gateOutputError)
+                                        .setTimestamp(gateDateAndTime);
+
+                                mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
+                            } else {
+                                logger.info(
+                                        "qospollgates: {}: CCAP Cops socket is down or client disconnected; gate poll not performed",
+                                        ccapId);
+                            }
+                        } else {
+                            //TODO define what happens if a gate is not active.. is nothing ok?
+                            logger.info("qospollgates: {}: gate not active; gate poll not performed", gatePathStr);
+                        }
+                    } //for
+                    rpcResponse = inputSubscriberId + "/: subscriber subtree poll in progress";
+                } else {
+                    rpcResponse =
+                            inputSubscriberId + "/: subscriber is not defined in the system, gate poll not performed";
+                }
+            }
+        } //inputSubId if
+        else {
+            // inputSubId is null
+            if (inputGateId != null) {
+                gatePathStr = appKey.getAppId() + "/" + inputSubscriberId + "/" + inputGateId;
+                rpcResponse = gatePathStr + ": Subscriber ID not provided; gate poll not performed";
+            } else {
+                //poll all gates for the appId
+
+                Subscribers subs = app.getSubscribers();
+
+                logger.info("qospollgates subscribers: " + subs.toString());
+
+                List<Subscriber> subList = subs.getSubscriber();
+                logger.info("qospollgates subList: " + subList.toString());
+                for (Subscriber sub : subList) {
+
+                    //generate active subIid
+                    subscriberId = sub.getSubscriberId();
+                    InstanceIdentifier<Subscriber> subIid = appIid.builder()
+                            .child(Subscribers.class)
+                            .child(Subscriber.class, new SubscriberKey(subscriberId))
+                            .build();
+
+                    List<Gate> gateList = sub.getGates().getGate();
+                    for (Gate gate : gateList) {
+                        //logger.info("qospollgates active gate: "+gate);
+
+                        //generate active gateIid
+                        gateId = gate.getGateId();
+                        InstanceIdentifier<Gate> gateIid =
+                                subIid.builder().child(Gates.class).child(Gate.class, new GateKey(gateId)).build();
+
+                        opsGate = readGateFromOperationalDatastore(gateIid);
+                        opsCopsGateId = opsGate.getCopsGateId();
+                        //generate active gatePathStr
+                        gatePathStr = appKey.getAppId() + "/" + subscriberId + "/" + gateId;
+                        if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
+                            ccapId = findCcapForSubscriberId(getInetAddress(subscriberId)).getCcapId();
+                            PCMMService pcmmService = pcmmServiceMap.get(ccapId);
+                            //is the CCAP socket open?
+                            if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
+                                PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
+                                DateAndTime gateDateAndTime = getNowTimeStamp();
+                                gateOutputError = Collections.singletonList(status.getMessage());
+
+
+                                gateBuilder.setGateId(gateId)
+                                        .setGatePath(gatePathStr)
+                                        .setCcapId(ccapId)
+                                        .setCopsGateState(
+                                                status.getCopsGateState() + "/" + status.getCopsGateStateReason())
+                                        .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
+                                        .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
+                                        .setCopsGateId(status.getCopsGateId())
+                                        .setError(gateOutputError)
+                                        .setTimestamp(gateDateAndTime);
+
+                                mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
+                            } else {
+                                logger.info(
+                                        "qospollgates: {}: CCAP socket is down or client disconnected; gate poll not performed",
+                                        ccapId);
+                            }
+                        } else {
+                            //TODO define what happens if a gate is not active.. is nothing ok
+                            logger.info("qospollgates: {}: gate not active; gate poll not performed", gatePathStr);
+                        }
+                    }
+                }
+                rpcResponse = appKey.getAppId() + "/: gate subtree poll in progress";
+            }
+        }
+
+        DateAndTime rpcDateAndTime = getNowTimeStamp();
+
+        QosPollGatesOutputBuilder outputBuilder = new QosPollGatesOutputBuilder().setTimestamp(rpcDateAndTime)
+                .setResponse(rpcResponse)
+                .setGate(gateOutputBuilder.build());
+        return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
+    }
+
+    private DateAndTime getNowTimeStamp() {
+        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
+        return new DateAndTime(dateFormat.format(new Date()));
+    }
 }
index 650ae3367ecaa4c0be4a517deecfee5c60ffeaa3..4d940e812b1048589bdf8883d53ced66a337a735 100644 (file)
@@ -5,6 +5,9 @@
 package org.opendaylight.controller.packetcable.provider;
 
 import static junit.framework.TestCase.assertEquals;
+
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -43,10 +46,10 @@ import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gate.spec
 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.Gate;
 import org.opendaylight.yang.gen.v1.urn.packetcable.rev151101.pcmm.qos.traffic.profile.TrafficProfile;
 import org.pcmm.PCMMPdpAgent;
-import org.pcmm.gates.IGateSpec.Direction;
 import org.pcmm.gates.IPCMMGate;
 import org.pcmm.rcd.IPCMMClient;
 import org.pcmm.rcd.impl.CMTS;
+import org.pcmm.rcd.impl.CMTSConfig;
 import org.umu.cops.stack.COPSClientSI;
 import org.umu.cops.stack.COPSContext;
 import org.umu.cops.stack.COPSContext.RType;
@@ -120,33 +123,33 @@ public class PCMMServiceTest {
     public void setup() throws IOException {
         srcAddr = new Ipv4Address("10.10.10.0");
         dstAddr = new Ipv4Address("10.32.99.99");
+        invalidCmAddrInet = InetAddress.getByAddress(new byte[] {99, 99, 99, 99});
 
         if (realCmts) {
             cmAddrInet = InetAddress.getByAddress(new byte[] {10, 32, 110, (byte)172});
-            invalidCmAddrInet = InetAddress.getByAddress(new byte[] {99, 99, 99, 99});
+
 
             // Use me when testing against a CMTS or emulator not running in the same JVM
             cmtsAddr = new Ipv4Address("10.32.10.3");
             ccap = makeCcapObj(PCMMPdpAgent.WELL_KNOWN_PDP_PORT, cmtsAddr, ccapId);
         } else {
             cmAddrInet = InetAddress.getByAddress(new byte[] {10, 32, 110, (byte)180});
-            invalidCmAddrInet = InetAddress.getByAddress(new byte[] {99, 99, 99, 99});
 
             // Use me for automated testing and the CMTS emulator running in the same JVM
             cmtsAddr = new Ipv4Address("127.0.0.1");
 
-            final Set<String> upGate = new HashSet<>();
-            upGate.add("extrm_up");
-            final Set<String> dnGate = new HashSet<>();
-            dnGate.add("extrm_dn");
-            final Map<Direction, Set<String>> gates = new HashMap<>();
-            gates.put(Direction.UPSTREAM, upGate);
-            gates.put(Direction.DOWNSTREAM, dnGate);
+            final Set<String> upSCN = new HashSet<>();
+            upSCN.add("extrm_up");
+            final Set<String> dnSCN = new HashSet<>();
+            dnSCN.add("extrm_dn");
 
             final Map<String, Boolean> cmStatus = new HashMap<>();
             cmStatus.put(cmAddrInet.getHostAddress(), true);
             cmStatus.put(invalidCmAddrInet.getHostAddress(), false);
-            icmts = new CMTS(gates, cmStatus);
+
+            CMTSConfig config = new CMTSConfig(0, (short)4, upSCN, dnSCN, cmStatus);
+
+            icmts = new CMTS(config);
             icmts.startServer();
 
             ccap = makeCcapObj(icmts.getPort(), cmtsAddr, ccapId);
@@ -250,7 +253,7 @@ public class PCMMServiceTest {
     public void testAddAndRemoveInvalidCmAddrUpGate() throws Exception {
         // TODO - fix cmts emulator
         final String expectedMsgStart = "404 Not Found - sendGateSet for " + ccapId + '/' + gatePath
-                + " returned error - Error Code: 13 Error Subcode : 0  Invalid SubscriberID";
+                + " returned error - Error Code: 13 Subcode: 0  Invalid SubscriberID";
         addInvalidGate(service, "extrm_up", srcAddr, dstAddr, ServiceFlowDirection.Us, invalidCmAddrInet, gatePath,
                 expectedMsgStart);
     }
@@ -258,7 +261,7 @@ public class PCMMServiceTest {
     @Test
     public void testAddInvalidScnUpGate() throws Exception {
         final String expectedMsgStart = "404 Not Found - sendGateSet for " + ccapId + '/' + gatePath
-                + " returned error - Error Code: 11 Error Subcode : 0  Undefined Service Class Name";
+                + " returned error - Error Code: 11 Subcode: 0  Undefined Service Class Name";
         addInvalidGate(service, "extrm_up_invalid", srcAddr, dstAddr, ServiceFlowDirection.Us, cmAddrInet, gatePath,
                 expectedMsgStart);
     }
@@ -266,7 +269,7 @@ public class PCMMServiceTest {
     @Test
     public void testAddInvalidScnDownGate() throws Exception {
         final String expectedMsgStart = "404 Not Found - sendGateSet for " + ccapId + '/' + gatePath
-                + " returned error - Error Code: 11 Error Subcode : 0  Undefined Service Class Name";
+                + " returned error - Error Code: 11 Subcode: 0  Undefined Service Class Name";
         addInvalidGate(service, "extrm_dn_invalid", srcAddr, dstAddr, ServiceFlowDirection.Ds, cmAddrInet, gatePath,
                 expectedMsgStart);
     }
@@ -362,10 +365,11 @@ public class PCMMServiceTest {
 //        Assert.assertNotNull(gateSetMsg);
 //        Assert.assertTrue(gateSetMsg, gateSetMsg.startsWith(expGateSetMsgStart));
 
-        // TODO update this method for the new GateSetStatus object
-        PCMMService.GateSetStatus status = service.sendGateSet(gatePath, cmAddrInet, gate, direction);
+        // TODO update this method for the new GateSendStatus object
+        PCMMService.GateSendStatus status = service.sendGateSet(gatePath, cmAddrInet, gate, direction);
         Assert.assertNotNull(status);
-        Assert.assertTrue(status.getMessage().startsWith(expGateSetMsgStart));
+        assertThat(status.getMessage(), startsWith(expGateSetMsgStart));
+
 
         // TODO - add validation to the PCMMGateReq contained within the map
         if (status.didSucceed()) {