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

com.abubusoft.kripton.processor.sqlite.BindContentProviderBuilder 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;

import static com.abubusoft.kripton.processor.core.reflect.TypeUtility.className;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import javax.annotation.processing.Filer;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.util.Elements;

import com.abubusoft.kripton.android.KriptonLibrary;
import com.abubusoft.kripton.android.Logger;
import com.abubusoft.kripton.android.annotation.BindContentProvider;
import com.abubusoft.kripton.android.annotation.BindContentProviderEntry;
import com.abubusoft.kripton.android.annotation.BindContentProviderEntry.MultiplicityResultType;
import com.abubusoft.kripton.android.annotation.BindContentProviderPath;
import com.abubusoft.kripton.common.Pair;
import com.abubusoft.kripton.processor.bind.JavaWriterHelper;
import com.abubusoft.kripton.processor.core.AnnotationAttributeType;
import com.abubusoft.kripton.processor.core.AssertKripton;
import com.abubusoft.kripton.processor.core.reflect.AnnotationUtility;
import com.abubusoft.kripton.processor.core.reflect.TypeUtility;
import com.abubusoft.kripton.processor.sqlite.core.JavadocUtility;
import com.abubusoft.kripton.processor.sqlite.grammars.jql.JQL.JQLType;
import com.abubusoft.kripton.processor.sqlite.model.SQLiteDaoDefinition;
import com.abubusoft.kripton.processor.sqlite.model.SQLiteDatabaseSchema;
import com.abubusoft.kripton.processor.sqlite.model.SQLiteModelMethod;
import com.abubusoft.kripton.processor.utils.AnnotationProcessorUtilis;
import com.google.common.base.CaseFormat;
import com.google.common.base.Converter;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.CodeBlock.Builder;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeSpec;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;

// TODO: Auto-generated Javadoc
/**
 * Generates content provider class.
 *
 * @author Francesco Benincasa ([email protected])
 */
public class BindContentProviderBuilder extends AbstractBuilder {

	/**
	 * The Class ContentEntry.
	 */
	public static class ContentEntry {

		/**
		 * Instantiates a new content entry.
		 *
		 * @param path
		 *            the path
		 */
		public ContentEntry(String path) {
			this.path = path;
		}

		/** The path. */
		public String path;

		/** The uri index. */
		public String uri_index;

		/** The insert. */
		public SQLiteModelMethod insert;

		/** The update. */
		public SQLiteModelMethod update;

		/** The delete. */
		public SQLiteModelMethod delete;

		/** The select. */
		public SQLiteModelMethod select;

		/** The path costant. */
		public String pathCostant;

		/** The path index. */
		public String pathIndex;

		/** The uri template. */
		public String uriTemplate;

		/** The path value. */
		public int pathValue;

		/**
		 * Gets the content type.
		 *
		 * @return the content type
		 */
		public String getContentType() {
			String type = "item";

			String typeName = null;
			SQLiteModelMethod[] methods = { insert, update, delete, select };

			for (SQLiteModelMethod item : methods) {
				if (item == null)
					continue;
				if (typeName == null) {
					typeName = item.getParent().contentProviderTypeName;
				}

				String value = AnnotationUtility.extractAsEnumerationValue(item.getElement(), BindContentProviderEntry.class, AnnotationAttributeType.MULTIPLICITY_RESULT);
				MultiplicityResultType multiplicity = MultiplicityResultType.valueOf(value);

				if (multiplicity == MultiplicityResultType.MANY || (multiplicity == MultiplicityResultType.DEFAULT && item.jql.operationType == JQLType.SELECT)) {
					type = "dir";
				}
			}

			return "vnd.android.cursor." + type + "/vnd." + typeName;

		}
	}

	/** The uri set. */
	protected Map uriSet = new TreeMap<>();

	/** The Constant PREFIX. */
	public static final String PREFIX = "Bind";

	/** The Constant SUFFIX. */
	public static final String SUFFIX = "ContentProvider";

	/**
	 * Instantiates a new bind content provider builder.
	 *
	 * @param elementUtils
	 *            the element utils
	 * @param filer
	 *            the filer
	 * @param model
	 *            the model
	 */
	public BindContentProviderBuilder(Elements elementUtils, Filer filer, SQLiteDatabaseSchema model) {
		super(elementUtils, filer, model);
	}

	/**
	 * Generate content provider.
	 *
	 * @param elementUtils
	 *            the element utils
	 * @param filer
	 *            the filer
	 * @param schema
	 *            the schema
	 * @throws Exception
	 *             the exception
	 */
	public static void generate(Elements elementUtils, Filer filer, SQLiteDatabaseSchema schema) throws Exception {
		BindContentProviderBuilder visitorDao = new BindContentProviderBuilder(elementUtils, filer, schema);
		visitorDao.build(elementUtils, filer, schema);
	}

	/**
	 * Builds the.
	 *
	 * @param elementUtils
	 *            the element utils
	 * @param filer
	 *            the filer
	 * @param schema
	 *            the schema
	 * @throws Exception
	 *             the exception
	 */
	public void build(Elements elementUtils, Filer filer, SQLiteDatabaseSchema schema) throws Exception {
		uriSet.clear();

		String dataSourceName = schema.getName();
		String dataSourceNameClazz = BindDataSourceBuilder.PREFIX + dataSourceName;
		String contentProviderName = PREFIX + dataSourceName.replace(BindDataSourceBuilder.SUFFIX, "") + SUFFIX;

		PackageElement pkg = elementUtils.getPackageOf(schema.getElement());
		String packageName = pkg.isUnnamed() ? null : pkg.getQualifiedName().toString();

		AnnotationProcessorUtilis.infoOnGeneratedClasses(BindContentProvider.class, packageName, contentProviderName);
		classBuilder = TypeSpec.classBuilder(contentProviderName).addModifiers(Modifier.PUBLIC).superclass(ContentProvider.class);

		classBuilder.addJavadoc("

This is the content provider generated for {@link $L}

\n\n", dataSourceName); classBuilder.addJavadoc("

Content provider authority:

\n"); classBuilder.addJavadoc("
$L
\n\n", schema.contentProvider.authority); generateOnCreate(dataSourceNameClazz); generateOnShutdown(dataSourceNameClazz); // define static fields classBuilder.addField(FieldSpec.builder(String.class, "URI", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL).initializer("$S", schema.contentProviderUri()) .addJavadoc("

content provider's URI.

\n
$L
\n", schema.contentProviderUri()).build()); // instance classBuilder.addField(FieldSpec.builder(className(dataSourceNameClazz), "dataSource", Modifier.PRIVATE, Modifier.STATIC).addJavadoc("

datasource singleton

\n").build()); classBuilder.addField(FieldSpec.builder(String.class, "AUTHORITY", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).addJavadoc("

Content provider authority

\n") .initializer("$S", schema.contentProvider.authority).build()); classBuilder.addField(FieldSpec.builder(UriMatcher.class, "sURIMatcher", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL).addJavadoc("

URI matcher

\n") .initializer("new $T($T.NO_MATCH)", UriMatcher.class, UriMatcher.class).build()); Builder staticBuilder = CodeBlock.builder(); Converter daoConstantConverter = CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.UPPER_UNDERSCORE); List listFieldUri = new ArrayList<>(); List listFieldString = new ArrayList<>(); List listFieldIndex = new ArrayList<>(); List listFieldAlias = new ArrayList<>(); for (SQLiteDaoDefinition daoDefinition : schema.getCollection()) { String pathConstantName = "PATH_" + daoConstantConverter.convert(daoDefinition.getEntitySimplyClassName()); if (!daoDefinition.contentProviderEnabled) continue; // define content provider paths for (SQLiteModelMethod daoMethod : daoDefinition.getCollection()) { if (!daoMethod.contentProviderEntryPathEnabled) continue; ContentEntry entry = uriSet.get(daoMethod.contentProviderEntryPathTemplate); if (entry == null) { entry = new ContentEntry(daoMethod.contentProviderEntryPath); uriSet.put(daoMethod.contentProviderEntryPathTemplate, entry); entry.path = daoMethod.contentProviderEntryPath; entry.uriTemplate = daoMethod.contentProviderEntryPathTemplate; // we finish later entry.pathCostant = pathConstantName; entry.pathIndex = pathConstantName; } switch (daoMethod.jql.operationType) { case INSERT: AssertKripton.fail(entry.insert != null, String.format("In DAO '%s', there are more than one %s statement associated to content provider path '%s'", daoDefinition.getName().toString(), daoMethod.jql.operationType, entry.path)); entry.insert = daoMethod; break; case UPDATE: AssertKripton.fail(entry.update != null, String.format("In DAO '%s', there are more than one %s statement associated to content provider path '%s'", daoDefinition.getName().toString(), daoMethod.jql.operationType, entry.path)); entry.update = daoMethod; break; case SELECT: AssertKripton.fail(entry.select != null, String.format("In DAO '%s', there are more than one %s statement associated to content provider path '%s'", daoDefinition.getName().toString(), daoMethod.jql.operationType, entry.path)); entry.select = daoMethod; break; case DELETE: AssertKripton.fail(entry.delete != null, String.format("In DAO '%s', there are more than one %s statement associated to content provider path '%s'", daoDefinition.getName().toString(), daoMethod.jql.operationType, entry.path)); entry.delete = daoMethod; break; } } } // sort uri set by List> listUriSet = new ArrayList<>(); Pair item; for (Entry entry : uriSet.entrySet()) { item = new Pair(entry.getKey(), entry.getValue()); listUriSet.add(item); } Comparator> c = new Comparator>() { @Override public int compare(Pair lhs, Pair rhs) { return lhs.value0.compareTo(rhs.value0); } }; Collections.sort(listUriSet, c); Set alreadyUsedName = new HashSet(); Converter format = CaseFormat.LOWER_CAMEL.converterTo(CaseFormat.UPPER_UNDERSCORE); int i = 1; for (Pair entry : listUriSet) { // define ordered part of attributes (after sort) entry.value1.pathCostant += "_" + i; entry.value1.pathIndex += "_" + i + "_INDEX"; entry.value1.pathValue = i; // build class attributes listFieldString.add(FieldSpec.builder(String.class, entry.value1.pathCostant, Modifier.STATIC, Modifier.FINAL).initializer(CodeBlock.of("$S", entry.value1.uriTemplate)).build()); listFieldIndex.add(FieldSpec.builder(Integer.TYPE, entry.value1.pathIndex, Modifier.STATIC, Modifier.FINAL).initializer(CodeBlock.of("$L", entry.value1.pathValue)).build()); listFieldUri.add(FieldSpec.builder(Uri.class, "URI_" + entry.value1.pathCostant, Modifier.STATIC, Modifier.FINAL, Modifier.PRIVATE).addJavadoc("

Uri

\n") .addJavadoc("
$L/$L
\n", schema.contentProviderUri().replace("*", "[*]"), entry.value1.uriTemplate.replace("*", "[*]")) .initializer(CodeBlock.of("Uri.parse(URI+\"/$L\")", entry.value1.uriTemplate)).build()); generateURIForMethod(schema, listFieldAlias, alreadyUsedName, format, entry, entry.value1.delete); generateURIForMethod(schema, listFieldAlias, alreadyUsedName, format, entry, entry.value1.insert); generateURIForMethod(schema, listFieldAlias, alreadyUsedName, format, entry, entry.value1.select); generateURIForMethod(schema, listFieldAlias, alreadyUsedName, format, entry, entry.value1.update); staticBuilder.addStatement("sURIMatcher.addURI(AUTHORITY, $L, $L)", entry.value1.pathCostant, entry.value1.pathIndex); i++; } for (FieldSpec f : listFieldUri) { classBuilder.addField(f); } for (FieldSpec f : listFieldString) { classBuilder.addField(f); } for (FieldSpec f : listFieldIndex) { classBuilder.addField(f); } for (FieldSpec f : listFieldAlias) { classBuilder.addField(f); } classBuilder.addStaticBlock(staticBuilder.build()); generateQuery(schema); generateInsert(schema); generateUpdate(schema); generateDelete(schema); generateGetType(schema); classBuilder.addJavadoc("\n\n"); JavadocUtility.generateJavadocGeneratedBy(classBuilder); TypeSpec typeSpec = classBuilder.build(); JavaWriterHelper.writeJava2File(filer, packageName, typeSpec); } /** * Generate URI for method. * * @param schema * the schema * @param listFieldAlias * the list field alias * @param alreadyUsedName * the already used name * @param format * the format * @param entry * the entry * @param method * the method */ private void generateURIForMethod(SQLiteDatabaseSchema schema, List listFieldAlias, Set alreadyUsedName, Converter format, Pair entry, SQLiteModelMethod method) { if (method == null) return; String alias = "URI_" + entry.value1.pathCostant.substring(0, entry.value1.pathCostant.lastIndexOf("_")).replace("PATH_", "") + "_" + format.convert(method.getName()); if (!alreadyUsedName.contains(alias)) { String contentUri = schema.contentProviderUri().replace("*", "[*]") + "/" + entry.value1.uriTemplate.replace("*", "[*]"); String contentUriWithParameter = method.contentProviderUri().replace("*", "[*]"); listFieldAlias.add(FieldSpec.builder(Uri.class, alias, Modifier.STATIC, Modifier.FINAL, Modifier.PUBLIC).addJavadoc("

URI standard

\n
$L

\n", contentUri) .addJavadoc("

URI with parameters

\n
$L
\n\n", contentUriWithParameter) .addJavadoc("

Method associated to this URI is {@link $LImpl#$L}

\n", method.getParent().getName(), method.contentProviderMethodName) .initializer(CodeBlock.of("URI_" + entry.value1.pathCostant)).build()); alreadyUsedName.add(alias); } } /** *

* Generate INSERT code for content provider *

* . * * @param schema * the schema */ private void generateInsert(SQLiteDatabaseSchema schema) { // method sign MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("insert").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(Uri.class); methodBuilder.addParameter(Uri.class, "uri"); methodBuilder.addParameter(ContentValues.class, "contentValues"); boolean hasOperation = hasOperationOfType(schema, methodBuilder, JQLType.INSERT); if (!hasOperation) { methodBuilder.addStatement("throw new $T(\"Unknown URI for $L operation: \" + uri)", IllegalArgumentException.class, JQLType.DELETE); classBuilder.addMethod(methodBuilder.build()); return; } defineJavadocHeaderForContentOperation(methodBuilder, "insert"); // method code methodBuilder.addStatement("long _id=-1"); methodBuilder.addStatement("$T _returnURL=null", Uri.class); methodBuilder.beginControlFlow("switch (sURIMatcher.match(uri))"); for (Entry item : uriSet.entrySet()) { if (item.getValue().insert == null) continue; defineJavadocForContentUri(methodBuilder, item.getValue().insert); methodBuilder.beginControlFlow("case $L:", item.getValue().pathIndex); methodBuilder.addStatement("_id=dataSource.get$L().$L(uri, contentValues)", item.getValue().insert.getParent().getName(), item.getValue().insert.contentProviderMethodName); methodBuilder.addStatement("_returnURL=Uri.withAppendedPath(uri, String.valueOf(_id))"); methodBuilder.addStatement("break"); methodBuilder.endControlFlow(); } defineJavadocFooterForContentOperation(methodBuilder); methodBuilder.beginControlFlow("default:"); methodBuilder.addStatement("throw new $T(\"Unknown URI for $L operation: \" + uri)", IllegalArgumentException.class, JQLType.INSERT); methodBuilder.endControlFlow(); methodBuilder.endControlFlow(); if (hasOperation) { if (schema.generateLog) { // generate log section - BEGIN methodBuilder.addComment("log section for content provider insert BEGIN"); methodBuilder.beginControlFlow("if (dataSource.isLogEnabled())"); methodBuilder.addStatement("$T.info(\"Element is created with URI '%s'\", _returnURL)", Logger.class); methodBuilder.addStatement("$T.info(\"Changes are notified for URI '%s'\", uri)", Logger.class); // generate log section - END methodBuilder.endControlFlow(); methodBuilder.addComment("log section for content provider insert END"); } methodBuilder.addStatement("getContext().getContentResolver().notifyChange(uri, null)"); methodBuilder.addStatement("return _returnURL"); } classBuilder.addMethod(methodBuilder.build()); } /** * Define javadoc for content uri. * * @param builder * the builder * @param method * the method */ private void defineJavadocForContentUri(MethodSpec.Builder builder, SQLiteModelMethod method) { String contentUri = method.contentProviderUri().replace("*", "[*]"); classBuilder.addJavadoc("
$L
{@link $LImpl#$L}\n", contentUri, method.getParent().getName(), method.contentProviderMethodName); builder.addJavadoc("
$L
{@link $LImpl#$L}\n", contentUri, method.getParent().getName(), method.contentProviderMethodName); } /** * Generate delete. * * @param schema * the schema */ private void generateDelete(SQLiteDatabaseSchema schema) { MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("delete").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(Integer.TYPE); methodBuilder.addParameter(Uri.class, "uri"); methodBuilder.addParameter(String.class, "selection"); methodBuilder.addParameter(ParameterSpec.builder(TypeUtility.arrayTypeName(String.class), "selectionArgs").build()); boolean hasOperation = hasOperationOfType(schema, methodBuilder, JQLType.DELETE); if (!hasOperation) { methodBuilder.addStatement("throw new $T(\"Unknown URI for $L operation: \" + uri)", IllegalArgumentException.class, JQLType.DELETE); classBuilder.addMethod(methodBuilder.build()); return; } methodBuilder.addStatement("int returnRowDeleted=-1"); methodBuilder.beginControlFlow("switch (sURIMatcher.match(uri))"); defineJavadocHeaderForContentOperation(methodBuilder, "delete"); for (Entry item : uriSet.entrySet()) { if (item.getValue().delete == null) continue; defineJavadocForContentUri(methodBuilder, item.getValue().delete); // methodBuilder.addJavadoc("uri $L\n", item.getKey()); methodBuilder.beginControlFlow("case $L:", item.getValue().pathIndex); methodBuilder.addCode("// URI: $L\n", item.getValue().delete.contentProviderUri()); methodBuilder.addStatement("returnRowDeleted=dataSource.get$L().$L(uri, selection, selectionArgs)", item.getValue().delete.getParent().getName(), item.getValue().delete.contentProviderMethodName); methodBuilder.addStatement("break"); methodBuilder.endControlFlow(); } defineJavadocFooterForContentOperation(methodBuilder); methodBuilder.beginControlFlow("default:"); methodBuilder.addStatement("throw new $T(\"Unknown URI for $L operation: \" + uri)", IllegalArgumentException.class, JQLType.DELETE); methodBuilder.endControlFlow(); methodBuilder.endControlFlow(); if (hasOperation) { if (schema.generateLog) { // generate log section - BEGIN methodBuilder.addComment("log section for content provider delete BEGIN"); methodBuilder.beginControlFlow("if (dataSource.isLogEnabled())"); methodBuilder.addStatement("$T.info(\"Changes are notified for URI %s\", uri)", Logger.class); // generate log section - END methodBuilder.endControlFlow(); methodBuilder.addComment("log section for content provider delete END"); } methodBuilder.addStatement("getContext().getContentResolver().notifyChange(uri, null)"); } methodBuilder.addCode("return returnRowDeleted;\n"); classBuilder.addMethod(methodBuilder.build()); } /** * Generate update. * * @param schema * the schema */ private void generateUpdate(SQLiteDatabaseSchema schema) { MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("update").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(Integer.TYPE); methodBuilder.addParameter(Uri.class, "uri"); methodBuilder.addParameter(ContentValues.class, "contentValues"); methodBuilder.addParameter(String.class, "selection"); methodBuilder.addParameter(ParameterSpec.builder(TypeUtility.arrayTypeName(String.class), "selectionArgs").build()); boolean hasOperation = hasOperationOfType(schema, methodBuilder, JQLType.UPDATE); if (!hasOperation) { methodBuilder.addStatement("throw new $T(\"Unknown URI for $L operation: \" + uri)", IllegalArgumentException.class, JQLType.UPDATE); classBuilder.addMethod(methodBuilder.build()); return; } defineJavadocHeaderForContentOperation(methodBuilder, "update"); methodBuilder.addStatement("int returnRowUpdated=1"); methodBuilder.beginControlFlow("switch (sURIMatcher.match(uri))"); for (Entry item : uriSet.entrySet()) { if (item.getValue().update == null) continue; // methodBuilder.addJavadoc("uri $L\n", item.getKey()); defineJavadocForContentUri(methodBuilder, item.getValue().update); methodBuilder.beginControlFlow("case $L:", item.getValue().pathIndex); methodBuilder.addCode("// URI: $L\n", item.getValue().update.contentProviderUri()); methodBuilder.addStatement("returnRowUpdated=dataSource.get$L().$L(uri, contentValues, selection, selectionArgs)", item.getValue().update.getParent().getName(), item.getValue().update.contentProviderMethodName); methodBuilder.addStatement("break"); methodBuilder.endControlFlow(); } defineJavadocFooterForContentOperation(methodBuilder); methodBuilder.beginControlFlow("default:"); methodBuilder.addStatement("throw new $T(\"Unknown URI for $L operation: \" + uri)", IllegalArgumentException.class, JQLType.UPDATE); methodBuilder.endControlFlow(); methodBuilder.endControlFlow(); if (hasOperation) { if (schema.generateLog) { // generate log section - BEGIN methodBuilder.addComment("log section BEGIN"); methodBuilder.beginControlFlow("if (dataSource.isLogEnabled())"); methodBuilder.addStatement("$T.info(\"Changes are notified for URI %s\", uri)", Logger.class); // generate log section - END methodBuilder.endControlFlow(); methodBuilder.addComment("log section END"); } methodBuilder.addStatement("getContext().getContentResolver().notifyChange(uri, null)"); } methodBuilder.addStatement("return returnRowUpdated"); classBuilder.addMethod(methodBuilder.build()); } /** * Define javadoc footer for content operation. * * @param methodBuilder * the method builder */ private void defineJavadocFooterForContentOperation(MethodSpec.Builder methodBuilder) { classBuilder.addJavadoc("\n\n"); methodBuilder.addJavadoc("\n\n"); } /** * Define javadoc header for content operation. * * @param builder * the builder * @param value * the value */ private void defineJavadocHeaderForContentOperation(MethodSpec.Builder builder, String value) { builder.addJavadoc("\n

Supported $L operations

\n", value); builder.addJavadoc("\n"); builder.addJavadoc("\n"); classBuilder.addJavadoc("

Supported $L operations

\n", value); classBuilder.addJavadoc("
URIDAO.METHOD
\n"); classBuilder.addJavadoc("\n"); } /** * iterate methods, selecting only jqlType and * contains @BindContentProviderEntry annotation. * * @param schema * the schema * @param methodBuilder * the method builder * @param jqlType * the jql type * @return true, if successful */ private boolean hasOperationOfType(SQLiteDatabaseSchema schema, MethodSpec.Builder methodBuilder, JQLType jqlType) { boolean hasOperation = false; for (SQLiteDaoDefinition daoDefinition : schema.getCollection()) { if (daoDefinition.getElement().getAnnotation(BindContentProviderPath.class) == null) continue; for (SQLiteModelMethod daoMethod : daoDefinition.getCollection()) { if (daoMethod.jql.operationType != jqlType) { continue; } if (!daoMethod.hasAnnotation(BindContentProviderEntry.class)) { continue; } hasOperation = true; // methodBuilder.addJavadoc("method $L.$L\n", // daoDefinition.getName(), daoMethod.getName()); } } return hasOperation; } /** * Generate get type. * * @param schema * the schema */ private void generateGetType(SQLiteDatabaseSchema schema) { MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("getType").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(String.class); methodBuilder.addParameter(Uri.class, "uri"); methodBuilder.beginControlFlow("switch (sURIMatcher.match(uri))"); for (Entry item : uriSet.entrySet()) { methodBuilder.beginControlFlow("case $L:", item.getValue().pathIndex); methodBuilder.addStatement("return $S", item.getValue().getContentType()); methodBuilder.endControlFlow(); } methodBuilder.endControlFlow(); methodBuilder.addStatement("throw new $T(\"Unknown URI for $L operation: \" + uri)", IllegalArgumentException.class, "getType"); classBuilder.addMethod(methodBuilder.build()); } /** * Generate on create. * * @param dataSourceNameClazz * the data source name clazz */ private void generateOnCreate(String dataSourceNameClazz) { MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("onCreate").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(Boolean.TYPE); methodBuilder.addJavadoc("

Create datasource and open database in read mode.

\n"); methodBuilder.addJavadoc("\n"); methodBuilder.addJavadoc("@see android.content.ContentProvider#onCreate()\n"); methodBuilder.beginControlFlow("if ($T.getContext()==null)", KriptonLibrary.class); methodBuilder.addStatement("KriptonLibrary.init(getContext())"); methodBuilder.endControlFlow(); methodBuilder.addStatement("dataSource = $L.getInstance()", dataSourceNameClazz); methodBuilder.addStatement("dataSource.openWritableDatabase()"); methodBuilder.addCode("return true;\n"); classBuilder.addMethod(methodBuilder.build()); } /** * Generate on shutdown. * * @param dataSourceNameClazz * the data source name clazz */ private void generateOnShutdown(String dataSourceNameClazz) { MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("shutdown").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(Void.TYPE); methodBuilder.addJavadoc("

Close database.

\n"); methodBuilder.addJavadoc("\n"); methodBuilder.addJavadoc("@see android.content.ContentProvider#shutdown()\n"); methodBuilder.addStatement("super.shutdown()"); methodBuilder.addStatement("dataSource.close()"); classBuilder.addMethod(methodBuilder.build()); } /** * Generate query. * * @param schema * the schema */ private void generateQuery(SQLiteDatabaseSchema schema) { MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("query").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(Cursor.class); methodBuilder.addParameter(Uri.class, "uri"); methodBuilder.addParameter(ParameterSpec.builder(TypeUtility.arrayTypeName(String.class), "projection").build()); methodBuilder.addParameter(String.class, "selection"); methodBuilder.addParameter(ParameterSpec.builder(TypeUtility.arrayTypeName(String.class), "selectionArgs").build()); methodBuilder.addParameter(String.class, "sortOrder"); boolean hasOperation = hasOperationOfType(schema, methodBuilder, JQLType.SELECT); if (!hasOperation) { methodBuilder.addStatement("throw new $T(\"Unknown URI for $L operation: \" + uri)", IllegalArgumentException.class, JQLType.SELECT); classBuilder.addMethod(methodBuilder.build()); return; } methodBuilder.addStatement("$T returnCursor=null", Cursor.class); for (SQLiteDaoDefinition daoDefinition : schema.getCollection()) { for (SQLiteModelMethod daoMethod : daoDefinition.getCollection()) { if (daoMethod.jql.operationType != JQLType.SELECT) continue; // methodBuilder.addJavadoc("method $L.$L\n", // daoDefinition.getName(), daoMethod.getName()); } } defineJavadocHeaderForContentOperation(methodBuilder, "query"); methodBuilder.beginControlFlow("switch (sURIMatcher.match(uri))"); for (Entry item : uriSet.entrySet()) { if (item.getValue().select == null) continue; defineJavadocForContentUri(methodBuilder, item.getValue().select); // methodBuilder.addJavadoc("uri $L\n", item.getKey()); methodBuilder.beginControlFlow("case $L:", item.getValue().pathIndex); methodBuilder.addCode("// URI: $L\n", item.getValue().select.contentProviderUri()); methodBuilder.addStatement("returnCursor=dataSource.get$L().$L(uri, projection, selection, selectionArgs, sortOrder)", item.getValue().select.getParent().getName(), item.getValue().select.contentProviderMethodName); methodBuilder.addStatement("break"); methodBuilder.endControlFlow(); } methodBuilder.beginControlFlow("default:"); methodBuilder.addStatement("throw new $T(\"Unknown URI for $L operation: \" + uri)", IllegalArgumentException.class, JQLType.SELECT); methodBuilder.endControlFlow(); methodBuilder.endControlFlow(); defineJavadocFooterForContentOperation(methodBuilder); if (hasOperation) { methodBuilder.addStatement("return returnCursor"); } classBuilder.addMethod(methodBuilder.build()); } }









URIDAO.METHOD