CloudSlang/cs-actions

View on GitHub
cs-vmware/src/main/java/io/cloudslang/content/vmware/connection/helpers/WaitForValues.java

Summary

Maintainability
C
1 day
Test Coverage
/*
 * Copyright 2019-2024 Open Text
 * This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0 which accompany this distribution.
 *
 * The Apache License is available at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package io.cloudslang.content.vmware.connection.helpers;

import com.vmware.vim25.HttpNfcLeaseState;
import com.vmware.vim25.InvalidCollectorVersionFaultMsg;
import com.vmware.vim25.InvalidPropertyFaultMsg;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.ObjectSpec;
import com.vmware.vim25.ObjectUpdate;
import com.vmware.vim25.ObjectUpdateKind;
import com.vmware.vim25.PropertyChange;
import com.vmware.vim25.PropertyChangeOp;
import com.vmware.vim25.PropertyFilterSpec;
import com.vmware.vim25.PropertyFilterUpdate;
import com.vmware.vim25.PropertySpec;
import com.vmware.vim25.RuntimeFaultFaultMsg;
import com.vmware.vim25.ServiceContent;
import com.vmware.vim25.UpdateSet;
import com.vmware.vim25.VimPortType;
import com.vmware.vim25.WaitOptions;
import io.cloudslang.content.vmware.connection.Connection;
import io.cloudslang.content.vmware.constants.Constants;
import org.w3c.dom.Element;

import java.util.Arrays;

public class WaitForValues {
    private static final String ERROR = "error";
    private static final String READY = "ready";
    private static final String FILTER_VALUES = "filtervals";
    private static final String KEY_VALUE_NULL_STRING = "val: null";
    private static final int MAX_TRIED_WAIT_FOR_UPDATE_COUNTER = 100;

    private ServiceContent serviceContent;
    private VimPortType vimPort;

    public WaitForValues(Connection connection) {
        this.serviceContent = connection.getServiceContent();
        this.vimPort = connection.getVimPort();
    }

    /**
     * Handle Updates for a single object. waits till expected values of
     * properties to check are reached Destroys the ObjectFilter when done.
     *
     * @param objMor         MOR of the Object to wait for param
     * @param filterProps    Properties list to filter
     * @param endWaitProps   Properties list to check for expected values these be properties
     *                       of a property in the filter properties list
     * @param expectedValues values for properties to end the wait
     * @return true indicating expected values were met, and false otherwise
     * @throws RuntimeFaultFaultMsg
     * @throws InvalidPropertyFaultMsg
     * @throws InvalidCollectorVersionFaultMsg
     */
    public Object[] wait(ManagedObjectReference objMor, String[] filterProps, String[] endWaitProps, Object[][] expectedValues)
            throws InvalidPropertyFaultMsg, RuntimeFaultFaultMsg, InvalidCollectorVersionFaultMsg {

        String version = Constants.EMPTY;
        String stateVal = null;

        Object[] endValues = new Object[endWaitProps.length];
        Object[] filterValues = new Object[filterProps.length];

        PropertyFilterSpec spec = propertyFilterSpec(objMor, filterProps);
        ManagedObjectReference filterSpecRef = vimPort.createFilter(serviceContent.getPropertyCollector(), spec, true);

        boolean reached = false;
        UpdateSet updateset;
        while (!reached) {
            updateset = vimPort.waitForUpdatesEx(serviceContent.getPropertyCollector(), version, new WaitOptions());

            int waitForUpdateCounter = 0;
            if (updateset == null || updateset.getFilterSet() == null) {
                waitForUpdateCounter++;
                if (waitForUpdateCounter <= MAX_TRIED_WAIT_FOR_UPDATE_COUNTER) {
                    continue;
                }
                break;
            }

            version = updateset.getVersion();
            for (PropertyFilterUpdate filtup : updateset.getFilterSet()) {
                for (ObjectUpdate objup : filtup.getObjectSet()) {
                    if (objup.getKind() == ObjectUpdateKind.MODIFY || objup.getKind() == ObjectUpdateKind.ENTER ||
                            objup.getKind() == ObjectUpdateKind.LEAVE) {
                        for (PropertyChange propchg : objup.getChangeSet()) {
                            updateValues(endWaitProps, endValues, propchg);
                            updateValues(filterProps, filterValues, propchg);
                        }
                    }
                }
            }
            // Check if the expected values have been reached and exit the loop if done.
            // Also exit the WaitForUpdates loop if this is the case.
            for (int chgi = 0; chgi < endValues.length && !reached; chgi++) {
                for (int vali = 0; vali < expectedValues[chgi].length && !reached; vali++) {
                    Object expctdval = expectedValues[chgi][vali];
                    if (endValues[chgi].toString().contains(KEY_VALUE_NULL_STRING)) {
                        Element stateElement = (Element) endValues[chgi];
                        if (stateElement != null && stateElement.getFirstChild() != null) {
                            stateVal = stateElement.getFirstChild().getTextContent();
                            reached = expctdval.toString().equalsIgnoreCase(stateVal);
                        }
                    } else {
                        expctdval = expectedValues[chgi][vali];
                        reached = expctdval.equals(endValues[chgi]);
                        stateVal = FILTER_VALUES;
                    }
                }
            }
        }
        try {
            vimPort.destroyPropertyFilter(filterSpecRef);
        } catch (RuntimeFaultFaultMsg e) {
            throw new RuntimeException(e.getMessage());
        }

        return getObjectState(stateVal, filterValues);
    }

    private Object[] getObjectState(String stateVal, Object[] filterValues) {
        if (stateVal == null) {
            return new Object[]{HttpNfcLeaseState.ERROR};
        } else {
            switch (stateVal) {
                case READY:
                    return new Object[]{HttpNfcLeaseState.READY};
                case ERROR:
                    return new Object[]{HttpNfcLeaseState.ERROR};
                case FILTER_VALUES:
                    return filterValues;
                default:
                    return null;
            }
        }
    }

    private PropertyFilterSpec propertyFilterSpec(ManagedObjectReference objmor, String[] filterProps) {
        ObjectSpec objSpec = new ObjectSpec();
        objSpec.setObj(objmor);
        objSpec.setSkip(false);

        PropertySpec propSpec = new PropertySpec();
        propSpec.getPathSet().addAll(Arrays.asList(filterProps));
        propSpec.setType(objmor.getType());

        PropertyFilterSpec spec = new PropertyFilterSpec();
        spec.getObjectSet().add(objSpec);
        spec.getPropSet().add(propSpec);

        return spec;
    }

    private void updateValues(String[] props, Object[] vals, PropertyChange propchg) {
        for (int findi = 0; findi < props.length; findi++) {
            if (propchg.getName().lastIndexOf(props[findi]) >= 0) {
                vals[findi] = propchg.getOp() == PropertyChangeOp.REMOVE ? Constants.EMPTY : propchg.getVal();
            }
        }
    }
}