com.gwtplatform.dispatch.rest.delegates.rebind.DelegateGenerator.java Source code

Java tutorial

Introduction

Here is the source code for com.gwtplatform.dispatch.rest.delegates.rebind.DelegateGenerator.java

Source

/**
 * Copyright 2014 ArcBees Inc.
 *
 * 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.gwtplatform.dispatch.rest.delegates.rebind;

import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.inject.Inject;
import javax.ws.rs.Path;

import org.apache.velocity.app.VelocityEngine;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JGenericType;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.gwtplatform.dispatch.rest.delegates.client.ResourceDelegate;
import com.gwtplatform.dispatch.rest.rebind.AbstractVelocityGenerator;
import com.gwtplatform.dispatch.rest.rebind.GeneratorWithInput;
import com.gwtplatform.dispatch.rest.rebind.events.RegisterGinBindingEvent;
import com.gwtplatform.dispatch.rest.rebind.resource.MethodDefinition;
import com.gwtplatform.dispatch.rest.rebind.resource.MethodGenerator;
import com.gwtplatform.dispatch.rest.rebind.resource.ResourceDefinition;
import com.gwtplatform.dispatch.rest.rebind.utils.ClassDefinition;
import com.gwtplatform.dispatch.rest.rebind.utils.Logger;
import com.gwtplatform.dispatch.rest.shared.RestAction;

import static com.gwtplatform.dispatch.rest.rebind.utils.Generators.findGenerator;

public class DelegateGenerator extends AbstractVelocityGenerator
        implements GeneratorWithInput<ResourceDefinition, DelegateDefinition> {
    static final String IMPL = "Delegate";

    private static final String TEMPLATE = "com/gwtplatform/dispatch/rest/delegates/rebind/Delegate.vm";

    private final EventBus eventBus;
    private final Set<MethodGenerator> methodGenerators;
    private final List<ClassDefinition> generatedDelegates;

    private ResourceDefinition resourceDefinition;
    private List<MethodDefinition> methodDefinitions;
    private Set<String> imports;

    @Inject
    DelegateGenerator(Logger logger, GeneratorContext context, VelocityEngine velocityEngine, EventBus eventBus,
            Set<MethodGenerator> methodGenerators) {
        super(logger, context, velocityEngine);

        this.eventBus = eventBus;
        this.methodGenerators = methodGenerators;
        this.generatedDelegates = Lists.newArrayList();
    }

    @Override
    public boolean canGenerate(ResourceDefinition resourceDefinition) {
        this.resourceDefinition = resourceDefinition;

        return !generatedDelegates.contains(getClassDefinition());
    }

    @Override
    public DelegateDefinition generate(ResourceDefinition resourceDefinition) throws UnableToCompleteException {
        this.resourceDefinition = resourceDefinition;

        imports = Sets.newTreeSet();
        imports.add(RestAction.class.getName());
        imports.add(resourceDefinition.getResourceInterface().getQualifiedSourceName());
        imports.add(resourceDefinition.getQualifiedName());

        methodDefinitions = Lists.newArrayList();

        generateMethods();

        PrintWriter printWriter = tryCreate();
        mergeTemplate(printWriter);
        commit(printWriter);

        maybeRegisterGinBinding();

        DelegateDefinition definition = new DelegateDefinition(getPackageName(), getImplName(), resourceDefinition,
                methodDefinitions);
        generatedDelegates.add(definition);
        return definition;
    }

    @Override
    protected String getTemplate() {
        return TEMPLATE;
    }

    @Override
    protected String getPackageName() {
        return resourceDefinition.getPackageName();
    }

    @Override
    protected String getImplName() {
        return resourceDefinition.getResourceInterface().getName() + IMPL;
    }

    @Override
    protected void populateTemplateVariables(Map<String, Object> variables) {
        JClassType resourceInterface = resourceDefinition.getResourceInterface();

        variables.put("resourceType", new ClassDefinition(resourceInterface).getParameterizedClassName());
        variables.put("methods", methodDefinitions);
        variables.put("imports", imports);
    }

    private void generateMethods() throws UnableToCompleteException {
        for (MethodDefinition methodDefinition : resourceDefinition.getMethodDefinitions()) {
            generateMethod(methodDefinition);
        }
    }

    private void generateMethod(MethodDefinition methodDefinition) throws UnableToCompleteException {
        DelegatedMethodContext context = new DelegatedMethodContext(resourceDefinition, methodDefinition);
        MethodGenerator generator = findGenerator(methodGenerators, context);

        if (generator != null) {
            MethodDefinition delegatedDefinition = generator.generate(context);

            methodDefinitions.add(delegatedDefinition);
            imports.addAll(delegatedDefinition.getImports());
        } else {
            getLogger().die("Unable to find a delegated method generator for `%s#%s`",
                    resourceDefinition.getQualifiedName(), methodDefinition.getMethod().getName());
        }
    }

    private void maybeRegisterGinBinding() throws UnableToCompleteException {
        if (!isSubResource()) {
            JGenericType resourceDelegateType = getType(ResourceDelegate.class).isGenericType();
            JParameterizedType parameterizedResourceDelegateType = getContext().getTypeOracle()
                    .getParameterizedType(resourceDelegateType,
                            new JClassType[] { resourceDefinition.getResourceInterface() });
            ClassDefinition definition = new ClassDefinition(parameterizedResourceDelegateType);

            RegisterGinBindingEvent.postSingleton(eventBus, definition, getClassDefinition());
        }
    }

    private boolean isSubResource() {
        return !resourceDefinition.getResourceInterface().isAnnotationPresent(Path.class);
    }
}