// 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.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ServerApiException; public class ParamUnpackWorker implements DispatchWorker { private static final Logger s_logger = Logger.getLogger(ParamUnpackWorker.class); @SuppressWarnings({"unchecked", "rawtypes"}) @Override public void handle(final DispatchTask task) throws ServerApiException { final Map<String, Object> lowercaseParams = new HashMap<String, Object>(); final Map<String, String> params = task.getParams(); for (final Map.Entry<String,String> entry : params.entrySet()) { final String key = entry.getKey(); final int arrayStartIndex = key.indexOf('['); final int arrayStartLastIndex = key.lastIndexOf('['); if (arrayStartIndex != arrayStartLastIndex) { throw new ServerApiException(ApiErrorCode.MALFORMED_PARAMETER_ERROR, "Unable to decode parameter " + key + "; if specifying an object array, please use parameter[index].field=XXX, e.g. userGroupList[0].group=httpGroup"); } if (arrayStartIndex > 0) { final int arrayEndIndex = key.indexOf(']'); final int arrayEndLastIndex = key.lastIndexOf(']'); if ((arrayEndIndex < arrayStartIndex) || (arrayEndIndex != arrayEndLastIndex)) { // malformed parameter throw new ServerApiException(ApiErrorCode.MALFORMED_PARAMETER_ERROR, "Unable to decode parameter " + key + "; if specifying an object array, please use parameter[index].field=XXX, e.g. userGroupList[0].group=httpGroup"); } // Now that we have an array object, check for a field name in the case of a complex object final int fieldIndex = key.indexOf('.'); String fieldName = null; if (fieldIndex < arrayEndIndex) { throw new ServerApiException(ApiErrorCode.MALFORMED_PARAMETER_ERROR, "Unable to decode parameter " + key + "; if specifying an object array, please use parameter[index].field=XXX, e.g. userGroupList[0].group=httpGroup"); } else { fieldName = key.substring(fieldIndex + 1); } // parse the parameter name as the text before the first '[' character String paramName = key.substring(0, arrayStartIndex); paramName = paramName.toLowerCase(); Map<Integer, Map> mapArray = null; Map<String, Object> mapValue = null; final String indexStr = key.substring(arrayStartIndex + 1, arrayEndIndex); int index = 0; boolean parsedIndex = false; try { if (indexStr != null) { index = Integer.parseInt(indexStr); parsedIndex = true; } } catch (final NumberFormatException nfe) { s_logger.warn("Invalid parameter " + key + " received, unable to parse object array, returning an error."); } if (!parsedIndex) { throw new ServerApiException(ApiErrorCode.MALFORMED_PARAMETER_ERROR, "Unable to decode parameter " + key + "; if specifying an object array, please use parameter[index].field=XXX, e.g. userGroupList[0].group=httpGroup"); } final Object value = lowercaseParams.get(paramName); if (value == null) { // for now, assume object array with sub fields mapArray = new HashMap<Integer, Map>(); mapValue = new HashMap<String, Object>(); mapArray.put(Integer.valueOf(index), mapValue); } else if (value instanceof Map) { mapArray = (HashMap)value; mapValue = mapArray.get(Integer.valueOf(index)); if (mapValue == null) { mapValue = new HashMap<String, Object>(); mapArray.put(Integer.valueOf(index), mapValue); } } // we are ready to store the value for a particular field into the map for this object mapValue.put(fieldName, entry.getValue()); lowercaseParams.put(paramName, mapArray); } else { lowercaseParams.put(key.toLowerCase(), entry.getValue()); } } // The chain continues processing the unpacked parameters task.setParams(lowercaseParams); } }