com.speedment.generator.translator.Translator Maven / Gradle / Ivy
/**
*
* Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved.
*
* 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.speedment.generator.translator;
import com.speedment.common.codegen.Generator;
import com.speedment.common.codegen.Meta;
import com.speedment.common.codegen.model.ClassOrInterface;
import com.speedment.common.codegen.model.File;
import com.speedment.common.codegen.model.Import;
import com.speedment.runtime.config.*;
import com.speedment.runtime.config.trait.HasAlias;
import com.speedment.runtime.config.trait.HasEnabled;
import com.speedment.runtime.config.trait.HasMainInterface;
import com.speedment.runtime.core.exception.SpeedmentException;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
import static java.util.Objects.requireNonNull;
/**
* Something that can translate a {@link Document} into something else. This
* interface is implemented to generate more files from the same database
* structure.
*
* @author Per Minborg
* @param the Document type to use
* @param the codegen type to make (Class, Interface or Enum)
* @see Document
* @since 2.3.0
*/
public interface Translator extends Supplier {
/**
* Return this node or any ancestral node that is a {@link Project}. If no
* such node exists, an {@code IllegalStateException} is thrown.
*
* @return the project node
*/
default Optional project() {
return getDocument(Project.class);
}
/**
* Return this node or any ancestral node that is a {@link Dbms}. If no such
* node exists, an {@code IllegalStateException} is thrown.
*
* @return the dbms node
*/
default Optional dbms() {
return getDocument(Dbms.class);
}
/**
* Return this node or any ancestral node that is a {@link Schema}. If no
* such node exists, an {@code IllegalStateException} is thrown.
*
* @return the schema node
*/
default Optional schema() {
return getDocument(Schema.class);
}
/**
* Return this node or any ancestral node that is a {@link Table}. If no
* such node exists, an {@code IllegalStateException} is thrown.
*
* @return the table node
*/
default Optional table() {
return getDocument(Table.class);
}
/**
* Return this node or any ancestral node that is a {@link Column}. If no
* such node exists, an {@code IllegalStateException} is thrown.
*
* @return the column node
*/
default Optional column() {
return getDocument(Column.class);
}
/**
* Returns a stream over all enabled columns in the node tree. Disabled
* nodes will be ignored.
*
* @return the enabled columns
* @see Column
* @see HasEnabled#isEnabled()
*/
default Stream extends Column> columns() {
return table()
.map(Table::columns)
.orElse(Stream.empty())
.filter(HasEnabled::test);
}
/**
* Returns a stream over all enabled indexes in the node tree. Disabled
* nodes will be ignored.
*
* @return the enabled indexes
* @see Index
* @see HasEnabled#isEnabled()
*/
default Stream extends Index> indexes() {
return table()
.map(Table::indexes)
.orElse(Stream.empty()).filter(HasEnabled::test);
}
/**
* Returns a stream over all enabled foreign keys in the node tree. Disabled
* nodes will be ignored.
*
* @return the enabled foreign keys
* @see ForeignKey
* @see HasEnabled#isEnabled()
*/
default Stream extends ForeignKey> foreignKeys() {
return table()
.map(Table::foreignKeys)
.orElse(Stream.empty())
.filter(HasEnabled::test);
}
/**
* Returns a stream over all enabled primary key columns in the node tree.
* Disabled nodes will be ignored.
*
* @return the enabled primary key columns
* @see PrimaryKeyColumn
* @see HasEnabled#isEnabled()
*/
default Stream extends PrimaryKeyColumn> primaryKeyColumns() {
return table()
.map(Table::primaryKeyColumns)
.orElse(Stream.empty())
.filter(HasEnabled::test);
}
/**
* The document being translated.
*
* @return the document
*/
DOC getDocument();
/**
* Returns this node or one of the ancestor nodes if it matches the
* specified {@code Class}. If no such node exists, an
* {@code IllegalStateException} is thrown.
*
* @param the type of the class to match
* @param clazz the class to match
* @return the node found
*/
default Optional getDocument(Class clazz) {
requireNonNull(clazz);
if (clazz.isAssignableFrom(Translator.this.getDocument().mainInterface())) {
@SuppressWarnings("unchecked")
final E result = (E) Translator.this.getDocument();
return Optional.of(result);
}
return Translator.this.getDocument()
.ancestors()
.filter(clazz::isInstance)
.map(clazz::cast)
.findAny();
}
/**
* The document being translated wrapped in a {@link HasAlias}.
*
* @return the document
*/
default HasAlias getAliasDocument() {
return HasAlias.of(Translator.this.getDocument());
}
/**
* Generates code for the {@link Document} contained in this
* {@code Translator}.
*
* @return the generated meta info
*/
default Meta generate() {
return getCodeGenerator().metaOn(
get()).findFirst().orElseThrow(
() -> new SpeedmentException("Unable to generate Java code")
);
}
/**
* Generates and returns the code translated from the contained
* {@link Document} by this {@code Translator}.
*
* @return the generated code
*/
default String toCode() {
return generate().getResult();
}
/**
* Returns {@code true} if the file generated by this {@code Translator}
* should be located in a {@code .generated.} package. Files located in
* such a package will be overwritten each time the generator runs.
*
* @return {@code true} if located in {@code .generated.}, else {@code false}
*/
boolean isInGeneratedPackage();
/**
* Returns the CodeGen {@link Generator} used by this {@code Translator}.
* This can be used to add dependencies to the runtime or to install new
* views.
*
* @return the {@link Generator} used
*/
Generator getCodeGenerator();
/**
* Append an additional action that should be executed as part of the make
* process of this translator. This method is useful for adding additional
* methods, fields or internal classes based on the configuration model.
*
* If the action requires additional {@link Import} statements to
* be added to the generated file, the {@link #onMake(BiConsumer)} method
* should be used instead.
*
* @param action the action to perform
* @see #onMake(BiConsumer)
*/
default void onMake(Consumer> action) {
onMake((file, builder) -> action.accept(builder));
}
/**
* Append an additional action that should be executed as part of the make
* process of this translator. This method is useful for adding additional
* methods, fields or internal classes based on the configuration model.
*
* This method allows the action to affect both the {@link Builder} and the
* file where the class or interface will be located. This should be used
* if the specified action require additional {@link Import} statements to
* be added to the file.
*
* @param action the action to perform
* @see #onMake(BiConsumer)
*/
void onMake(BiConsumer> action);
/**
* Returns a {@code Stream} of the listeners currently part of the make
* process of this {@code Translator}.
*
* @return {@code Stream} of all listeners
*/
Stream>> listeners();
/**
* The make process is divided into three phases; {@link #PRE_MAKE},
* {@link #MAKE} and {@link #POST_MAKE}, as specified by this enum.
*
* @author Per Minborg
* @since 2.3
*/
enum Phase { PRE_MAKE, MAKE, POST_MAKE }
/**
* A general interface for all builder implementations used by this
* {@link Translator}. A builder is finalized using the {@link #build()}
* method.
*
* @param {@link com.speedment.common.codegen.model.Class Class},
* {@link com.speedment.common.codegen.model.Interface Interface} or
* {@link com.speedment.common.codegen.model.Enum Enum} to build.
*
* @author Emil Forslund
* @since 2.3
*/
interface Builder {
/**
* Executes the specified code for every document of the specified type
* that is found during this build. This method could for an example be
* called to add additional methods or fields to the
* {@link ClassOrInterface} being built.
*
* A key and constructor is specified so that the document of the
* unknown type can be constructed when the tree is traversed.
*
* @param
the type of the parent document
* @param the type of the document
* @param key the key to react on
* @param constructor constructor for the document to react on
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
default Builder
forEvery(String key, BiFunction, DOC> constructor, BiConsumer consumer) {
return forEvery(Phase.MAKE, key, constructor, consumer);
}
/**
* Executes the specified code for every document of the specified type
* that is found during this build. This method could for an example be
* called to add additional methods or fields to the
* {@link ClassOrInterface} being built.
*
* A key and constructor is specified so that the document of the
* unknown type can be constructed when the tree is traversed.
*
* @param
the type of the parent document
* @param the type of the document
* @param phase the {@link Phase} to execute in
* @param key the key to react on
* @param constructor constructor for the document to react on
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
Builder
forEvery(Phase phase, String key, BiFunction, DOC> constructor, BiConsumer consumer);
/**
* Executes the specified code for the {@link Project} document of this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
default Builder forEveryProject(BiConsumer consumer) {return forEveryProject(Phase.MAKE, consumer);}
/**
* Executes the specified code for the {@link Project} document of this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param phase the {@link Phase} to execute in
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
Builder forEveryProject(Phase phase, BiConsumer consumer);
/**
* Executes the specified code for every {@link Dbms} document in this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
default Builder forEveryDbms(BiConsumer consumer) {
return forEveryDbms(Phase.MAKE, consumer);
}
/**
* Executes the specified code for every {@link Dbms} document in this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param phase the {@link Phase} to execute in
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
Builder forEveryDbms(Phase phase, BiConsumer consumer);
/**
* Executes the specified code for every {@link Schema} document in this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
default Builder forEverySchema(BiConsumer consumer) {
return forEverySchema(Phase.MAKE, consumer);
}
/**
* Executes the specified code for every {@link Schema} document in this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param phase the {@link Phase} to execute in
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
Builder forEverySchema(Phase phase, BiConsumer consumer);
/**
* Executes the specified code for every {@link Table} document in this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
default Builder forEveryTable(BiConsumer consumer) {
return forEveryTable(Phase.MAKE, consumer);
}
/**
* Executes the specified code for every {@link Table} document in this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param phase the {@link Phase} to execute in
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
Builder forEveryTable(Phase phase, BiConsumer consumer);
/**
* Executes the specified code for every {@link Column} document in this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
default Builder forEveryColumn(BiConsumer consumer) {
return forEveryColumn(Phase.MAKE, consumer);
}
/**
* Executes the specified code for every {@link Column} document in this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param phase the {@link Phase} to execute in
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
Builder forEveryColumn(Phase phase, BiConsumer consumer);
/**
* Executes the specified code for every {@link Index} document in this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
default Builder forEveryIndex(BiConsumer consumer) {
return forEveryIndex(Phase.MAKE, consumer);
}
/**
* Executes the specified code for every {@link Index} document in this
* build. This method could for an example be called to add additional
* methods or fields to the {@link ClassOrInterface} being built.
*
* @param phase the {@link Phase} to execute in
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
Builder forEveryIndex(Phase phase, BiConsumer consumer);
/**
* Executes the specified code for every {@link ForeignKey} document in
* this build. This method could for an example be called to add
* additional methods or fields to the {@link ClassOrInterface} being
* built.
*
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
default Builder forEveryForeignKey(BiConsumer consumer) {
return forEveryForeignKey(Phase.MAKE, consumer);
}
/**
* Executes the specified code for every {@link ForeignKey} document in
* this build. This method could for an example be called to add
* additional methods or fields to the {@link ClassOrInterface} being
* built.
*
* @param phase the {@link Phase} to execute in
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
Builder forEveryForeignKey(Phase phase, BiConsumer consumer);
/**
* Executes the specified code for every external {@link ForeignKey}
* document that is referencing this document during this build. This
* method could for an example be called to add additional methods or
* fields to the {@link ClassOrInterface} being built.
*
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
default Builder forEveryForeignKeyReferencingThis(BiConsumer consumer) {
return forEveryForeignKeyReferencingThis(Phase.MAKE, consumer);
}
/**
* Executes the specified code for every external {@link ForeignKey}
* document that is referencing this document during this build. This
* method could for an example be called to add additional methods or
* fields to the {@link ClassOrInterface} being built.
*
* @param phase the {@link Phase} to execute in
* @param consumer the code to apply
* @return a reference to this {@code Builder}
*/
Builder forEveryForeignKeyReferencingThis(Phase phase, BiConsumer consumer);
/**
* Builds the {@link com.speedment.common.codegen.model.Class Class},
* {@link com.speedment.common.codegen.model.Interface Interface} or
* {@link com.speedment.common.codegen.model.Enum Enum} that has been prepared
* by this {@code Builder}.
*
* @return the built instance
*/
T build();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy