/**
*
* 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.common.codegen;
import java.util.Collection;
import java.util.Optional;
import java.util.stream.Stream;
/**
* A hook to the generator that can be passed to various stages in the pipeline.
* Contains multiple methods for generating model-to-model or model-to-text.
*
* @author Emil Forslund
* @since 2.0
*/
public interface Generator {
/**
* Returns the {@link DependencyManager} currently being used.
*
* @return the dependency manager
*
* @see DependencyManager
*/
DependencyManager getDependencyMgr();
/**
* Returns the current rendering stack. The top element will be the one most
* recent rendered and the bottom one will be the element that was first
* passed to the generator. Elements are removed from the stack once they
* have finished rendering.
* <p>
* If an element needs to access its parent, it can call this method and
* peek on the second element from the top.
*
* @return the current rendering stack
*
* @see RenderStack
*/
RenderStack getRenderStack();
/**
* Renders the specified model into a stream of code models. This is used
* internally to provide the other interface methods.
*
* @param <A> the input type
* @param <B> the expected output type
* @param from the model to generate
* @param to the model type to transform to
* @return a stream of meta objects
*
* @see Meta
*/
<A, B> Stream<Meta<A, B>> metaOn(A from, Class<B> to);
/**
* Renders the specified model into a stream of code models. This is used
* internally to provide the other interface methods.
* <p>
* If the specified transform is not installed, an empty stream will be
* returned.
*
* @param <A> the input type
* @param <B> the expected output type
* @param from the model to generate
* @param to the model type to transform to
* @param transform the specified transform to use
* @return a stream of meta objects
*
* @see Meta
*/
default <A, B> Stream<Meta<A, B>> metaOn(
A from,
Class<B> to,
Class<? extends Transform<A, B>> transform) {
return metaOn(from, to)
.filter(meta -> transform.equals(meta.getTransform().getClass()));
}
/**
* Renders the specified model into a stream of code models. This is used
* internally to provide the other interface methods.
*
* @param <M> the model type
* @param model the model to generate
* @return a stream of meta objects
*
* @see Meta
*/
default <M> Stream<Meta<M, String>> metaOn(M model) {
return metaOn(model, String.class);
}
/**
* Renders all the specified models into a stream of code models. This is
* used internally to provide the other interface methods.
*
* @param <A> the input type
* @param models the models to generate
* @return a stream of meta objects
*
* @see Meta
*/
default <A> Stream<Meta<A, String>> metaOn(Collection<A> models) {
return models.stream().flatMap(this::metaOn);
}
/**
* Renders all the specified models into a stream of code models. This is
* used internally to provide the other interface methods.
*
* @param <A> the input type
* @param <B> the expected output type
* @param models the models to generate
* @param to the expected result type
* @return a stream of meta objects
*
* @see Meta
*/
default <A, B> Stream<Meta<A, B>> metaOn(
Collection<A> models, Class<B> to) {
return models.stream().flatMap(model -> metaOn(model, to));
}
/**
* Renders all the specified models into a stream of code models. This is
* used internally to provide the other interface methods. This will only
* return results from the specified transform.
* <p>
* If the specified transform is not installed, an empty stream will be
* returned.
*
* @param <A> the input type
* @param <B> the expected output type
* @param models the models to generate
* @param to the expected result type
* @param transform the specific transform to use
* @return a stream of meta objects
*
* @see Meta
*/
default <A, B> Stream<Meta<A, B>> metaOn(
Collection<A> models,
Class<B> to,
Class<? extends Transform<A, B>> transform) {
return metaOn(models, to)
.filter(meta -> meta.getTransform().is(transform));
}
/**
* Locates the {@link Transform} that corresponds to the specified model
* and uses it to generate a <code>String</code>. If no view is associated
* with the model type, an empty <code>Optional</code> will be returned.
*
* @param model the model
* @return the generated text if any
*/
default Optional<String> on(Object model) {
final Object m;
if (model instanceof Optional) {
final Optional<?> result = (Optional<?>) model;
if (result.isPresent()) {
m = result.get();
} else {
return Optional.empty();
}
} else {
m = model;
}
return metaOn(m).map(Meta::getResult).findAny();
}
/**
* Renders all the specified models into a stream of strings.
*
* @param <M> the model type
* @param models the models to generate
* @return a stream of meta objects
*/
default <M> Stream<String> onEach(Collection<M> models) {
return metaOn(models).map(Meta::getResult);
}
/**
* Transforms the specified model using the specified {@link Transform} from
* the specified {@link TransformFactory}.
*
* @param <A> the input type
* @param <B> the expected output type
* @param transform the transform to use
* @param model the inputed model
* @param factory the factory used when instantiating the transform
* @return the meta object if successful, else empty
*
* @see Transform
* @see TransformFactory
*/
<A, B> Optional<Meta<A, B>> transform(
Transform<A, B> transform,
A model,
TransformFactory factory);
}