/* * Copyright 2011 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.annotation.processor; import java.io.IOException; import java.io.Writer; import java.util.Collection; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import com.google.gwt.user.client.rpc.IsSerializable; import com.gwtplatform.dispatch.annotation.GenDispatch; import com.gwtplatform.dispatch.annotation.In; import com.gwtplatform.dispatch.annotation.Out; import com.gwtplatform.dispatch.annotation.helper.BuilderGenerationHelper; import com.gwtplatform.dispatch.annotation.helper.GenerationHelper; import com.gwtplatform.dispatch.annotation.helper.ReflectionHelper; /** * Processes {@link GenDispatch} annotations. * <p/> * {@link GenDispatchProcessor} should only ever be called by tool infrastructure. See * {@link javax.annotation.processing.Processor} for more details. */ @SupportedAnnotationTypes("com.gwtplatform.dispatch.annotation.GenDispatch") public class GenDispatchProcessor extends GenProcessor { private static final String RPC_DISPATCH_PACKAGE = "com.gwtplatform.dispatch.rpc.shared"; @Override public void process(Element dispatchElement) { GenDispatch genDispatch = dispatchElement.getAnnotation(GenDispatch.class); generateAction(dispatchElement, genDispatch.isSecure(), genDispatch.serviceName(), genDispatch.extraActionInterfaces() ); generateResult(dispatchElement, genDispatch.extraResultInterfaces()); } protected void generateAction(Element dispatchElement, boolean isSecure, String serviceName, String extraActionInterfaces) { BuilderGenerationHelper writer = null; try { ReflectionHelper reflection = new ReflectionHelper(getEnvironment(), (TypeElement) dispatchElement); String dispatchElementSimpleName = reflection.getSimpleClassName(); String dispatchActionSimpleName = dispatchElementSimpleName + "Action"; String dispatchActionClassName = reflection.getClassName() + "Action"; printMessage("Generating '" + dispatchActionClassName + "' from '" + dispatchElementSimpleName + "'."); @SuppressWarnings("resource") Writer sourceWriter = getEnvironment().getFiler().createSourceFile(dispatchActionClassName, dispatchElement).openWriter(); writer = new BuilderGenerationHelper(sourceWriter); Collection<VariableElement> annotatedInFields = reflection.getInFields(); Collection<VariableElement> allFields = reflection.filterConstantFields(reflection.getInFields()); Collection<VariableElement> optionalFields = reflection.sortFields(In.class, reflection.getOptionalFields(In.class)); Collection<VariableElement> requiredFields = reflection.filterConstantFields(reflection.getInFields()); requiredFields.removeAll(optionalFields); writer.generatePackageDeclaration(reflection.getPackageName()); writer.generateImports(RPC_DISPATCH_PACKAGE + ".Action"); String actionInterface = "Action<" + dispatchElementSimpleName + "Result>"; writer.generateClassHeader(dispatchActionSimpleName, null, reflection.getClassRepresenter().getModifiers(), actionInterface, extraActionInterfaces ); writer.generateFieldDeclarations(annotatedInFields); if (!optionalFields.isEmpty()) { // has optional fields. writer.setWhitespaces(2); writer.generateBuilderClass(dispatchActionSimpleName, requiredFields, optionalFields); writer.resetWhitespaces(); writer.generateEmptyConstructor(dispatchActionSimpleName, Modifier.PROTECTED); if (!requiredFields.isEmpty()) { // and required fields writer.generateConstructorUsingFields(dispatchActionSimpleName, requiredFields, Modifier.PUBLIC); } writer.generateCustomBuilderConstructor(dispatchActionSimpleName, allFields); } else if (!requiredFields.isEmpty()) { // has only required fields writer.generateEmptyConstructor(dispatchActionSimpleName, Modifier.PROTECTED); writer.generateConstructorUsingFields(dispatchActionSimpleName, requiredFields, Modifier.PUBLIC); } else { // has no non-static fields writer.generateEmptyConstructor(dispatchActionSimpleName, Modifier.PUBLIC); } generateServiceNameAccessor(writer, dispatchElementSimpleName, serviceName); generateIsSecuredMethod(writer, isSecure); writer.generateFieldAccessors(annotatedInFields); writer.generateEquals(dispatchActionSimpleName, annotatedInFields); writer.generateHashCode(annotatedInFields); writer.generateToString(dispatchActionSimpleName, annotatedInFields); writer.generateFooter(); } catch (IOException e) { throw new RuntimeException(e); } finally { if (writer != null) { writer.close(); } } } protected void generateResult(Element dispatchElement, String extraResultInterfaces) { BuilderGenerationHelper writer = null; try { ReflectionHelper reflection = new ReflectionHelper(getEnvironment(), (TypeElement) dispatchElement); String dispatchElementSimpleName = reflection.getSimpleClassName(); String dispatchResultSimpleName = dispatchElementSimpleName + "Result"; String dispatchResultClassName = reflection.getClassName() + "Result"; printMessage("Generating '" + dispatchResultClassName + "' from '" + dispatchElementSimpleName + "'."); @SuppressWarnings("resource") Writer sourceWriter = getEnvironment().getFiler().createSourceFile(dispatchResultClassName, dispatchElement).openWriter(); writer = new BuilderGenerationHelper(sourceWriter); Collection<VariableElement> annotatedOutFields = reflection.getOutFields(); Collection<VariableElement> allFields = reflection.filterConstantFields(reflection.getOutFields()); Collection<VariableElement> optionalFields = reflection.sortFields(Out.class, reflection.getOptionalFields(Out.class)); Collection<VariableElement> requiredFields = reflection.filterConstantFields(reflection.getOutFields()); requiredFields.removeAll(optionalFields); writer.generatePackageDeclaration(reflection.getPackageName()); writer.generateImports( reflection.hasOptionalFields() ? IsSerializable.class.getName() : null, null, RPC_DISPATCH_PACKAGE + ".Result" ); String resultInterface = "Result"; writer.generateClassHeader(dispatchResultSimpleName, null, reflection.getClassRepresenter().getModifiers(), resultInterface, extraResultInterfaces ); writer.generateFieldDeclarations(annotatedOutFields); if (!optionalFields.isEmpty()) { writer.setWhitespaces(2); writer.generateBuilderClass(dispatchResultSimpleName, requiredFields, optionalFields, "IsSerializable"); writer.resetWhitespaces(); writer.generateEmptyConstructor(dispatchResultSimpleName, Modifier.PROTECTED); if (!requiredFields.isEmpty()) { writer.generateConstructorUsingFields(dispatchResultSimpleName, requiredFields, Modifier.PUBLIC); } writer.generateCustomBuilderConstructor(dispatchResultSimpleName, allFields); } else if (!requiredFields.isEmpty()) { writer.generateEmptyConstructor(dispatchResultSimpleName, Modifier.PROTECTED); writer.generateConstructorUsingFields(dispatchResultSimpleName, requiredFields, Modifier.PUBLIC); } else { writer.generateEmptyConstructor(dispatchResultSimpleName, Modifier.PUBLIC); } writer.generateFieldAccessors(annotatedOutFields); writer.generateEquals(dispatchResultSimpleName, annotatedOutFields); writer.generateHashCode(annotatedOutFields); writer.generateToString(dispatchResultSimpleName, annotatedOutFields); writer.generateFooter(); } catch (IOException e) { throw new RuntimeException(e); } finally { if (writer != null) { writer.close(); } } } protected void generateIsSecuredMethod(GenerationHelper writer, boolean isSecure) { writer.println(); writer.println(" @Override"); writer.println(" public boolean isSecured() {"); writer.println(" return " + isSecure + ";"); writer.println(" }"); } protected void generateServiceNameAccessor(GenerationHelper writer, String simpleClassName, String serviceName) { writer.println(); writer.println(" @Override"); writer.println(" public String getServiceName() {"); if (serviceName.isEmpty()) { writer.println(" return Action.DEFAULT_SERVICE_NAME + \"{0}\";", simpleClassName); } else { writer.println(" return \"{0}\";", serviceName); } writer.println(" }"); } }