/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* 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.asakusafw.dmdl.windgate.util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.asakusafw.dmdl.java.emitter.EmitContext;
import com.asakusafw.utils.java.model.syntax.Attribute;
import com.asakusafw.utils.java.model.syntax.ClassDeclaration;
import com.asakusafw.utils.java.model.syntax.Expression;
import com.asakusafw.utils.java.model.syntax.MethodDeclaration;
import com.asakusafw.utils.java.model.syntax.ModelFactory;
import com.asakusafw.utils.java.model.syntax.Name;
import com.asakusafw.utils.java.model.syntax.Type;
import com.asakusafw.utils.java.model.syntax.TypeBodyDeclaration;
import com.asakusafw.utils.java.model.syntax.WildcardBoundKind;
import com.asakusafw.utils.java.model.util.AttributeBuilder;
import com.asakusafw.utils.java.model.util.ExpressionBuilder;
import com.asakusafw.utils.java.model.util.JavadocBuilder;
import com.asakusafw.utils.java.model.util.Models;
import com.asakusafw.utils.java.model.util.TypeBuilder;
import com.asakusafw.vocabulary.external.ImporterDescription.DataSize;
import com.asakusafw.windgate.core.vocabulary.DataModelStreamSupport;
/**
* Generates {@code FsImporterDescription} and {@code FsExporterDescription}.
* @since 0.7.3
*/
public final class FsProcessDescriptionGenerator {
// for reduce library dependencies
private static final String IMPORTER_TYPE_NAME =
"com.asakusafw.vocabulary.windgate.FsImporterDescription"; //$NON-NLS-1$
// for reduce library dependencies
private static final String EXPORTER_TYPE_NAME =
"com.asakusafw.vocabulary.windgate.FsExporterDescription"; //$NON-NLS-1$
private final EmitContext context;
private final Description description;
private final ModelFactory f;
private final boolean importer;
private FsProcessDescriptionGenerator(
EmitContext context,
Description description,
boolean importer) {
assert context != null;
assert description != null;
this.context = context;
this.f = context.getModelFactory();
this.importer = importer;
this.description = description;
}
/**
* Generates the class in the context.
* @param context the target emit context
* @param description the meta-description of target class
* @throws IOException if generation was failed by I/O error
*/
public static void generateImporter(EmitContext context, Description description) throws IOException {
FsProcessDescriptionGenerator generator = new FsProcessDescriptionGenerator(context, description, true);
generator.emit();
}
/**
* Generates the class in the context.
* @param context the target emit context
* @param description the meta-description of target class
* @throws IOException if generation was failed by I/O error
*/
public static void generateExporter(EmitContext context, Description description) throws IOException {
FsProcessDescriptionGenerator generator = new FsProcessDescriptionGenerator(context, description, false);
generator.emit();
}
private void emit() throws IOException {
ClassDeclaration decl = f.newClassDeclaration(
new JavadocBuilder(f)
.inline("{0} for {1}.",
d -> d.text(description.getDescription()),
d -> d.linkType(context.resolve(description.getModelClassName())))
.toJavadoc(),
getClassAttributes(),
context.getTypeName(),
context.resolve(Models.toName(f, importer ? IMPORTER_TYPE_NAME : EXPORTER_TYPE_NAME)),
Collections.emptyList(),
createMembers());
context.emit(decl);
}
private List<? extends Attribute> getClassAttributes() {
AttributeBuilder builder = new AttributeBuilder(f);
builder.Public();
if (description.getProfileName() == null
|| description.getPath() == null
|| description.getSupportClassName() == null) {
builder.Abstract();
}
return builder.toAttributes();
}
private List<TypeBodyDeclaration> createMembers() {
List<TypeBodyDeclaration> results = new ArrayList<>();
results.add(createGetModelType());
if (description.getProfileName() != null) {
results.add(createGetProfileName());
}
if (description.getPath() != null) {
results.add(createGetPath());
}
if (description.getSupportClassName() != null) {
results.add(createGetStreamSupport());
}
if (description.getDataSize() != null) {
results.add(createGetDataSize());
}
return results;
}
private MethodDeclaration createGetModelType() {
return createGetter(
new TypeBuilder(f, context.resolve(Class.class))
.parameterize(f.newWildcard(
WildcardBoundKind.UPPER_BOUNDED,
context.resolve(description.getModelClassName())))
.toType(),
"getModelType", //$NON-NLS-1$
f.newClassLiteral(context.resolve(description.getModelClassName())));
}
private MethodDeclaration createGetProfileName() {
return createGetter(
context.resolve(String.class),
"getProfileName", //$NON-NLS-1$
Models.toLiteral(f, description.getProfileName()));
}
private MethodDeclaration createGetStreamSupport() {
return createGetter(
new TypeBuilder(f, context.resolve(Class.class))
.parameterize(f.newWildcard(
WildcardBoundKind.UPPER_BOUNDED,
new TypeBuilder(f, context.resolve(DataModelStreamSupport.class))
.parameterize(f.newWildcard())
.toType()))
.toType(),
"getStreamSupport", //$NON-NLS-1$
f.newClassLiteral(context.resolve(description.getSupportClassName())));
}
private MethodDeclaration createGetPath() {
return createGetter(
context.resolve(String.class),
"getPath", //$NON-NLS-1$
Models.toLiteral(f, description.getPath()));
}
private MethodDeclaration createGetDataSize() {
Type type = context.resolve(DataSize.class);
return createGetter(
type,
"getDataSize", //$NON-NLS-1$
new TypeBuilder(f, type)
.field(description.getDataSize().name())
.toExpression());
}
private MethodDeclaration createGetter(
com.asakusafw.utils.java.model.syntax.Type type,
String name,
Expression value) {
assert type != null;
assert name != null;
assert value != null;
return f.newMethodDeclaration(
null,
new AttributeBuilder(f)
.annotation(context.resolve(Override.class))
.Public()
.toAttributes(),
type,
f.newSimpleName(name),
Collections.emptyList(),
Arrays.asList(new ExpressionBuilder(f, value).toReturnStatement()));
}
/**
* Represents the meta description.
* @since 0.7.0
*/
public static final class Description {
private final String description;
private final Name modelClassName;
private String path;
private String profileName;
private Name supportClassName;
private DataSize dataSize;
/**
* Creates a new instance.
* @param description the textual description
* @param modelClassName the target data model class name
*/
public Description(String description, Name modelClassName) {
this.description = description;
this.modelClassName = modelClassName;
}
/**
* Returns the textual description for the target class.
* @return the description
*/
public String getDescription() {
return description;
}
/**
* Returns the data model class name.
* @return the data model class name
*/
public Name getModelClassName() {
return modelClassName;
}
/**
* Returns the profile name.
* @return the profile name, or {@code null} if it is not set
*/
public String getProfileName() {
return profileName;
}
/**
* Sets the profile name.
* @param value the value to set
*/
public void setProfileName(String value) {
this.profileName = value;
}
/**
* Returns path.
* @return the path, or {@code null} if it is not set
*/
public String getPath() {
return path;
}
/**
* Sets the path.
* @param value the value to set
*/
public void setPath(String value) {
this.path = value;
}
/**
* Returns the format class name.
* @return the format class name, or {@code null} if it is not set
*/
public Name getSupportClassName() {
return supportClassName;
}
/**
* Sets the format class name.
* @param value the value to set
*/
public void setSupportClassName(Name value) {
this.supportClassName = value;
}
/**
* Returns the data size.
* @return the data size, or {@code null} if it is not set
*/
public DataSize getDataSize() {
return dataSize;
}
/**
* Sets the data size.
* @param value the value to set
*/
public void setDataSize(DataSize value) {
this.dataSize = value;
}
}
}