Package org.apache.sqoop.model

Source Code of org.apache.sqoop.model.FormUtils

/**
* 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 org.apache.sqoop.model;

import org.apache.sqoop.common.SqoopException;
import org.apache.sqoop.utils.ClassUtils;
import org.apache.sqoop.validation.Status;
import org.apache.sqoop.validation.Validation;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
* Util class for transforming data from correctly annotated configuration
* objects to different structures and vice-versa.
*/
public class FormUtils {

  /**
   * Transform correctly annotated configuration object to corresponding
   * list of forms.
   *
   * Forms will be order according to the occurrence in the configuration
   * class. Inputs will be also ordered based on occurrence.
   *
   * @param configuration Annotated arbitrary configuration object
   * @return Corresponding list of forms
   */
  public static List<MForm> toForms(Object configuration) {
    return toForms(configuration.getClass(), configuration);
  }

  public static List<MForm> toForms(Class klass) {
    return toForms(klass, null);
  }

  @SuppressWarnings("unchecked")
  public static List<MForm> toForms(Class klass, Object configuration) {
    ConfigurationClass global =
      (ConfigurationClass)klass.getAnnotation(ConfigurationClass.class);

    // Each configuration object must have this class annotation
    if(global == null) {
      throw new SqoopException(ModelError.MODEL_003,
        "Missing annotation ConfigurationClass on class " + klass.getName());
    }

    List<MForm> forms = new LinkedList<MForm>();

    // Iterate over all declared fields
    for (Field field : klass.getDeclaredFields()) {
      field.setAccessible(true);

      String formName = field.getName();

      // Each field that should be part of user input should have Input
      // annotation.
      Form formAnnotation = field.getAnnotation(Form.class);

      if(formAnnotation != null) {
        Class type = field.getType();

        Object value = null;
        if(configuration != null) {
          try {
            value = field.get(configuration);
          } catch (IllegalAccessException e) {
            throw new SqoopException(ModelError.MODEL_005,
              "Can't retrieve value from " + field.getName(), e);
          }
        }

        forms.add(toForm(formName, type, value));
      }
    }

    return forms;
  }

  @SuppressWarnings("unchecked")
  private static MForm toForm(String formName, Class klass, Object object) {
     FormClass global =
      (FormClass)klass.getAnnotation(FormClass.class);

    // Each configuration object must have this class annotation
    if(global == null) {
      throw new SqoopException(ModelError.MODEL_003,
        "Missing annotation FormClass on class " + klass.getName());
    }

    // Intermediate list of inputs
    List<MInput<?>> inputs = new LinkedList<MInput<?>>();

    // Iterate over all declared fields
    for (Field field : klass.getDeclaredFields()) {
      field.setAccessible(true);

      String fieldName = field.getName();
      String inputName = formName + "." + fieldName;

      // Each field that should be part of user input should have Input
      // annotation.
      Input inputAnnotation = field.getAnnotation(Input.class);

      if(inputAnnotation != null) {
        boolean sensitive = inputAnnotation.sensitive();
        short maxLen = inputAnnotation.size();
        Class type = field.getType();

        MInput input;

        // We need to support NULL, so we do not support primitive types
        if(type.isPrimitive()) {
          throw new SqoopException(ModelError.MODEL_007,
            "Detected primitive type " + type + " for field " + fieldName);
        }

        // Instantiate corresponding MInput<?> structure
        if(type == String.class) {
          input = new MStringInput(inputName, sensitive, maxLen);
        } else if (type.isAssignableFrom(Map.class)) {
          input = new MMapInput(inputName, sensitive);
        } else if(type == Integer.class) {
          input = new MIntegerInput(inputName, sensitive);
        } else if(type.isEnum()) {
          input = new MEnumInput(inputName, sensitive, ClassUtils.getEnumStrings(type));
        } else {
          throw new SqoopException(ModelError.MODEL_004,
            "Unsupported type " + type.getName() + " for input " + fieldName);
        }

        // Move value if it's present in original configuration object
        if(object != null) {
          Object value;
          try {
            value = field.get(object);
          } catch (IllegalAccessException e) {
            throw new SqoopException(ModelError.MODEL_005,
              "Can't retrieve value from " + field.getName(), e);
          }
          if(value == null) {
            input.setEmpty();
          } else {
            input.setValue(value);
          }
        }

        inputs.add(input);
      }
    }

    return new MForm(formName, inputs);
  }

  /**
   * Move form values from form list into corresponding configuration object.
   *
   * @param forms Input form list
   * @param configuration Output configuration object
   */
  public static void fromForms(List<MForm> forms, Object configuration) {
    Class klass = configuration.getClass();

    for(MForm form : forms) {
      Field formField;
      try {
        formField = klass.getDeclaredField(form.getName());
      } catch (NoSuchFieldException e) {
        throw new SqoopException(ModelError.MODEL_006,
          "Missing field " + form.getName() + " on form class " + klass.getCanonicalName(), e);
      }

      // We need to access this field even if it would be declared as private
      formField.setAccessible(true);

      Class formClass = formField.getType();
      Object newValue = ClassUtils.instantiate(formClass);

      if(newValue == null) {
        throw new SqoopException(ModelError.MODEL_006,
          "Can't instantiate new form " + formClass);
      }

      for(MInput input : form.getInputs()) {
        String[] splitNames = input.getName().split("\\.");
        if(splitNames.length != 2) {
          throw new SqoopException(ModelError.MODEL_009,
            "Invalid name: " + input.getName());
        }

        String inputName = splitNames[1];
        // TODO(jarcec): Names structures fix, handle error cases
        Field inputField;
        try {
          inputField = formClass.getDeclaredField(inputName);
        } catch (NoSuchFieldException e) {
          throw new SqoopException(ModelError.MODEL_006,
            "Missing field " + input.getName(), e);
        }

        // We need to access this field even if it would be declared as private
        inputField.setAccessible(true);

        try {
          if(input.isEmpty()) {
            inputField.set(newValue, null);
          } else {
            if (input.getType() == MInputType.ENUM) {
              inputField.set(newValue, Enum.valueOf((Class<? extends Enum>)inputField.getType(), (String) input.getValue()));
            } else {
              inputField.set(newValue, input.getValue());
            }
          }
        } catch (IllegalAccessException e) {
          throw new SqoopException(ModelError.MODEL_005,
            "Issue with field " + inputField.getName(), e);
        }
      }

      try {
        formField.set(configuration, newValue);
      } catch (IllegalAccessException e) {
        throw new SqoopException(ModelError.MODEL_005,
          "Issue with field " + formField.getName(), e);
      }
    }
  }

  /**
   * Apply validations on the forms.
   *
   * @param forms Forms that should be updated
   * @param validation Validation that we should apply
   */
  public static void applyValidation(List<MForm> forms, Validation validation) {
    Map<Validation.FormInput, Validation.Message> messages = validation.getMessages();

    for(MForm form : forms) {
      applyValidation(form, messages);

      for(MInput input : form.getInputs()) {
        applyValidation(input, messages);
      }
    }
  }

  /**
   * Apply validation on given validated element.
   *
   * @param element Element on what we're applying the validations
   * @param messages Map of all validation messages
   */
  public static void applyValidation(MValidatedElement element, Map<Validation.FormInput, Validation.Message> messages) {
    Validation.FormInput name = new Validation.FormInput(element.getName());

    if(messages.containsKey(name)) {
      Validation.Message message = messages.get(name);
      element.setValidationMessage(message.getStatus(), message.getMessage());
    } else {
      element.setValidationMessage(Status.getDefault(), null);
    }
  }

  /**
   * Convert configuration object to JSON. Only filled properties are serialized,
   * properties with null value are skipped.
   *
   * @param configuration Correctly annotated configuration object
   * @return String of JSON representation
   */
  @SuppressWarnings("unchecked")
  public static String toJson(Object configuration) {
    Class klass = configuration.getClass();

    ConfigurationClass global =
      (ConfigurationClass)klass.getAnnotation(ConfigurationClass.class);

    // Each configuration object must have this class annotation
    if(global == null) {
      throw new SqoopException(ModelError.MODEL_003,
        "Missing annotation Configuration on class " + klass.getName());
    }

    JSONObject jsonOutput = new JSONObject();

    // Iterate over all declared fields
    for (Field formField : klass.getDeclaredFields()) {
      formField.setAccessible(true);
      String formName = formField.getName();

      // We're processing only form validations
      Form formAnnotation = formField.getAnnotation(Form.class);
      if(formAnnotation == null) {
        continue;
      }

      Object formValue;
      try {
        formValue = formField.get(configuration);
      } catch (IllegalAccessException e) {
        throw new SqoopException(ModelError.MODEL_005,
          "Issue with field " + formName, e);
      }

      JSONObject jsonForm = new JSONObject();

      // Now process each input on the form
      for(Field inputField : formField.getType().getDeclaredFields()) {
        inputField.setAccessible(true);
        String inputName = inputField.getName();

        Object value;
        try {
          value = inputField.get(formValue);
        } catch (IllegalAccessException e) {
          throw new SqoopException(ModelError.MODEL_005,
            "Issue with field " + formName + "." + inputName, e);
        }

        Input inputAnnotation = inputField.getAnnotation(Input.class);

        // Do not serialize all values
        if(inputAnnotation != null && value != null) {
          Class type = inputField.getType();

          // We need to support NULL, so we do not support primitive types
          if(type.isPrimitive()) {
            throw new SqoopException(ModelError.MODEL_007,
              "Detected primitive type " + type + " for field " + formName + "." + inputName);
          }

          if(type == String.class) {
            jsonForm.put(inputName, value);
          } else if (type.isAssignableFrom(Map.class)) {
            JSONObject map = new JSONObject();
            for(Object key : ((Map)value).keySet()) {
              map.put(key, ((Map)value).get(key));
            }
            jsonForm.put(inputName, map);
          } else if(type == Integer.class) {
            jsonForm.put(inputName, value);
          } else if(type.isEnum()) {
            jsonForm.put(inputName, value.toString());
          } else {
            throw new SqoopException(ModelError.MODEL_004,
              "Unsupported type " + type.getName() + " for input " + formName + "." + inputName);
          }
        }
      }

      jsonOutput.put(formName, jsonForm);
    }

    return jsonOutput.toJSONString();
  }

  /**
   * Parse given input JSON string and move it's values to given configuration
   * object.
   *
   * @param json JSON representation of the configuration object
   * @param configuration Configuration object to be filled
   */
  public static void fillValues(String json, Object configuration) {
    Class klass = configuration.getClass();

    JSONObject jsonForms = (JSONObject) JSONValue.parse(json);

    for(Field formField : klass.getDeclaredFields()) {
      formField.setAccessible(true);
      String formName = formField.getName();

      // We're processing only form validations
      Form formAnnotation = formField.getAnnotation(Form.class);
      if(formAnnotation == null) {
        continue;
      }

      try {
        formField.set(configuration, formField.getType().newInstance());
      } catch (Exception e) {
        throw new SqoopException(ModelError.MODEL_005,
          "Issue with field " + formName, e);
      }

      JSONObject jsonInputs = (JSONObject) jsonForms.get(formField.getName());
      if(jsonInputs == null) {
        continue;
      }

      Object formValue;
      try {
        formValue = formField.get(configuration);
      } catch (IllegalAccessException e) {
        throw new SqoopException(ModelError.MODEL_005,
          "Issue with field " + formName, e);
      }

      for(Field inputField : formField.getType().getDeclaredFields()) {
        inputField.setAccessible(true);
        String inputName = inputField.getName();

        Input inputAnnotation = inputField.getAnnotation(Input.class);

        if(inputAnnotation == null || jsonInputs.get(inputName) == null) {
          try {
            inputField.set(formValue, null);
          } catch (IllegalAccessException e) {
            throw new SqoopException(ModelError.MODEL_005,
              "Issue with field " + formName + "." + inputName, e);
          }
          continue;
        }

        Class type = inputField.getType();

        try {
          if(type == String.class) {
            inputField.set(formValue, jsonInputs.get(inputName));
          } else if (type.isAssignableFrom(Map.class)) {
            Map<String, String> map = new HashMap<String, String>();
            JSONObject jsonObject = (JSONObject) jsonInputs.get(inputName);
            for(Object key : jsonObject.keySet()) {
              map.put((String)key, (String)jsonObject.get(key));
            }
            inputField.set(formValue, map);
          } else if(type == Integer.class) {
            inputField.set(formValue, ((Long)jsonInputs.get(inputName)).intValue());
          } else if(type.isEnum()) {
            inputField.set(formValue, Enum.valueOf((Class<? extends Enum>) inputField.getType(), (String) jsonInputs.get(inputName)));
          } else {
            throw new SqoopException(ModelError.MODEL_004,
              "Unsupported type " + type.getName() + " for input " + formName + "." + inputName);
          }
        } catch (IllegalAccessException e) {
          throw new SqoopException(ModelError.MODEL_005,
            "Issue with field " + formName + "." + inputName, e);
        }
      }
    }
  }

}
TOP

Related Classes of org.apache.sqoop.model.FormUtils

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.