All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.effektif.workflow.impl.json.MappingsBuilder Maven / Gradle / Ivy

/* Copyright (c) 2014, Effektif GmbH.
 * 
 * Licensed 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.effektif.workflow.impl.json;

import com.effektif.workflow.api.condition.Condition;
import com.effektif.workflow.api.model.RelativeTime;
import com.effektif.workflow.api.types.BooleanType;
import com.effektif.workflow.api.types.DataType;
import com.effektif.workflow.api.types.NumberType;
import com.effektif.workflow.api.types.TextType;
import com.effektif.workflow.api.workflow.Activity;
import com.effektif.workflow.api.workflow.Extensible;
import com.effektif.workflow.api.workflow.Timer;
import com.effektif.workflow.api.workflow.Trigger;
import com.effektif.workflow.impl.activity.AbstractTriggerImpl;
import com.effektif.workflow.impl.activity.ActivityType;
import com.effektif.workflow.impl.conditions.ConditionImpl;
import com.effektif.workflow.impl.data.DataTypeImpl;
import com.effektif.workflow.impl.job.JobType;
import com.effektif.workflow.impl.job.TimerType;
import com.effektif.workflow.impl.json.types.*;
import com.effektif.workflow.impl.workflow.boundary.BoundaryEventTimerImpl;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

/**
 * @author Tom Baeyens
 */
public class MappingsBuilder {
  
  Map baseClasses = new HashMap<>();
  List subClasses = new ArrayList<>();
  Set inlineFields = new HashSet<>();
  Set ignoredFields = new HashSet<>();
  Map fieldsMappings = new HashMap<>();
  Map fieldNames = new HashMap<>();
  List typeMapperFactories = new ArrayList<>();
  Map dataTypesByValueClass = new HashMap<>();
  
  public MappingsBuilder configureDefaults() {
    inline(Extensible.class, "properties");
    baseClass(Trigger.class);
    baseClass(JobType.class);
    subClasses(BoundaryEventTimerImpl.class); //todo: make this dynamic
    baseClass(Activity.class);
    baseClass(Condition.class);
    baseClass(DataType.class, "name");
    baseClass(RelativeTime.class);
    subClasses(RelativeTime.SUBCLASSES);
    baseClass(Timer.class);
    typeMapperFactory(new ValueMapper());
    typeMapperFactory(new StringMapper());
    typeMapperFactory(new BooleanMapper());
    typeMapperFactory(new ClassMapper());
    typeMapperFactory(new NumberMapperFactory());
    typeMapperFactory(new VariableMapperFactory());
    typeMapperFactory(new VariableInstanceMapperFactory());
    typeMapperFactory(new TypedValueMapperFactory());
    typeMapperFactory(new EnumMapperFactory());
    typeMapperFactory(new ArrayMapperFactory());
    typeMapperFactory(new CollectionMapperFactory());
    typeMapperFactory(new EnumSetMapperFactory());
    typeMapperFactory(new MapMapperFactory());
    typeMapperFactory(new BindingMapperFactory());
    loadPlugins();
    return this;
  }

  public MappingsBuilder baseClass(Class baseClass) {
    return baseClass(baseClass, "type");
  }

  public MappingsBuilder baseClass(Class baseClass, String typeField) {
    baseClasses.put(baseClass, typeField);
    return this;
  }

  public MappingsBuilder subClass(Class subClass) {
    subClasses.add(subClass);
    return this;
  }

  public MappingsBuilder subClasses(Class... subClasses) {
    if (subClasses!=null) {
      for (Class subClass: subClasses) {
        this.subClasses.add(subClass);
      }
    }
    return this;
  }

  public void removeSubClass(Class subClass) {
    subClasses.remove(subClass);
  }

  public MappingsBuilder inline(Class clazz, String fieldName) {
    inlineFields.add(getField(clazz, fieldName));
    return this;
  }

  public MappingsBuilder ignore(Class clazz, String fieldName) {
    ignoredFields.add(getField(clazz, fieldName));
    return this;
  }

  public MappingsBuilder fieldMapping(Class clazz, String fieldName, FieldMapping fieldMapping) {
    Field field = getField(clazz, fieldName);
    fieldsMappings.put(field, fieldMapping);
    return this;
  }

  public MappingsBuilder fieldMapper(Class clazz, String fieldName, JsonTypeMapper fieldMapper) {
    Field field = getField(clazz, fieldName);
    fieldsMappings.put(field, new FieldMapping(field, fieldMapper));
    return this;
  }

  public MappingsBuilder jsonFieldName(Class clazz, String fieldName, String jsonFieldName) {
    fieldNames.put(getField(clazz, fieldName), jsonFieldName);
    return this;
  }

  public MappingsBuilder typeMapperFactory(JsonTypeMapperFactory mapperFactory) {
    typeMapperFactories.add(mapperFactory);
    return this;
  }
  
  public MappingsBuilder loadPlugins() {
    ServiceLoader activityTypeLoader = ServiceLoader.load(ActivityType.class);
    for (ActivityType activityType: activityTypeLoader) {
      subClass(activityType.getActivityApiClass());
    }
    ServiceLoader conditionLoader = ServiceLoader.load(ConditionImpl.class);
    for (ConditionImpl condition: conditionLoader) {
      subClass(condition.getApiType());
    }
    ServiceLoader triggerLoader = ServiceLoader.load(AbstractTriggerImpl.class);
    for (AbstractTriggerImpl trigger: triggerLoader) {
        subClass(trigger.getTriggerApiClass());
    }
    ServiceLoader dataTypeLoader = ServiceLoader.load(DataTypeImpl.class);
    for (DataTypeImpl dataTypeImpl: dataTypeLoader) {
      try {
        Class apiClass = dataTypeImpl.getApiClass();
        if (apiClass!=null) {
          subClass(apiClass);
          DataType dataType = apiClass.newInstance();
          dataTypesByValueClass.put(dataType.getValueType(), dataType);
        }
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
    ServiceLoader timerTypeLoader = ServiceLoader.load(TimerType.class);
    for (TimerType timerType: timerTypeLoader) {
        subClass(timerType.getTimerApiClass());
    }
    // potentially multiple datatypes may map to eg String. 
    // by re-putting these datatypes, we ensure that these basic
    // data types are used when looking up a datatype by value
    dataTypesByValueClass.put(String.class, TextType.INSTANCE);
    dataTypesByValueClass.put(Boolean.class, BooleanType.INSTANCE);
    dataTypesByValueClass.put(Byte.class, NumberType.INSTANCE);
    dataTypesByValueClass.put(Short.class, NumberType.INSTANCE);
    dataTypesByValueClass.put(Integer.class, NumberType.INSTANCE);
    dataTypesByValueClass.put(Long.class, NumberType.INSTANCE);
    dataTypesByValueClass.put(Float.class, NumberType.INSTANCE);
    dataTypesByValueClass.put(Double.class, NumberType.INSTANCE);
    dataTypesByValueClass.put(BigInteger.class, NumberType.INSTANCE);
    dataTypesByValueClass.put(BigDecimal.class, NumberType.INSTANCE);
    return this;
  }
  
  public Mappings getMappings() {
    return new Mappings(this);
  }

  protected Field getField(Class clazz, String fieldName) {
    try {
      return clazz.getDeclaredField(fieldName);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy