/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* 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 org.kie.workbench.common.forms.dynamic.backend.server.context.generation.statik.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.drools.workbench.models.datamodel.oracle.Annotation;
import org.drools.workbench.models.datamodel.oracle.DataType;
import org.drools.workbench.models.datamodel.oracle.ModelField;
import org.kie.workbench.common.forms.commons.layout.Dynamic;
import org.kie.workbench.common.forms.commons.layout.FormLayoutTemplateGenerator;
import org.kie.workbench.common.forms.dynamic.backend.server.context.generation.statik.impl.fieldInitializers.FieldInitializer;
import org.kie.workbench.common.forms.dynamic.backend.server.context.generation.statik.impl.fieldInitializers.FormAwareFieldInitializer;
import org.kie.workbench.common.forms.dynamic.backend.server.context.generation.statik.impl.processors.FieldAnnotationProcessor;
import org.kie.workbench.common.forms.dynamic.service.context.generation.FormRenderingContextGenerator;
import org.kie.workbench.common.forms.dynamic.service.shared.DynamicContext;
import org.kie.workbench.common.forms.dynamic.service.shared.StaticContext;
import org.kie.workbench.common.forms.dynamic.service.shared.impl.StaticModelFormRenderingContext;
import org.kie.workbench.common.forms.metaModel.FieldDef;
import org.kie.workbench.common.forms.model.FieldDataType;
import org.kie.workbench.common.forms.model.FieldDefinition;
import org.kie.workbench.common.forms.model.FormDefinition;
import org.kie.workbench.common.forms.service.FieldManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@StaticContext
@DynamicContext
@Dependent
public class FormRenderingContextGeneratorImpl implements FormRenderingContextGenerator<DMOBasedTransformerContext, StaticModelFormRenderingContext> {
private static final Logger logger = LoggerFactory.getLogger(FormRenderingContextGeneratorImpl.class);
private FieldManager fieldManager;
private FormLayoutTemplateGenerator layoutGenerator;
private List<FieldAnnotationProcessor> processors = new ArrayList<>();
private List<FieldInitializer<? extends FieldDefinition>> fieldInitializers = new ArrayList<>();
@Inject
public FormRenderingContextGeneratorImpl(Instance<FieldAnnotationProcessor<? extends FieldDefinition>> installedProcessors,
Instance<FieldInitializer<? extends FieldDefinition>> installedInitializers,
@Dynamic FormLayoutTemplateGenerator layoutGenerator,
FieldManager fieldManager) {
this.layoutGenerator = layoutGenerator;
this.fieldManager = fieldManager;
for (FieldAnnotationProcessor processor : installedProcessors) {
processors.add(processor);
}
for (FieldInitializer initializer : installedInitializers) {
if (initializer instanceof FormAwareFieldInitializer) {
((FormAwareFieldInitializer) initializer).setTransformerService(this);
}
fieldInitializers.add(initializer);
}
}
@Override
public StaticModelFormRenderingContext createContext(Object model) {
try {
DMOBasedTransformerContext context = DMOBasedTransformerContext.getTransformerContextFor(model);
FormDefinition form = generateFormDefinition(context);
context.getRenderingContext().setRootForm(form);
return context.getRenderingContext();
} catch (IOException e) {
logger.warn("Error creating context: ",
e);
}
return null;
}
public FormDefinition generateFormDefinition(DMOBasedTransformerContext context) {
FormDefinition form = new FormDefinition();
final String modelType = context.getType();
form.setId(modelType);
Set<FieldSetting> settings = getClassFieldSettings(modelType,
context);
for (FieldSetting setting : settings) {
FieldDefinition field = null;
for (Annotation annotation : setting.getAnnotations()) {
for (FieldAnnotationProcessor processor : processors) {
if (processor.supportsAnnotation(annotation)) {
field = processor.getFieldDefinition(setting,
annotation,
context);
}
}
}
if (field == null) {
field = fieldManager.getDefinitionByDataType(setting.getTypeInfo());
if (field != null) {
field.setId(setting.getFieldName());
field.setName(setting.getFieldName());
field.setLabel(setting.getLabel());
String binding = setting.getFieldName();
if (!StringUtils.isEmpty(setting.getProperty())) {
binding += "." + setting.getProperty();
}
field.setBinding(binding);
}
}
if (field == null) {
continue;
}
for (FieldInitializer initializer : fieldInitializers) {
if (initializer.supports(field)) {
initializer.initializeField(field,
setting,
context);
}
}
form.getFields().add(field);
}
layoutGenerator.generateLayoutTemplate(form);
return form;
}
@Override
public FormDefinition generateFormDefinitionForType(String type,
DMOBasedTransformerContext context) {
if (!context.getType().equals(type)) {
context = context.copyFor(type);
}
return generateFormDefinition(context);
}
protected Set<FieldSetting> getClassFieldSettings(String modelType,
DMOBasedTransformerContext context) {
TreeSet<FieldSetting> settings = new TreeSet<FieldSetting>();
ModelField[] modelFields = context.getOracle().getProjectModelFields().get(modelType);
for (ModelField modelField : modelFields) {
final String fieldName = modelField.getName();
if (fieldName.equals("this")) {
continue;
}
Set<Annotation> annotations = context.getOracle().getProjectTypeFieldsAnnotations().get(modelType).get(fieldName);
if (annotations == null || annotations.isEmpty()) {
continue;
}
for (Annotation annotation : annotations) {
if (annotation.getQualifiedTypeName().equals(FieldDef.class.getName())) {
String fieldModelType = modelType;
String fieldClassName = modelField.getClassName();
boolean isEnunm = context.getOracle().getProjectJavaEnumDefinitions().get(modelType + "#" + modelField.getName()) != null;
// here we store final field we want to generate the Form Field for.
ModelField finalModelField = modelField;
// If field is collection check for the generic type
if (isCollection(modelField)) {
fieldModelType = modelType;
} else {
String property = annotation.getParameters().get("property").toString();
/*
if the annotation has property let's get the nested field and overwrite the finalField value
in order to generate a Form Field with the right type.
*/
if (property != null && !property.isEmpty()) {
ModelField[] fields = context.getOracle().getProjectModelFields().get(fieldClassName);
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(property)) {
finalModelField = fields[i];
// check if the nested value is an Enum
isEnunm = context.getOracle().getProjectJavaEnumDefinitions().get(fieldClassName + "#" + property) != null;
/*
if field isn't a collection let's get the real className, if it is a collection
we'll use the type to get the generic type later.
*/
if (!isCollection(finalModelField)) {
fieldClassName = finalModelField.getClassName();
} else {
fieldModelType = fieldClassName;
}
}
}
}
}
boolean isCollection = isCollection(finalModelField);
if (isCollection) {
// if field is a collection let's get the generic type of it.
fieldClassName = context.getOracle().getProjectFieldParametersType().get(fieldModelType + "#" + finalModelField.getName());
}
if (fieldClassName != null) {
FieldSetting setting = new FieldSetting(fieldName,
new FieldDataType(fieldClassName,
isCollection,
isEnunm),
annotation,
annotations);
settings.add(setting);
}
}
}
}
return settings;
}
private boolean isCollection(ModelField modelField) {
return DataType.TYPE_COLLECTION.equals(modelField.getType());
}
}