content: // Licensed to the Apache Software Foundation (ASF) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The ASF licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  
  package com.cloud.api.dispatch;
  
  import java.lang.reflect.Field;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  
  import org.apache.cloudstack.api.ApiConstants;
  import org.apache.cloudstack.api.BaseCmd;
  import org.apache.cloudstack.api.Parameter;
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.LogManager;
  
  /**
   * This worker validates parameters in a generic way, by using annotated
   * restrictions without involving the {@Link BaseCmd}. This worker doesn't
   * know or care about the meaning of the parameters and that's why we can
   * have it out of the {@Link BaseCmd}
   *
   * @author afornie
   */
  public class ParamGenericValidationWorker implements DispatchWorker {
  
      protected Logger logger = LogManager.getLogger(getClass());
  
      protected static final List<String> defaultParamNames = new ArrayList<String>();
  
      static {
          defaultParamNames.add(ApiConstants.ACCOUNT_ID);
          defaultParamNames.add(ApiConstants.CTX_START_EVENT_ID);
          defaultParamNames.add(ApiConstants.COMMAND);
          defaultParamNames.add(ApiConstants.CMD_EVENT_TYPE);
          defaultParamNames.add(ApiConstants.USERNAME);
          defaultParamNames.add(ApiConstants.USER_ID);
          defaultParamNames.add(ApiConstants.PASSWORD);
          defaultParamNames.add(ApiConstants.DOMAIN);
          defaultParamNames.add(ApiConstants.DOMAIN_ID);
          defaultParamNames.add(ApiConstants.DOMAIN__ID);
          defaultParamNames.add(ApiConstants.SESSIONKEY);
          defaultParamNames.add(ApiConstants.RESPONSE);
          defaultParamNames.add(ApiConstants.PAGE);
          defaultParamNames.add(ApiConstants.USER_API_KEY);
          defaultParamNames.add(ApiConstants.API_KEY);
          defaultParamNames.add(ApiConstants.PAGE_SIZE);
          defaultParamNames.add(ApiConstants.HTTPMETHOD);
          defaultParamNames.add(ApiConstants.SIGNATURE);
          defaultParamNames.add(ApiConstants.CTX_ACCOUNT_ID);
          defaultParamNames.add(ApiConstants.CTX_START_EVENT_ID);
          defaultParamNames.add(ApiConstants.CTX_USER_ID);
          defaultParamNames.add(ApiConstants.CTX_DETAILS);
          defaultParamNames.add(ApiConstants.UUID);
          defaultParamNames.add(ApiConstants.ID);
          defaultParamNames.add(ApiConstants.SIGNATURE_VERSION);
          defaultParamNames.add(ApiConstants.EXPIRES);
          defaultParamNames.add(ApiConstants.SCHEDULE_ID);
          defaultParamNames.add("_");
      }
  
      protected static final String ERROR_MSG_PREFIX = "Unknown parameters :";
  
      @SuppressWarnings("rawtypes")
      @Override
      public void handle(final DispatchTask task) {
          final BaseCmd cmd = task.getCmd();
          final Map params = task.getParams();
  
          final List<String> expectedParamNames = getParamNamesForCommand(cmd);
  
          final StringBuilder errorMsg = new StringBuilder(ERROR_MSG_PREFIX);
          boolean foundUnknownParam = false;
          for (final Object actualParamName : params.keySet()) {
              // If none of the expected params matches, we have an unknown param
              boolean matchedCurrentParam = false;
              for (final String expectedName : expectedParamNames) {
                  if (expectedName.equalsIgnoreCase((String) actualParamName)) {
                      matchedCurrentParam = true;
                      break;
                  }
              }
              if (!matchedCurrentParam && !((String)actualParamName).equalsIgnoreCase("expires") &&
                  !((String)actualParamName).equalsIgnoreCase("signatureversion") &&
                  !((String)actualParamName).equalsIgnoreCase("projectid")) {
                  errorMsg.append(" ").append(actualParamName);
                  foundUnknownParam= true;
              }
          }
  
          if (foundUnknownParam) {
              logger.warn(String.format("Received unknown parameters for command %s. %s", cmd.getActualCommandName(), errorMsg));
          }
      }
  
      protected List<String> getParamNamesForCommand(final BaseCmd cmd) {
          final List<String> paramNames = new ArrayList<String>();
          // The expected param names are all the specific for the current command class ...
          for (final Field field : cmd.getParamFields()) {
              final Parameter parameterAnnotation = field.getAnnotation(Parameter.class);
              paramNames.add(parameterAnnotation.name());
          }
          // ... plus the default ones
          paramNames.addAll(defaultParamNames);
          return paramNames;
      }
  }
  