package org.springframework.roo.addon.web.mvc.controller; import java.util.HashSet; import java.util.Set; import java.util.logging.Logger; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.text.StrTokenizer; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.springframework.roo.addon.plural.PluralMetadata; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.TypeLocationService; import org.springframework.roo.classpath.converters.JavaTypeConverter; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.metadata.MetadataService; import org.springframework.roo.model.JavaPackage; import org.springframework.roo.model.JavaType; import org.springframework.roo.project.LogicalPath; import org.springframework.roo.project.ProjectOperations; import org.springframework.roo.shell.CliAvailabilityIndicator; import org.springframework.roo.shell.CliCommand; import org.springframework.roo.shell.CliOption; import org.springframework.roo.shell.CommandMarker; import org.springframework.roo.support.logging.HandlerUtils; /** * Commands for the 'mvc controller' add-on to be used by the ROO shell. * * @author Stefan Schmidt * @since 1.0 */ @Component @Service public class ControllerCommands implements CommandMarker { private static Logger LOGGER = HandlerUtils .getLogger(ControllerCommands.class); @Reference private ControllerOperations controllerOperations; @Reference private MetadataService metadataService; @Reference private ProjectOperations projectOperations; @Reference private TypeLocationService typeLocationService; @Deprecated @CliCommand(value = "controller all", help = "Scaffold controllers for all project entities without an existing controller - deprecated, use 'web mvc setup' + 'web mvc all' instead") public void generateAll( @CliOption(key = "package", mandatory = true, optionContext = "update", help = "The package in which new controllers will be placed") final JavaPackage javaPackage) { LOGGER.warning("This command has been deprecated and will be disabled soon! Please use 'web mvc setup' followed by 'web mvc all --package ' instead."); controllerOperations.setup(); webMvcAll(javaPackage); } @Deprecated @CliAvailabilityIndicator({ "controller scaffold", "controller all" }) public boolean isNewControllerAvailable() { return controllerOperations.isNewControllerAvailable(); } @CliAvailabilityIndicator({ "web mvc all", "web mvc scaffold" }) public boolean isScaffoldAvailable() { return controllerOperations.isControllerInstallationPossible(); } @Deprecated @CliCommand(value = "controller scaffold", help = "Create a new scaffold Controller (ie where we maintain CRUD automatically) - deprecated, use 'web mvc scaffold' instead") public void newController( @CliOption(key = { "class", "" }, mandatory = true, help = "The path and name of the controller object to be created") final JavaType controller, @CliOption(key = "entity", mandatory = false, optionContext = JavaTypeConverter.PROJECT, unspecifiedDefaultValue = "*", help = "The name of the entity object which the controller exposes to the web tier") final JavaType entity, @CliOption(key = "path", mandatory = false, help = "The base path under which the controller listens for RESTful requests (defaults to the simple name of the form backing object)") final String path, @CliOption(key = "disallowedOperations", mandatory = false, help = "A comma separated list of operations (only create, update, delete allowed) that should not be generated in the controller") final String disallowedOperations) { LOGGER.warning("This command has been deprecated and will be disabled soon! Please use 'web mvc setup' followed by 'web mvc scaffold' instead."); controllerOperations.setup(); webMvcScaffold(controller, entity, path, disallowedOperations); } @CliCommand(value = "web mvc all", help = "Scaffold Spring MVC controllers for all project entities without an existing controller") public void webMvcAll( @CliOption(key = "package", mandatory = true, optionContext = "update", help = "The package in which new controllers will be placed") final JavaPackage javaPackage) { if (!javaPackage.getFullyQualifiedPackageName().startsWith( projectOperations.getTopLevelPackage( projectOperations.getFocusedModuleName()) .getFullyQualifiedPackageName())) { LOGGER.warning("Your controller was created outside of the project's top level package and is therefore not included in the preconfigured component scanning. Please adjust your component scanning manually in webmvc-config.xml"); } controllerOperations.generateAll(javaPackage); } @CliCommand(value = "web mvc scaffold", help = "Create a new scaffold Controller (ie where Roo maintains CRUD functionality automatically)") public void webMvcScaffold( @CliOption(key = { "class", "" }, mandatory = true, help = "The path and name of the controller object to be created") final JavaType controller, @CliOption(key = "backingType", mandatory = false, optionContext = JavaTypeConverter.PROJECT, unspecifiedDefaultValue = "*", help = "The name of the form backing type which the controller exposes to the web tier") final JavaType backingType, @CliOption(key = "path", mandatory = false, help = "The base path under which the controller listens for RESTful requests (defaults to the simple name of the form backing object)") String path, @CliOption(key = "disallowedOperations", mandatory = false, help = "A comma separated list of operations (only create, update, delete allowed) that should not be generated in the controller") final String disallowedOperations) { final ClassOrInterfaceTypeDetails cid = typeLocationService .getTypeDetails(backingType); if (cid == null) { LOGGER.warning("The specified entity can not be resolved to a type in your project"); return; } if (controller.getSimpleTypeName().equalsIgnoreCase( backingType.getSimpleTypeName())) { LOGGER.warning("Controller class name needs to be different from the class name of the form backing object (suggestion: '" + backingType.getSimpleTypeName() + "Controller')"); return; } final Set<String> disallowedOperationSet = new HashSet<String>(); if (!"".equals(disallowedOperations)) { final String[] disallowedOperationsTokens = new StrTokenizer( disallowedOperations, ",").getTokenArray(); for (final String operation : disallowedOperationsTokens) { if (!("create".equals(operation) || "update".equals(operation) || "delete" .equals(operation))) { LOGGER.warning("-disallowedOperations options can only contain 'create', 'update', 'delete': -disallowedOperations update,delete"); return; } disallowedOperationSet.add(operation.toLowerCase()); } } if (StringUtils.isBlank(path)) { final LogicalPath targetPath = PhysicalTypeIdentifier.getPath(cid .getDeclaredByMetadataId()); final PluralMetadata pluralMetadata = (PluralMetadata) metadataService .get(PluralMetadata.createIdentifier(backingType, targetPath)); Validate.notNull(pluralMetadata, "Could not determine plural for '" + backingType.getSimpleTypeName() + "'"); path = pluralMetadata.getPlural().toLowerCase(); } else if (path.equals("/") || path.equals("/*")) { LOGGER.warning("Your application already contains a mapping to '/' or '/*' by default. Please provide a different path."); return; } else if (path.startsWith("/")) { path = path.substring(1); } controllerOperations.createAutomaticController(controller, backingType, disallowedOperationSet, path); } }