/* * Copyright 2015 cruxframework.org. * * 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.cruxframework.crux.tools.annotation.processor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Properties; import java.util.Set; import java.util.Map.Entry; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedOptions; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; import javax.lang.model.type.MirroredTypeException; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; import javax.tools.FileObject; import org.cruxframework.crux.core.annotation.processor.CruxAnnotationProcessor; import org.cruxframework.crux.core.rebind.screen.widget.declarative.DeclarativeFactory; /** * @author Thiago da Rosa de Bustamante * */ @SupportedAnnotationTypes("org.cruxframework.crux.core.rebind.screen.widget.declarative.DeclarativeFactory") @SupportedOptions( { CruxAnnotationProcessor.CRUX_RUN_APT, CruxAnnotationProcessor.CRUX_APT_INCREMENTAL }) public class LibraryProcessor extends CruxAnnotationProcessor { private static final String CRUX_WIDGETS_FACTORY_MAP_FILE = "META-INF/crux-widgets-factory"; private static final String CRUX_WIDGETS_TYPE_MAP_FILE = "META-INF/crux-widgets-type"; private boolean previousSourcesLoaded = false; private Properties widgetFactoryMap; private Properties widgetTypeMap; public LibraryProcessor() { widgetFactoryMap = new Properties(); widgetTypeMap = new Properties(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if(!runAPT()) { return true; } try { boolean incremental = isIncremental(); if (incremental && !previousSourcesLoaded) { loadPreviousMapFiles(); } for (Element elem : roundEnv.getElementsAnnotatedWith(DeclarativeFactory.class)) { DeclarativeFactory factoryAnnotation = elem.getAnnotation(DeclarativeFactory.class); if (elem.getKind() == ElementKind.CLASS) { String id = factoryAnnotation.id(); String library = factoryAnnotation.library(); String widgetType = library + "_" + id; String targetWidget = getTargetWidgetType(factoryAnnotation).toString(); String widgetFactoryClassName = ((TypeElement) elem).getQualifiedName().toString(); removePreviousEntryForCurrentClass(incremental, widgetFactoryClassName); widgetFactoryMap.put(widgetType, widgetFactoryClassName); widgetTypeMap.put(targetWidget, widgetType); } } if (roundEnv.processingOver()) { FileObject cruxWidgetFactoryFile = createResourceFile(CRUX_WIDGETS_FACTORY_MAP_FILE); OutputStream outputStream = cruxWidgetFactoryFile.openOutputStream(); widgetFactoryMap.store(outputStream, "Crux Widget Factories mapping"); outputStream.close(); FileObject cruxWidgetTypeFile = createResourceFile(CRUX_WIDGETS_TYPE_MAP_FILE); outputStream = cruxWidgetTypeFile.openOutputStream(); widgetTypeMap.store(outputStream, "Crux Widget Types mapping"); outputStream.close(); } } catch (Exception e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage()); } return true; } private void loadPreviousMapFiles() throws IOException { InputStream inputStream = getResourceFileStream(CRUX_WIDGETS_FACTORY_MAP_FILE); if (inputStream != null) { widgetFactoryMap.load(inputStream); inputStream.close(); } inputStream = getResourceFileStream(CRUX_WIDGETS_TYPE_MAP_FILE); if (inputStream != null) { widgetTypeMap.load(inputStream); inputStream.close(); } previousSourcesLoaded = true; } private void removePreviousEntryForCurrentClass(boolean incremental, String widgetFactoryClassName) { if (incremental && widgetFactoryMap.containsValue(widgetFactoryClassName)) { for (Entry<Object, Object> entry: widgetFactoryMap.entrySet()) { if (entry.getValue().equals(widgetFactoryClassName)) { Object previousWidgetType = entry.getKey(); widgetFactoryMap.remove(previousWidgetType); for (Entry<Object, Object> entryTypes: widgetTypeMap.entrySet()) { if (entryTypes.getValue().equals(previousWidgetType)) { widgetTypeMap.remove(entryTypes.getKey()); break; } } break; } } } } /** * Hacking to access the TypeMirror from an annotation * @param factoryAnnotation * @return */ private static TypeMirror getTargetWidgetType(DeclarativeFactory factoryAnnotation) { try { factoryAnnotation.targetWidget(); // this should throw } catch (MirroredTypeException mte) { return mte.getTypeMirror(); } return null; // can this ever happen ?? } }