/* * 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.uberfire.ext.preferences.processors; import java.io.BufferedWriter; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; import javax.tools.Diagnostic.Kind; import freemarker.template.Template; import freemarker.template.TemplateException; import org.uberfire.annotations.processors.AbstractGenerator; import org.uberfire.annotations.processors.GeneratorUtils; import org.uberfire.annotations.processors.exceptions.GenerationException; import org.uberfire.preferences.shared.annotations.Property; import org.uberfire.preferences.shared.annotations.WorkbenchPreference; /** * A source code generator for {@link WorkbenchPreference}. */ public class WorkbenchPreferenceGeneratedImplGenerator extends AbstractGenerator { private GeneratorContext generatorContext; private String targetClassName = null; public WorkbenchPreferenceGeneratedImplGenerator(final GeneratorContext generatorContext) { this.generatorContext = generatorContext; } @Override public StringBuffer generate(final String packageName, final PackageElement packageElement, final String className, final Element element, final ProcessingEnvironment processingEnvironment) throws GenerationException { final Messager messager = processingEnvironment.getMessager(); messager.printMessage(Kind.NOTE, "Starting code generation for [" + className + "]"); final Elements elementUtils = processingEnvironment.getElementUtils(); final TypeElement classElement = (TypeElement) element; final WorkbenchPreference annotation = element.getAnnotation(WorkbenchPreference.class); String sourcePackage = packageName; String sourceClassName = className; String targetPackage = packageName; String identifier = annotation.identifier(); String[] parents = annotation.parents(); String bundleKey = annotation.bundleKey(); if (GeneratorContext.BEAN.equals(generatorContext)) { targetClassName = className + "BeanGeneratedImpl"; } else if (GeneratorContext.PORTABLE.equals(generatorContext)) { targetClassName = className + "PortableGeneratedImpl"; } List<PropertyData> properties = new ArrayList<>(); TypeElement c = classElement; c.getEnclosedElements().forEach(el -> { final Property propertyAnnotation = el.getAnnotation(Property.class); if (propertyAnnotation != null) { properties.add(new PropertyData(el, propertyAnnotation, elementUtils)); } }); final List<PropertyData> simpleProperties = properties.stream() .filter(p -> !p.isSubPreference()) .collect(Collectors.toList()); final List<PropertyData> subPreferences = properties.stream() .filter(p -> p.isSubPreference()) .collect(Collectors.toList()); final List<PropertyData> nonSharedSubPreferences = subPreferences.stream() .filter(p -> !p.isShared()) .collect(Collectors.toList()); final List<PropertyData> sharedSubPreferences = subPreferences.stream() .filter(p -> p.isShared()) .collect(Collectors.toList()); final List<String> constructorParams = properties.stream() .map(p -> "@MapsTo(\"" + p.getFieldName() + "\") " + p.getTypeFullName() + " " + p.getFieldName()) .collect(Collectors.toList()); final String constructorParamsText = String.join(", ", constructorParams); final List<String> propertyFields = properties.stream() .map(PropertyData::getFieldName) .collect(Collectors.toList()); final String propertyFieldsText = String.join(", ", propertyFields); final String parentsIdentifiers = String.join(", ", parents); final String isPersistable = Boolean.toString(!simpleProperties.isEmpty() || !nonSharedSubPreferences.isEmpty()); if (GeneratorUtils.debugLoggingEnabled()) { final List<String> simplePropertiesNames = simpleProperties.stream() .map(PropertyData::getFieldName) .collect(Collectors.toList()); final String simplePropertiesText = String.join(", ", simplePropertiesNames); final List<String> subPreferencesNames = subPreferences.stream() .map(PropertyData::getFieldName) .collect(Collectors.toList()); final String subPreferencesText = String.join(", ", subPreferencesNames); final List<String> sharedSubPreferencesNames = sharedSubPreferences.stream() .map(PropertyData::getFieldName) .collect(Collectors.toList()); final String sharedSubPreferencesText = String.join(", ", sharedSubPreferencesNames); final List<String> nonSharedSubPreferencesNames = nonSharedSubPreferences.stream() .map(PropertyData::getFieldName) .collect(Collectors.toList()); final String nonSharedSubPreferencesText = String.join(", ", nonSharedSubPreferencesNames); messager.printMessage(Kind.NOTE, "Source package name: " + sourcePackage); messager.printMessage(Kind.NOTE, "Source class name: " + sourceClassName); messager.printMessage(Kind.NOTE, "Target package name: " + targetPackage); messager.printMessage(Kind.NOTE, "Target class name: " + targetClassName); messager.printMessage(Kind.NOTE, "Identifier: " + identifier); messager.printMessage(Kind.NOTE, "Parents: " + parentsIdentifiers); messager.printMessage(Kind.NOTE, "Property fields: " + propertyFieldsText); messager.printMessage(Kind.NOTE, "Simple properties fields: " + simplePropertiesText); messager.printMessage(Kind.NOTE, "Sub-preferences fields: " + subPreferencesText); messager.printMessage(Kind.NOTE, "Shared subPreferences fields: " + sharedSubPreferencesText); messager.printMessage(Kind.NOTE, "Non-shared subPreferences fields: " + nonSharedSubPreferencesText); messager.printMessage(Kind.NOTE, "Constructor parameters: " + constructorParamsText); messager.printMessage(Kind.NOTE, "Is persistable: " + isPersistable); } Map<String, Object> root = new HashMap<String, Object>(); root.put("sourcePackage", sourcePackage); root.put("sourceClassName", sourceClassName); root.put("targetPackage", targetPackage); root.put("targetClassName", targetClassName); root.put("identifier", identifier); root.put("parentsIdentifiers", parentsIdentifiers); root.put("bundleKey", bundleKey); root.put("properties", properties); root.put("simpleProperties", simpleProperties); root.put("subPreferences", subPreferences); root.put("sharedSubPreferences", sharedSubPreferences); root.put("nonSharedSubPreferences", nonSharedSubPreferences); root.put("constructorParamsText", constructorParamsText); root.put("propertyFieldsText", propertyFieldsText); root.put("isPersistable", isPersistable); final StringWriter sw = new StringWriter(); final BufferedWriter bw = new BufferedWriter(sw); try { Template template = null; if (GeneratorContext.BEAN.equals(generatorContext)) { template = config.getTemplate("workbenchPreferenceBean.ftl"); } else if (GeneratorContext.PORTABLE.equals(generatorContext)) { template = config.getTemplate("workbenchPreferencePortable.ftl"); } if (template != null) { template.process(root, bw); } } catch (IOException ioe) { throw new GenerationException(ioe); } catch (TemplateException te) { throw new GenerationException(te); } finally { try { bw.close(); sw.close(); } catch (IOException ioe) { throw new GenerationException(ioe); } } messager.printMessage(Kind.NOTE, "Successfully generated code for [" + className + "]"); return sw.getBuffer(); } public String getTargetClassName() { return targetClassName; } }