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

com.abubusoft.kripton.processor.sqlite.model.SQLiteDatabaseSchema Maven / Gradle / Ivy

There is a newer version: 8.2.0-rc.4
Show newest version
/*******************************************************************************
 * Copyright 2015, 2017 Francesco Benincasa ([email protected]).
 *
 * 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.abubusoft.kripton.processor.sqlite.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;

import com.abubusoft.kripton.android.annotation.BindDataSource;
import com.abubusoft.kripton.android.annotation.BindDataSourceOptions;
import com.abubusoft.kripton.android.annotation.BindTransaction;
import com.abubusoft.kripton.common.CaseFormat;
import com.abubusoft.kripton.common.Converter;
import com.abubusoft.kripton.common.Pair;
import com.abubusoft.kripton.processor.KriptonOptions;
import com.abubusoft.kripton.processor.ReferredClasses;
import com.abubusoft.kripton.processor.core.AssertKripton;
import com.abubusoft.kripton.processor.core.Finder;
import com.abubusoft.kripton.processor.core.ModelAnnotation;
import com.abubusoft.kripton.processor.core.ModelBucket;
import com.abubusoft.kripton.processor.core.TypeAdapterHelper;
import com.abubusoft.kripton.processor.core.reflect.AnnotationUtility;
import com.abubusoft.kripton.processor.core.reflect.AnnotationUtility.AnnotationFoundListener;
import com.abubusoft.kripton.processor.core.reflect.AnnotationUtility.MethodFoundListener;
import com.abubusoft.kripton.processor.core.reflect.TypeUtility;
import com.abubusoft.kripton.processor.element.GeneratedTypeElement;
import com.abubusoft.kripton.processor.sqlite.FindSqlTypeAdapterVisitor;
import com.abubusoft.kripton.processor.sqlite.FindTasksVisitor;
import com.abubusoft.kripton.processor.sqlite.SqlBuilderHelper;
import com.squareup.javapoet.ClassName;

/**
 * The Class SQLiteDatabaseSchema.
 */
public class SQLiteDatabaseSchema extends ModelBucket {

	/** The config populator clazz. */
	public final String configPopulatorClazz;

	/** The class name converter. */
	public Converter classNameConverter = CaseFormat.UPPER_CAMEL
			.converterTo(CaseFormat.LOWER_UNDERSCORE);

	/** The column name converter. */
	public Converter columnNameConverter = CaseFormat.LOWER_CAMEL
			.converterTo(CaseFormat.LOWER_UNDERSCORE);

	/** The entities. */
	protected Map entities = new HashMap();

	/** The entities by simple name. */
	protected Map entitiesBySimpleName = new HashMap();

	/** The sql for create. */
	public List sqlForCreate = new ArrayList();

	/** The sql for drop. */
	public List sqlForDrop = new ArrayList();

	/** used to. */
	protected long globalCounter = 0;

	/**
	 * Next counter.
	 *
	 * @return the long
	 */
	public long nextCounter() {
		return ++globalCounter;
	}

	/** The file name. */
	public String fileName;

	/** The generated class name. */
	public String generatedClassName;

	/**
	 * Gets the generated class name.
	 *
	 * @return the generatedClassName
	 */
	public String getGeneratedClassName() {
		return generatedClassName;
	}

	/** The version. */
	public int version;

	/** The generate log. */
	public boolean generateLog;

	/** The generate async task. */
	public boolean generateAsyncTask;

	/** The generate cursor. */
	public boolean generateCursor;

	/** The generate schema. */
	public boolean generateSchema;

	/** The generated entities. */
	public LinkedHashSet generatedEntities;

	public List transactions = new ArrayList();

	/**
	 * if true, content provider is generated.
	 */
	public boolean generateContentProvider;

	/** The content provider. */
	public SQLiteModelContentProvider contentProvider;

	/** The property by simple name. */
	private Map> propertyBySimpleName = new HashMap<>();

	/** The dao name set. */
	private List daoNameSet;

	/** The generate rx. */
	public boolean generateRx;

	/** The config update tasks. */
	public final ArrayList> configUpdateTasks;

	/** The config in memory. */
	public final boolean configInMemory;

	/** The config cursor factory clazz. */
	public final String configCursorFactoryClazz;

	/** The config log enabled. */
	public final boolean configLogEnabled;

	/** The config database error handler clazz. */
	public final String configDatabaseErrorHandlerClazz;

	/** The config database lifecycle handler clazz. */
	public final String configDatabaseLifecycleHandlerClazz;

	/** The global sql type adapter. */
	public final Map globalSqlTypeAdapter = new HashMap();

	/**
	 * directory used for generate schema
	 */
	public String schemaLocationDirectory;

	/**
	 * Gets the dao name set.
	 *
	 * @return the dao name set
	 */
	public List getDaoNameSet() {
		return daoNameSet;
	}

	/**
	 * Instantiates a new SQ lite database schema.
	 *
	 * @param item
	 *            the item
	 * @param schemaFileName
	 *            the schema file name
	 * @param schemaVersion
	 *            the schema version
	 * @param schema
	 *            the schema
	 * @param log
	 *            the log
	 * @param asyncTask
	 *            the async task
	 * @param generateCursor
	 *            the generate cursor
	 * @param generateRx
	 *            the generate rx
	 * @param daoIntoDataSource
	 *            the dao into data source
	 * @param configCursorFactoryClass
	 *            the config cursor factory class
	 * @param configDatabaseErrorHandlerClass
	 *            the config database error handler class
	 * @param configDatabaseLifecycleHandlerClass
	 *            the config database lifecycle handler class
	 * @param configInMemory
	 *            the config in memory
	 * @param configLogEnabled
	 *            the config log enabled
	 * @param configPopulatorClass
	 *            the config populator class
	 * @param schemaLocationDirectory
	 */
	public SQLiteDatabaseSchema(TypeElement item, String schemaFileName, int schemaVersion, boolean schema, boolean log,
			boolean asyncTask, boolean generateCursor, boolean generateRx, List daoIntoDataSource,
			String configCursorFactoryClass, String configDatabaseErrorHandlerClass,
			String configDatabaseLifecycleHandlerClass, boolean configInMemory, boolean configLogEnabled,
			String configPopulatorClass) {
		super(item.getSimpleName().toString(), item);

		this.fileName = schemaFileName;
		this.version = schemaVersion;
		this.generateLog = log;
		this.generateAsyncTask = asyncTask;
		this.generateCursor = generateCursor;
		this.generateSchema = schema;
		this.generatedClassName = "Bind" + getName();
		this.generateContentProvider = false;
		this.generateRx = generateRx;
		this.contentProvider = null;
		this.generatedEntities = new LinkedHashSet();
		this.daoNameSet = daoIntoDataSource;
		this.schemaLocationDirectory = KriptonOptions.getSchemaLocation();

		FindTasksVisitor valueVisitor = new FindTasksVisitor();
		FindSqlTypeAdapterVisitor typeAdapterVisitors = new FindSqlTypeAdapterVisitor();
		List annotationMirrors = item.getAnnotationMirrors();
		for (AnnotationMirror annotationMirror : annotationMirrors) {
			Map elementValues = annotationMirror
					.getElementValues();

			if (BindDataSourceOptions.class.getName().equals(annotationMirror.getAnnotationType().toString())) {
				for (Map.Entry entry : elementValues
						.entrySet()) {
					// The 'entry.getKey()' here is the annotation attribute
					// name.
					String key = entry.getKey().getSimpleName().toString();
					entry.getValue().accept(valueVisitor, key);
				}
			} else if (BindDataSource.class.getName().equals(annotationMirror.getAnnotationType().toString())) {
				for (Map.Entry entry : elementValues
						.entrySet()) {
					String key = entry.getKey().getSimpleName().toString();
					entry.getValue().accept(typeAdapterVisitors, key);
				}
			}
		}

		// TODO add supported type and check about types
		{
			List list = typeAdapterVisitors.getAdapters();
			for (String typeAdapter : list) {
				String sourceType = TypeAdapterHelper.detectSourceType(typeAdapter);
				AssertKripton.assertTrueOrInvalidGlobalTypeApdaterException(
						!globalSqlTypeAdapter.containsKey(sourceType), this, typeAdapter,
						globalSqlTypeAdapter.get(sourceType));

				globalSqlTypeAdapter.put(sourceType, typeAdapter);
			}
		}

		this.configLogEnabled = configLogEnabled;
		this.configInMemory = configInMemory;
		this.configUpdateTasks = valueVisitor.getTasks();

		this.configCursorFactoryClazz = fillClazz(configCursorFactoryClass, ReferredClasses.NO_CURSOR_FACTORY_CLASS_NAME);
		this.configDatabaseErrorHandlerClazz = fillClazz(configDatabaseErrorHandlerClass, ReferredClasses.NO_DATABASE_ERROR_HANDLER_CLASS_NAME);
		this.configDatabaseLifecycleHandlerClazz = fillClazz(configDatabaseLifecycleHandlerClass,
				ReferredClasses.NO_DATABASE_LIFECYCLE_HANDLER_CLASS_NAME);
		this.configPopulatorClazz = fillClazz(configPopulatorClass, ReferredClasses.NO_POPULATOR_CLASS_NAME);

		// methods
		// create method for dao
		SqlBuilderHelper.forEachMethods((TypeElement) element, new MethodFoundListener() {

			@Override
			public void onMethod(ExecutableElement methodElement) {
				if (methodElement.getModifiers().contains(Modifier.STATIC)) {

					final List annotationList = new ArrayList<>();

					AnnotationUtility.forEachAnnotations(methodElement, new AnnotationFoundListener() {

						@Override
						public void onAcceptAnnotation(Element element, String annotationClassName,
								Map attributes) {

							if // @formatter:off
								(annotationClassName.equals(BindTransaction.class.getCanonicalName()))
								// @formatter:on
							{
								ModelAnnotation annotation = new ModelAnnotation(annotationClassName, attributes);
								annotationList.add(annotation);
							}
							// we don't insert annotation

						}
					});

					annotationList.addAll(annotationList);

					AssertKripton.assertTrueOrInvalidMethodSignException(annotationList.size()!=1,
							SQLiteDatabaseSchema.this, methodElement);

					transactions.add(methodElement);

				}
			}

		});
	}

	/**
	 * Fill clazz.
	 *
	 * @param configClazz
	 *            the config clazz
	 * @param clazz
	 *            the clazz
	 * @return the string
	 */
	private String fillClazz(String configClazz, String clazz) {
		if (!clazz.equals(configClazz)) {
			return configClazz;
		} else {
			return null;
		}
	}

	/**
	 * Clear.
	 */
	public void clear() {
		entities.clear();
		entitiesBySimpleName.clear();
	}

	/**
	 * Adds the entity.
	 *
	 * @param value
	 *            the value
	 */
	public void addEntity(SQLiteEntity value) {
		entities.put(value.getName(), value);
		entitiesBySimpleName.put(value.getSimpleName().toString().toLowerCase(), value);
		Set listEntity = null;

		// update map property name -> property collection with same name
		for (SQLProperty p : value.getCollection()) {
			listEntity = propertyBySimpleName.get(p.getName());
			if (listEntity == null) {
				listEntity = new HashSet<>();
			}
			checkName(listEntity, p);
			listEntity.add(p);
			propertyBySimpleName.put(p.getName().toLowerCase(), listEntity);
		}
	}

	/**
	 * property in different class, but same name, must have same column name.
	 *
	 * @param listEntity
	 *            the list entity
	 * @param p
	 *            the p
	 */
	private void checkName(Set listEntity, SQLProperty p) {
		for (SQLProperty item : listEntity) {
			AssertKripton.assertTrueOrInvalidPropertyName(item.columnName.equals(p.columnName), item, p);
		}

	}

	/**
	 * Gets the entities.
	 *
	 * @return the entities
	 */
	public Collection getEntities() {
		return entities.values();
	}

	/**
	 * Gets the entities as list.
	 *
	 * @return the entities as list
	 */
	public List getEntitiesAsList() {
		return new ArrayList<>(entities.values());
	}

	/**
	 * Gets the entity.
	 *
	 * @param entityClassName
	 *            the entity class name
	 * @return the entity
	 */
	public SQLiteEntity getEntity(String entityClassName) {
		return entities.get(entityClassName);
	}

	/**
	 * Gets the entity by simple name.
	 *
	 * @param entityName
	 *            the entity name
	 * @return the entity by simple name
	 */
	public Finder getEntityBySimpleName(String entityName) {
		if (entityName == null)
			return null;

		SQLiteEntity result = entitiesBySimpleName.get(entityName.toLowerCase());
		if (result != null)
			return result;

		for (GeneratedTypeElement item : this.generatedEntities) {
			if (item.typeSpec.name.toLowerCase().equals(entityName.toLowerCase())) {
				return item;
			}
		}

		return null;
	}

	/**
	 * Gets the property by simple name.
	 *
	 * @param propertyName
	 *            the property name
	 * @return the property by simple name
	 */
	public Set getPropertyBySimpleName(String propertyName) {
		if (propertyName == null)
			return null;

		return this.propertyBySimpleName.get(propertyName.toLowerCase());
	}

	/**
	 * get a.
	 *
	 * @param method
	 *            the method
	 * @param propertyName
	 *            the property name
	 * @return the string
	 */
	public String findColumnNameByPropertyName(SQLiteModelMethod method, String propertyName) {
		Set propertiesSet = getPropertyBySimpleName(propertyName);
		Set set = new HashSet();
		String result = null;

		for (SQLProperty item : propertiesSet) {
			result = item.columnName;
			set.add(item.columnName);
		}

		AssertKripton.assertTrueOrInvalidMethodSignException(result != null && set.size() == 1, method,
				"in JQL attribute can not translate property %s", propertyName);

		return result;
	}

	/**
	 * Checks if is log enabled.
	 *
	 * @return true, if is log enabled
	 */
	public boolean isLogEnabled() {
		return generateLog;
	}

	/**
	 * Content provider uri.
	 *
	 * @return the string
	 */
	public String contentProviderUri() {
		if (!generateContentProvider)
			return "";

		return contentProvider.getUri();

	}

	/**
	 * Gets the generated class.
	 *
	 * @return the generated class
	 */
	public ClassName getGeneratedClass() {
		String packageName = getElement().asType().toString();
		return TypeUtility
				.className(packageName.substring(0, packageName.lastIndexOf(".")) + "." + getGeneratedClassName());
	}

	/**
	 * Returns true if any DAO exposes a method with live data.
	 *
	 * @return true, if successful
	 */
	public boolean hasLiveData() {
		for (SQLiteDaoDefinition dao : getCollection()) {
			if (dao.hasLiveData()) {
				return true;
			}
		}

		return false;
	}

	public SQLiteDaoDefinition findDaoDefinitionForEntity(SQLiteEntity entity) {
		for (SQLiteDaoDefinition item : collection) {
			if (item.getEntity().getName().equals(entity.getName())) {
				return item;
			}
		}

		return null;
	}

	public long currentCounter() {
		return globalCounter;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy