com.abubusoft.kripton.processor.sqlite.BindContentProviderBuilder Maven / Gradle / Ivy
/*******************************************************************************
* 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("\nSupported $L operations
\n", value);
builder.addJavadoc("\n");
builder.addJavadoc("URI DAO.METHOD \n");
classBuilder.addJavadoc("Supported $L operations
\n", value);
classBuilder.addJavadoc("\n");
classBuilder.addJavadoc("URI DAO.METHOD \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());
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy