| // 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); | |
| } | |
| } |