1717package com .cloud .network .vpc ;
1818
1919import java .util .ArrayList ;
20+ import java .util .Collections ;
21+ import java .util .Comparator ;
2022import java .util .List ;
2123import java .util .Map ;
2224
2729import org .apache .cloudstack .api .command .user .network .CreateNetworkACLCmd ;
2830import org .apache .cloudstack .api .command .user .network .ListNetworkACLListsCmd ;
2931import org .apache .cloudstack .api .command .user .network .ListNetworkACLsCmd ;
32+ import org .apache .cloudstack .api .command .user .network .MoveNetworkAclItemCmd ;
3033import org .apache .cloudstack .api .command .user .network .UpdateNetworkACLItemCmd ;
3134import org .apache .cloudstack .api .command .user .network .UpdateNetworkACLListCmd ;
3235import org .apache .cloudstack .context .CallContext ;
@@ -936,4 +939,123 @@ public NetworkACL updateNetworkACL(UpdateNetworkACLListCmd updateNetworkACLListC
936939 return _networkACLDao .findById (id );
937940 }
938941
942+ @ Override
943+ public NetworkACLItem moveNetworkAclRuleToNewPosition (MoveNetworkAclItemCmd moveNetworkAclItemCmd ) {
944+ String uuidRuleBeingMoved = moveNetworkAclItemCmd .getUuidRuleBeingMoved ();
945+ String nextAclRuleUuid = moveNetworkAclItemCmd .getNextAclRuleUuid ();
946+ String previousAclRuleUuid = moveNetworkAclItemCmd .getPreviousAclRuleUuid ();
947+
948+ if (StringUtils .isBlank (previousAclRuleUuid ) && StringUtils .isBlank (nextAclRuleUuid )) {
949+ throw new InvalidParameterValueException ("Both previous and next ACL rule IDs cannot be blank." );
950+ }
951+
952+ NetworkACLItemVO ruleBeingMoved = _networkACLItemDao .findByUuid (uuidRuleBeingMoved );
953+ if (ruleBeingMoved == null ) {
954+ throw new InvalidParameterValueException (String .format ("Could not find a rule with ID[%s]" , uuidRuleBeingMoved ));
955+ }
956+ NetworkACLItemVO previousRule = retrieveAndValidateAclRule (previousAclRuleUuid );
957+ NetworkACLItemVO nextRule = retrieveAndValidateAclRule (nextAclRuleUuid );
958+
959+ validateMoveAclRulesData (ruleBeingMoved , previousRule , nextRule );
960+
961+ List <NetworkACLItemVO > allAclRules = getAllAclRulesSortedByNumber (ruleBeingMoved .getAclId ());
962+ if (previousRule == null ) {
963+ return moveRuleToTheTop (ruleBeingMoved , allAclRules );
964+ }
965+ if (nextRule == null ) {
966+ return moveRuleToTheBottom (ruleBeingMoved , allAclRules );
967+ }
968+
969+ return moveRuleBetweenAclRules (ruleBeingMoved , allAclRules , previousRule , nextRule );
970+ }
971+
972+ private List <NetworkACLItemVO > getAllAclRulesSortedByNumber (long aclId ) {
973+ List <NetworkACLItemVO > allAclRules = _networkACLItemDao .listByACL (aclId );
974+ Collections .sort (allAclRules , new Comparator <NetworkACLItemVO >() {
975+ @ Override
976+ public int compare (NetworkACLItemVO o1 , NetworkACLItemVO o2 ) {
977+ return o1 .number - o2 .number ;
978+ }
979+ });
980+ return allAclRules ;
981+ }
982+
983+ private NetworkACLItem moveRuleBetweenAclRules (NetworkACLItemVO ruleBeingMoved , List <NetworkACLItemVO > allAclRules , NetworkACLItemVO previousRule , NetworkACLItemVO nextRule ) {
984+ if (previousRule .getNumber () + 1 != nextRule .getNumber ()) {
985+ int newNumberFieldValue = previousRule .getNumber () + 1 ;
986+ for (NetworkACLItemVO networkACLItemVO : allAclRules ) {
987+ if (networkACLItemVO .getNumber () == newNumberFieldValue ) {
988+ throw new InvalidParameterValueException ("There are some inconsistencies with the data you sent. The new position calculated already has a ACL rule on it." );
989+ }
990+ }
991+ ruleBeingMoved .setNumber (newNumberFieldValue );
992+ _networkACLItemDao .updateNumberFieldNetworkItem (ruleBeingMoved .getId (), newNumberFieldValue );
993+ return _networkACLItemDao .findById (ruleBeingMoved .getId ());
994+ }
995+ int positionToStartProcessing = 0 ;
996+ for (int i = 0 ; i < allAclRules .size (); i ++) {
997+ if (allAclRules .get (i ).getId () == previousRule .getId ()) {
998+ positionToStartProcessing = i + 1 ;
999+ break ;
1000+ }
1001+ }
1002+ return updateAclRuleToNewPositionAndExecuteShiftIfNecessary (ruleBeingMoved , previousRule .getNumber () + 1 , allAclRules , positionToStartProcessing );
1003+ }
1004+
1005+ private NetworkACLItem moveRuleToTheBottom (NetworkACLItemVO ruleBeingMoved , List <NetworkACLItemVO > allAclRules ) {
1006+ NetworkACLItemVO lastAclRule = allAclRules .get (allAclRules .size () - 1 );
1007+
1008+ int newNumberFieldValue = lastAclRule .getNumber () + 1 ;
1009+ ruleBeingMoved .setNumber (newNumberFieldValue );
1010+
1011+ _networkACLItemDao .updateNumberFieldNetworkItem (ruleBeingMoved .getId (), newNumberFieldValue );
1012+ return _networkACLItemDao .findById (ruleBeingMoved .getId ());
1013+ }
1014+
1015+ private NetworkACLItem moveRuleToTheTop (NetworkACLItemVO ruleBeingMoved , List <NetworkACLItemVO > allAclRules ) {
1016+ return updateAclRuleToNewPositionAndExecuteShiftIfNecessary (ruleBeingMoved , 1 , allAclRules , 0 );
1017+ }
1018+
1019+ private NetworkACLItem updateAclRuleToNewPositionAndExecuteShiftIfNecessary (NetworkACLItemVO ruleBeingMoved , int newNumberFieldValue , List <NetworkACLItemVO > allAclRules , int indexToStartProcessing ) {
1020+ ruleBeingMoved .setNumber (newNumberFieldValue );
1021+ for (int i = indexToStartProcessing ; i < allAclRules .size (); i ++) {
1022+ NetworkACLItemVO networkACLItemVO = allAclRules .get (i );
1023+ if (networkACLItemVO .getId () == ruleBeingMoved .getId ()) {
1024+ continue ;
1025+ }
1026+ if (newNumberFieldValue != networkACLItemVO .getNumber ()) {
1027+ break ;
1028+ }
1029+ int newNumberFieldValueNextAclRule = newNumberFieldValue + 1 ;
1030+ updateAclRuleToNewPositionAndExecuteShiftIfNecessary (networkACLItemVO , newNumberFieldValueNextAclRule , allAclRules , i );
1031+ }
1032+ _networkACLItemDao .updateNumberFieldNetworkItem (ruleBeingMoved .getId (), newNumberFieldValue );
1033+ return _networkACLItemDao .findById (ruleBeingMoved .getId ());
1034+ }
1035+
1036+ private NetworkACLItemVO retrieveAndValidateAclRule (String aclRuleUuid ) {
1037+ if (StringUtils .isBlank (aclRuleUuid )) {
1038+ return null ;
1039+ }
1040+ NetworkACLItemVO aclRule = _networkACLItemDao .findByUuid (aclRuleUuid );
1041+ if (aclRule == null ) {
1042+ throw new InvalidParameterValueException (String .format ("Could not find rule with ID [%s]" , aclRuleUuid ));
1043+ }
1044+ return aclRule ;
1045+ }
1046+
1047+ private void validateMoveAclRulesData (NetworkACLItemVO ruleBeingMoved , NetworkACLItemVO previousRule , NetworkACLItemVO nextRule ) {
1048+ if (nextRule == null && previousRule == null ) {
1049+ throw new InvalidParameterValueException ("Both previous and next ACL rule IDs cannot be invalid." );
1050+ }
1051+ long aclId = ruleBeingMoved .getAclId ();
1052+
1053+ if ((nextRule != null && nextRule .getAclId () != aclId ) || (previousRule != null && previousRule .getAclId () != aclId )) {
1054+ throw new InvalidParameterValueException ("Cannot use ACL rules from differenting ACLs. Rule being moved." );
1055+ }
1056+ NetworkACLVO acl = _networkACLDao .findById (aclId );
1057+ Vpc vpc = _entityMgr .findById (Vpc .class , acl .getVpcId ());
1058+ Account caller = CallContext .current ().getCallingAccount ();
1059+ _accountMgr .checkAccess (caller , null , true , vpc );
1060+ }
9391061}
0 commit comments