Package com.arconsis.android.datarobot.processor

Source Code of com.arconsis.android.datarobot.processor.EntityAnnotationProcessor

/*
* Copyright (C) 2014 The Datarobot Authors
*
* 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.arconsis.android.datarobot.processor;

import com.arconsis.android.datarobot.builder.provider.ContentProviderBuilder;
import com.arconsis.android.datarobot.builder.provider.SourceContentProviderData;
import com.arconsis.android.datarobot.builder.schema.reader.SchemaReader;
import com.arconsis.android.datarobot.builder.schema.visitor.TypeResolvingVisitor;
import com.arconsis.android.datarobot.builder.schema.writer.SchemaWriter;
import com.arconsis.android.datarobot.config.Persistence;
import com.arconsis.android.datarobot.entity.Entity;
import com.arconsis.android.datarobot.hooks.Create;
import com.arconsis.android.datarobot.hooks.DbCreate;
import com.arconsis.android.datarobot.hooks.DbUpdate;
import com.arconsis.android.datarobot.hooks.Update;
import com.arconsis.android.datarobot.manifest.AndroidManifest;
import com.arconsis.android.datarobot.manifest.AndroidManifestAccess;
import com.arconsis.android.datarobot.schema.SchemaConstants;

import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic.Kind;

import static com.arconsis.android.datarobot.schema.SchemaConstants.GENERATED_SUFFIX;

/**
* @author Alexander Frank
* @author Falk Appel
*/
@SupportedAnnotationTypes({"com.arconsis.android.datarobot.entity.Entity", "com.arconsis.android.datarobot.config.Persistence",
    "com.arconsis.android.datarobot.hooks.Update", "com.arconsis.android.datarobot.hooks.Create"})
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class EntityAnnotationProcessor extends AbstractProcessor {

  private Messager              messager;
  private AndroidManifestAccess androidManifestAccess;

  @Override
  public synchronized void init(final ProcessingEnvironment processingEnv) {
    super.init(processingEnv);
    messager = processingEnv.getMessager();
    androidManifestAccess = new AndroidManifestAccess(processingEnv);
  }

  @Override
  public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
    if (!roundEnv.processingOver()) {
      try {
        Persistence persistence = checkPersistenceAnnotation(roundEnv);
        if (persistence == null) {
          return true;
        }

        AndroidManifest androidManifest = androidManifestAccess.load();
        String updateHookName = getHookName(roundEnv, Update.class, DbUpdate.class);
        String createHookName = getHookName(roundEnv, Create.class, DbCreate.class);
        Set<? extends Element> entityAnnotated = roundEnv.getElementsAnnotatedWith(Entity.class);

        String generatedPackage = androidManifest.getPackageName() + "." + GENERATED_SUFFIX;
        generateDbSchema(generatedPackage, entityAnnotated, persistence, updateHookName, createHookName);
        generateContentProviderIfRequested(generatedPackage, entityAnnotated);
      } catch (RuntimeException e) {
        messager.printMessage(Kind.ERROR, "Not able to generate DB schema from the annotated entity classes " + e.getMessage());
        throw e;
      } catch (Exception e) {
        messager.printMessage(Kind.ERROR, "Not able to generate DB schema from the annotated entity classes " + e.getMessage());
        throw new IllegalStateException(e);
      }
    }
    return true;
  }

  @Override
  public java.util.Set<String> getSupportedOptions() {
    HashSet<String> validOptions = new HashSet<String>();
    validOptions.add("manifest");
    return validOptions;
  }

  private Persistence checkPersistenceAnnotation(final RoundEnvironment roundEnv) {
    Set<? extends Element> persistenceAnnotated = roundEnv.getElementsAnnotatedWith(Persistence.class);

    if (persistenceAnnotated.size() == 0) {
      return null;
    }

    if (persistenceAnnotated.size() > 1) {
      messager.printMessage(Kind.ERROR, "Only one @Persistence activator is allowed within the project", persistenceAnnotated.iterator().next());
      return null;
    }
    Element persistenceClass = persistenceAnnotated.iterator().next();
    Persistence persistence = persistenceClass.getAnnotation(Persistence.class);
    return persistence;
  }

  private String getHookName(final RoundEnvironment roundEnv, Class<? extends Annotation> hookAnnotation, Class<?> hookInterface) {
    Set<? extends Element> annotated = roundEnv.getElementsAnnotatedWith(hookAnnotation);
    if (annotated.size() == 0) {
      return null;
    }
    if (annotated.size() > 1) {
      messager.printMessage(Kind.ERROR,
          "Only one " + hookAnnotation.getCanonicalName() + " hook is allowed with the project", annotated.iterator().next());
      return null;
    }
    Element updateElement = annotated.iterator().next();
    TypeElement typeElement = updateElement.accept(new TypeResolvingVisitor(), null);
    boolean implementsDbUpdate = false;
    for (TypeMirror typeMirror : typeElement.getInterfaces()) {
      if (typeMirror.toString().equals(hookInterface.getCanonicalName())) {
        implementsDbUpdate = true;
      }
    }
    if (!implementsDbUpdate) {
      messager.printMessage(Kind.ERROR,
          "The " + hookAnnotation + " hook has to implement the " + hookInterface.getCanonicalName() + " interface", updateElement);
      return null;
    }
    return typeElement.getQualifiedName().toString();
  }

  private void generateDbSchema(final String packageName, final Set<? extends Element> entityAnnotated, final Persistence persistence,
                  String updateHookName, final String createHookName) {
    SchemaReader schemaReader = new SchemaReader(persistence, updateHookName, createHookName, entityAnnotated, messager);
    SchemaWriter schemaWriter = new SchemaWriter(packageName, SchemaConstants.DB, schemaReader.read());

    JavaFileWriter javaFileWriter = new JavaFileWriter(packageName, SchemaConstants.DB, processingEnv);
    javaFileWriter.write(schemaWriter.write());
  }

  private void generateContentProviderIfRequested(final String packageName, final Set<? extends Element> entityAnnotated) throws Exception {
    List<ContentProviderData> providers = new LinkedList<ContentProviderData>();
    for (Element entity : entityAnnotated) {
      Entity entityAnnotation = entity.getAnnotation(Entity.class);
      if (entityAnnotation.contentProvider()) {
        ContentProviderBuilder providerBuilder = new ContentProviderBuilder(packageName, entity, messager);
        SourceContentProviderData providerData = providerBuilder.build();
        JavaFileWriter javaFileWriter = new JavaFileWriter(packageName, providerData.getSimpleName(), processingEnv);
        javaFileWriter.write(providerData.getSource());
        providers.add(providerData);
      }
    }
    androidManifestAccess.addProviders(providers);
  }

  public static void main(final String[] args) {
    // keep eclipse happy
  }

}
TOP

Related Classes of com.arconsis.android.datarobot.processor.EntityAnnotationProcessor

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.