Package org.glassfish.common.util.admin

Source Code of org.glassfish.common.util.admin.MapInjectionResolver

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

package org.glassfish.common.util.admin;

import com.sun.enterprise.util.LocalStringManagerImpl;
import java.io.File;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.validation.Validator;
import org.glassfish.api.ExecutionContext;
import org.glassfish.api.Param;
import org.glassfish.api.ParamDefaultCalculator;
import org.glassfish.api.admin.CommandModel;
import org.glassfish.api.admin.ParameterMap;
import org.glassfish.hk2.api.MultiException;
import org.jvnet.hk2.component.MultiMap;
import org.jvnet.hk2.config.InjectionResolver;


/**
* An InjectionResolver that uses a ParameterMap object as the source of
* the data to inject.
*/
public class MapInjectionResolver extends InjectionResolver<Param> {
    private final CommandModel model;
    private final ParameterMap parameters;
    private ExecutionContext context = null;

    private final MultiMap<String,File> optionNameToUploadedFileMap;

    public static final LocalStringManagerImpl localStrings =
            new LocalStringManagerImpl(MapInjectionResolver.class);
    private static Validator beanValidator = null;

   
    public MapInjectionResolver(CommandModel model,
          ParameterMap parameters) {
        this(model, parameters, null);
    }
   
    public MapInjectionResolver(CommandModel model,
          ParameterMap parameters,
                                        final MultiMap<String,File> optionNameToUploadedFileMap) {
  super(Param.class);
  this.model = model;
  this.parameters = parameters;
        this.optionNameToUploadedFileMap = optionNameToUploadedFileMap;
    }

    /**
     * Set the context that is passed to the DynamicParamImpl.defaultValue method.
     */
    public void setContext(ExecutionContext context) {
        this.context = context;
    }
   
    @Override
    public boolean isOptional(AnnotatedElement element, Param annotation) {
       String name = CommandModel.getParamName(annotation, element);
       CommandModel.ParamModel param = model.getModelFor(name);
       return param.getParam().optional();
    }

    @Override
    public <V> V getValue(Object component, AnnotatedElement target, Type genericType, Class<V> type) throws MultiException {
  // look for the name in the list of parameters passed.
  Param param = target.getAnnotation(Param.class);
  String paramName = CommandModel.getParamName(param, target);
  if (param.primary()) {
      // this is the primary parameter for the command
      // XXX - for now, only handle multiple values for primary
      List<String> value = parameters.get("DEFAULT");
      if (value != null && value.size() > 0) {
                /*
                 * If the operands are uploaded files, replace the
                 * client-provided values with the paths to the uploaded files.
                 * XXX - assume the lists are in the same order.
                 */
                final List<String> filePaths = getUploadedFileParamValues(
                        "DEFAULT",
                        type, optionNameToUploadedFileMap);
                if (filePaths != null) {
                    value = filePaths;
                    // replace the file name operands with the uploaded files
                    parameters.set("DEFAULT", value);
                } else {
                    for (String s : value) {
                        checkAgainstAcceptableValues(target, s);
                    }
                   
                }
    // let's also copy this value to the cmd with a real name
    parameters.set(paramName, value);
                V paramValue = (V) convertListToObject(target, type, value);
                return paramValue;
      }
  }
  String paramValueStr = getParamValueString(parameters, param, target, context);

        /*
         * If the parameter is an uploaded file, replace the client-provided
         * value with the path to the uploaded file.
         */
        final String fileParamValueStr = getUploadedFileParamValue(
                paramName, type, optionNameToUploadedFileMap);
        if (fileParamValueStr != null) {
            paramValueStr = fileParamValueStr;
            parameters.set(paramName, paramValueStr);
        }
  checkAgainstAcceptableValues(target, paramValueStr);
       
        return paramValueStr != null ?
                (V) convertStringToObject(target, type, paramValueStr) :
                (V) getParamField(component, target);
    }

    /**
     * Returns the path to the uploaded file if the specified field is of type
     * File and if the field name is the same as one of the option names that
     * was associated with an uploaded File in the incoming command request.
     *
     * @param fieldName name of the field being injected
     * @param fieldType type of the field being injected
     * @param optionNameToFileMap map of field names to uploaded Files
     * @return absolute path of the uploaded file for the field;
     *          null if no file uploaded for this field
     */
    public static String getUploadedFileParamValue(final String fieldName,
                final Class fieldType,
                final MultiMap<String,File> optionNameToFileMap) {
        if (optionNameToFileMap == null) {
            return null;
        }
        final File uploadedFile = optionNameToFileMap.getOne(fieldName);
        if (uploadedFile != null && fieldType.isAssignableFrom(File.class)) {
            return uploadedFile.getAbsolutePath();
        } else {
            return null;
        }
    }

    /**
     * Returns the paths to the uploaded files if the specified field is of type
     * File[] and if the field name is the same as one of the option names that
     * was associated with an uploaded File in the incoming command request.
     *
     * @param fieldName name of the field being injected
     * @param fieldType type of the field being injected
     * @param optionNameToFileMap map of field names to uploaded Files
     * @return List of absolute paths of the uploaded files for the field;
     *          null if no file uploaded for this field
     */
    public static List<String> getUploadedFileParamValues(
                final String fieldName,
                final Class fieldType,
                final MultiMap<String,File> optionNameToFileMap) {
        if (optionNameToFileMap == null) {
            return null;
        }
        final List<File> uploadedFiles = optionNameToFileMap.get(fieldName);
        if (uploadedFiles != null && uploadedFiles.size() > 0 &&
                (fieldType.isAssignableFrom(File.class) ||
                 fieldType.isAssignableFrom(File[].class))) {
            final List<String> paths = new ArrayList(uploadedFiles.size());
            for (File f : uploadedFiles)
                paths.add(f.getAbsolutePath());
            return paths;
        } else {
            return null;
        }
    }

    /**
     * Get the param value.  Checks if the param (option) value
     * is defined on the command line (URL passed by the client)
     * by calling getParameterValue method.  If not, then check
     * for the shortName.  If param value is not given by the
     * shortName (short option) then if the default value is
     * defined return it.
     *
     * @param parameters parameters from the command line.
     * @param param from the annotated Param
     * @param target annotated element
     * @return param value
     */
    // package-private, for testing
    static String getParamValueString(final ParameterMap parameters,
                               final Param param,
                               final AnnotatedElement target,
                               final ExecutionContext context) {
        String paramValueStr = getParameterValue(parameters,
                                      CommandModel.getParamName(param, target),
                                      true);
        if (paramValueStr == null && param.alias().length() > 0) {
            // check for alias
            paramValueStr = getParameterValue(parameters, param.alias(), true);
        }
        if (paramValueStr == null) {
            // check for shortName
            paramValueStr = parameters.getOne(param.shortName());
        }
       
        // if paramValueStr is still null, then check to
        // see if the defaultValue is defined
        if (paramValueStr == null) {
            final String defaultValue = param.defaultValue();
            paramValueStr = defaultValue.equals("") ? null : defaultValue;
        }
        // if paramValueStr is still null, then check to see if a defaultCalculator
        // is defined, and if so, call the class to get the default value
        if (paramValueStr == null) {
            Class<? extends ParamDefaultCalculator> dc = param.defaultCalculator();
            if (dc != ParamDefaultCalculator.class) {
                try {
                    ParamDefaultCalculator pdc = dc.newInstance();
                    paramValueStr = pdc.defaultValue(context);
                } catch (InstantiationException ex) { // @todo Java SE 7 - use multi catch
                    Logger.getLogger(MapInjectionResolver.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(MapInjectionResolver.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return paramValueStr;
    }

    /**
     * Get the value of the field.  This value is defined in the
     * annotated Param declaration.  For example:
     * <code>
     * @Param(optional=true)
     * String name="server"
     * </code>
     * The Field, name's value, "server" is returned.
     *
     * @param component command class object
     * @param annotated annotated element
     * @return the annotated Field value
     */
    // package-private, for testing
    static Object getParamField(final Object component,
                         final AnnotatedElement annotated) {
        try {
            if (annotated instanceof Field) {
                final Field field = (Field)annotated;
                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    @Override
                    public Object run() {
                        field.setAccessible(true);
                        return null;
                    }
                });
                return ((Field) annotated).get(component);
            }
        } catch (Exception e) {
            // unable to get the field value, may not be defined
            // return null instead.
            return null;
        }
        return null;
    }

    /**
     * Searches for the parameter with the specified key in this parameter map.
     * The method returns null if the parameter is not found.
     *
     * @param params the parameter map to search in
     * @param key the property key
     * @param ignoreCase true to search the key ignoring case,
     *                   false otherwise
     * @return the value in this parameter map with the specified key value
     */
    // package-private, for testing
    static String getParameterValue(final ParameterMap params,
                            String key, final boolean ignoreCase) {
        if (ignoreCase) {
            for (Map.Entry<String,List<String>> entry : params.entrySet()) {
                final String paramName = entry.getKey();
                if (paramName.equalsIgnoreCase(key)) {
                    key = paramName;
                    break;
                }
            }
        }
        return params.getOne(key);
    }

    /**
     * Convert the String parameter to the specified type.
     * For example if type is Properties and the String
     * value is: name1=value1:name2=value2:...
     * then this api will convert the String to a Properties
     * class with the values {name1=name2, name2=value2, ...}
     *
     * @param target the target field
     * @param type the type of class to convert
     * @param paramValStr the String value to convert
     * @return Object
     */
    // package-private, for testing
    static Object convertStringToObject(AnnotatedElement target,
                                    Class type, String paramValStr) {
        Param param = target.getAnnotation(Param.class);
        Object paramValue = paramValStr;
        if (type.isAssignableFrom(String.class)) {
            paramValue = paramValStr;
        } else if (type.isAssignableFrom(Properties.class)) {
            paramValue =
                convertStringToProperties(paramValStr, param.separator());
        } else if (type.isAssignableFrom(List.class)) {
            paramValue = convertStringToList(paramValStr, param.separator());
        } else if (type.isAssignableFrom(Boolean.class) ||
                    type.isAssignableFrom(boolean.class)) {
            String paramName = CommandModel.getParamName(param, target);
            paramValue = convertStringToBoolean(paramName, paramValStr);
        } else if (type.isAssignableFrom(Integer.class) ||
                    type.isAssignableFrom(int.class)) {
            String paramName = CommandModel.getParamName(param, target);
            paramValue = convertStringToInteger(paramName, paramValStr);
        } else if (type.isAssignableFrom(String[].class)) {
            paramValue =
                convertStringToStringArray(paramValStr, param.separator());
        } else if (type.isAssignableFrom(File.class)) {
            return new File(paramValStr);
        }
        return paramValue;
    }

    /**
     * Convert the List<String> parameter to the specified type.
     *
     * @param target the target field
     * @param type the type of class to convert
     * @param paramValList the List of String values to convert
     * @return Object
     */
    // package-private, for testing
    static Object convertListToObject(AnnotatedElement target,
                                    Class type, List<String> paramValList) {
        Param param = target.getAnnotation(Param.class);
        // does this parameter type allow multiple values?
        if (!param.multiple()) {
            if (paramValList.size() == 1)
                return convertStringToObject(target, type, paramValList.get(0));
            throw new UnacceptableValueException(
                localStrings.getLocalString("TooManyValues",
                    "Invalid parameter: {0}.  This parameter may not have " +
                    "more than one value.",
                    CommandModel.getParamName(param, target)));
        }

        Object paramValue = paramValList;
        if (type.isAssignableFrom(List.class)) {
            // the default case, nothing to do
        } else if (type.isAssignableFrom(String[].class)) {
            paramValue = paramValList.toArray(new String[paramValList.size()]);
        } else if (type.isAssignableFrom(File[].class)) {
            paramValue = convertListToFiles(paramValList);
        } else if (type.isAssignableFrom(Properties.class)) {
            paramValue = convertListToProperties(paramValList);
        }
        // XXX - could handle arrays of other types
        return paramValue;
    }

    /**
     * Convert a String to a Boolean.
     * null --> true
     * "" --> true
     * case insensitive "true" --> true
     * case insensitive "false" --> false
     * anything else --> throw Exception
     *
     * @param paramName the name of the param
     * @param s the String to convert
     * @return Boolean
     */
    private static Boolean convertStringToBoolean(String paramName, String s) {
        if (!ok(s))
            return Boolean.TRUE;

        if (s.equalsIgnoreCase(Boolean.TRUE.toString()))
            return Boolean.TRUE;

        if (s.equalsIgnoreCase(Boolean.FALSE.toString()))
            return Boolean.FALSE;

        String msg = localStrings.getLocalString("UnacceptableBooleanValue",
                "Invalid parameter: {0}.  This boolean option must be set " +
                    "(case insensitive) to true or false.  " +
                    "Its value was set to {1}",
                paramName, s);

        throw new UnacceptableValueException(msg);
    }

    /**
     * Convert a String to an Integer.
     *
     * @param paramName the name of the param
     * @param s the String to convert
     * @return Integer
     */
    private static Integer convertStringToInteger(String paramName, String s) {
        try {
            return new Integer(s);
        } catch (Exception ex) {
            String msg = localStrings.getLocalString("UnacceptableIntegerValue",
                "Invalid parameter: {0}.  This integer option must be set " +
                    "to a valid integer.\nIts value was set to {1}",
                    paramName, s);
            throw new UnacceptableValueException(msg);
        }
    }

    /**
     * Convert a String with the following format to Properties:
     * name1=value1:name2=value2:name3=value3:...
     * The Properties object contains elements:
     * {name1=value1, name2=value2, name3=value3, ...}
     *
     * @param propsString the String to convert
     * @param sep the separator character
     * @return Properties containing the elements in String
     */
    // package-private, for testing
    static Properties convertStringToProperties(String propsString, char sep) {
        final Properties properties = new Properties();
        if (propsString != null) {
            ParamTokenizer stoken = new ParamTokenizer(propsString, sep);
            while (stoken.hasMoreTokens()) {
                String token = stoken.nextTokenKeepEscapes();
                final ParamTokenizer nameTok = new ParamTokenizer(token, '=');
                String name = null, value = null;
                if (nameTok.hasMoreTokens())
                    name = nameTok.nextToken();
                if (nameTok.hasMoreTokens())
                    value = nameTok.nextToken();
                if (name == null)       // probably "::"
                    throw new IllegalArgumentException(
                        localStrings.getLocalString("PropertyMissingName",
                        "Invalid property syntax, missing property name",
                        propsString));
                if (value == null)
                    throw new IllegalArgumentException(
                        localStrings.getLocalString("PropertyMissingValue",
                        "Invalid property syntax, missing property value",
                        token));
                if (nameTok.hasMoreTokens())
                    throw new IllegalArgumentException(
                        localStrings.getLocalString("PropertyExtraEquals",
                        "Invalid property syntax, \"=\" in value", token));
                properties.setProperty(name, value);
            }
        }
        return properties;
    }

    /**
     * Convert a List of Strings to an array of File objects.
     *
     * @param filesList the List of Strings to convert
     * @return File[] containing the elements in the list
     */
    private static File[] convertListToFiles(List<String> filesList) {
        final File[] files = new File[filesList.size()];
        for (int i = 0; i < filesList.size(); i++)
            files[i] = new File(filesList.get(i));
        return files;
    }

    /**
     * Convert a List of Strings, each with the following format, to Properties:
     * name1=value1
     *
     * @param propsList the List of Strings to convert
     * @return Properties containing the elements in the list
     */
    private static Properties convertListToProperties(List<String> propsList) {
        final Properties properties = new Properties();
        if (propsList != null) {
            for (String prop : propsList) {
                final ParamTokenizer nameTok = new ParamTokenizer(prop, '=');
                String name = null, value = null;
                if (nameTok.hasMoreTokens())
                    name = nameTok.nextToken();
                if (nameTok.hasMoreTokens())
                    value = nameTok.nextToken();
                if (nameTok.hasMoreTokens() || name == null || value == null)
                    throw new IllegalArgumentException(
                        localStrings.getLocalString("InvalidPropertySyntax",
                            "Invalid property syntax.", prop));
                properties.setProperty(name, value);
            }
        }
        return properties;
    }

    /**
     * Convert a String with the following format to List<String>:
     * string1:string2:string3:...
     * The List object contains elements: string1, string2, string3, ...
     *
     * @param listString - the String to convert
     * @param sep the separator character
     * @return List containing the elements in String
     */
    // package-private, for testing
    static List<String> convertStringToList(String listString, char sep) {
        List<String> list = new java.util.ArrayList();
        if (listString != null) {
            final ParamTokenizer ptoken = new ParamTokenizer(listString, sep);
            while (ptoken.hasMoreTokens()) {
                String token = ptoken.nextToken();
                list.add(token);
            }
        }
        return list;
    }

    /**
     * convert a String with the following format to String Array:
     * string1,string2,string3,...
     * The String Array contains: string1, string2, string3, ...
     *
     * @param arrayString - the String to convert
     * @param sep the separator character
     * @return String[] containing the elements in String
     */
    // package-private, for testing
    static String[] convertStringToStringArray(String arrayString, char sep) {
        final ParamTokenizer paramTok = new ParamTokenizer(arrayString, sep);
        List<String> strs = new ArrayList<String>();
        while (paramTok.hasMoreTokens())
            strs.add(paramTok.nextToken());
        return strs.toArray(new String[strs.size()]);
    }

    /**
     * Check if the value string is one of the strings in the list of
     * acceptable values in the @Param annotation on the target.
     *
     * @param target the target field
     * @param paramValueStr the parameter value
     */
    private static void checkAgainstAcceptableValues(AnnotatedElement target,
                                                    String paramValueStr) {
        Param param = target.getAnnotation(Param.class);
        String acceptable = param.acceptableValues();
        String paramName = CommandModel.getParamName(param, target);

        if (ok(acceptable) && ok(paramValueStr)) {
            String[] ss = acceptable.split(",");

            for (String s : ss) {
                if (paramValueStr.equals(s.trim()))
                    return;     // matched, value is good
            }

            // didn't match any, error
            throw new UnacceptableValueException(
                localStrings.getLocalString("UnacceptableValue",
                    "Invalid parameter: {0}.  Its value is {1} " +
                        "but it isn''t one of these acceptable values: {2}",
                    paramName,
                    paramValueStr,
                    acceptable));
        }
    }

    private static boolean ok(String s) {
        return s != null && s.length() > 0;
    }
}
TOP

Related Classes of org.glassfish.common.util.admin.MapInjectionResolver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.