/**
* Copyright 2011-2014 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.java.emitter.driver;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.asakusafw.dmdl.java.emitter.EmitContext;
import com.asakusafw.dmdl.java.spi.JavaDataModelDriver;
import com.asakusafw.dmdl.model.ModelDefinitionKind;
import com.asakusafw.dmdl.semantics.ModelDeclaration;
import com.asakusafw.dmdl.semantics.PropertyDeclaration;
import com.asakusafw.dmdl.semantics.PropertySymbol;
import com.asakusafw.dmdl.semantics.trait.JoinTrait;
import com.asakusafw.dmdl.semantics.trait.MappingFactor;
import com.asakusafw.dmdl.semantics.trait.ReduceTerm;
import com.asakusafw.utils.collections.Lists;
import com.asakusafw.utils.collections.Maps;
import com.asakusafw.utils.java.model.syntax.Annotation;
import com.asakusafw.utils.java.model.syntax.ArrayInitializer;
import com.asakusafw.utils.java.model.syntax.ClassLiteral;
import com.asakusafw.utils.java.model.syntax.Literal;
import com.asakusafw.utils.java.model.syntax.ModelFactory;
import com.asakusafw.utils.java.model.util.AttributeBuilder;
import com.asakusafw.utils.java.model.util.Models;
import com.asakusafw.vocabulary.model.Joined;
import com.asakusafw.vocabulary.model.Key;
/**
* Implements joined-model feature.
*/
public class JoinDriver extends JavaDataModelDriver {
@Override
public List<Annotation> getTypeAnnotations(EmitContext context, ModelDeclaration model) {
if (model.getOriginalAst().kind != ModelDefinitionKind.JOINED) {
return Collections.emptyList();
}
JoinTrait trait = model.getTrait(JoinTrait.class);
if (trait == null) {
throw new IllegalStateException(MessageFormat.format(
"Internal Error: joined model {0} has no JoinTrait", //$NON-NLS-1$
model.getName()));
}
ModelFactory f = context.getModelFactory();
List<Annotation> eTerms = Lists.create();
for (ReduceTerm<?> term : trait.getTerms()) {
ClassLiteral source = f.newClassLiteral(context.resolve(term.getSource()));
ArrayInitializer mappings = toMappings(context, term.getMappings());
Annotation shuffle = toKey(context, term);
eTerms.addAll(new AttributeBuilder(f)
.annotation(context.resolve(Joined.Term.class),
"source", source, //$NON-NLS-1$
"mappings", mappings, //$NON-NLS-1$
"shuffle", shuffle) //$NON-NLS-1$
.toAnnotations());
}
return new AttributeBuilder(f)
.annotation(context.resolve(Joined.class),
"terms", f.newArrayInitializer(eTerms)) //$NON-NLS-1$
.toAnnotations();
}
private ArrayInitializer toMappings(EmitContext context, List<MappingFactor> mappings) {
assert context != null;
assert mappings != null;
ModelFactory f = context.getModelFactory();
List<Annotation> eachMapping = Lists.create();
for (MappingFactor factor : mappings) {
String source = context.getFieldName(factor.getSource().findDeclaration()).getToken();
String target = context.getFieldName(factor.getTarget().findDeclaration()).getToken();
eachMapping.addAll(new AttributeBuilder(f)
.annotation(context.resolve(Joined.Mapping.class),
"source", Models.toLiteral(f, source), //$NON-NLS-1$
"destination", Models.toLiteral(f, target)) //$NON-NLS-1$
.toAnnotations());
}
return f.newArrayInitializer(eachMapping);
}
private Annotation toKey(EmitContext context, ReduceTerm<?> term) {
assert context != null;
assert term != null;
ModelFactory f = context.getModelFactory();
List<Literal> properties = Lists.create();
Map<String, PropertySymbol> reverseMapping = Maps.create();
for (MappingFactor mapping : term.getMappings()) {
reverseMapping.put(mapping.getTarget().getName().identifier, mapping.getSource());
}
for (PropertySymbol property : term.getGrouping()) {
PropertySymbol origin = reverseMapping.get(property.getName().identifier);
assert origin != null;
PropertyDeclaration decl = origin.findDeclaration();
properties.add(Models.toLiteral(f, context.getFieldName(decl).getToken()));
}
return new AttributeBuilder(f)
.annotation(context.resolve(Key.class),
"group", f.newArrayInitializer(properties)) //$NON-NLS-1$
.toAnnotations()
.get(0);
}
}