mx.itesm.imb.ImbOperationsImpl.java Source code

Java tutorial

Introduction

Here is the source code for mx.itesm.imb.ImbOperationsImpl.java

Source

/*
 * Copyright 2011 jccastrejon
 *  
 * This file is part of InstanceModelBus.
 *
 * InstanceModelBus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * InstanceModelBus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
    
 * You should have received a copy of the GNU General Public License
 * along with InstanceModelBus.  If not, see <http://www.gnu.org/licenses/>.
*/
package mx.itesm.imb;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.SortedSet;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.io.FileUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.springframework.roo.file.monitor.event.FileDetails;
import org.springframework.roo.metadata.MetadataService;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.project.Dependency;
import org.springframework.roo.project.Path;
import org.springframework.roo.project.PathResolver;
import org.springframework.roo.project.ProjectMetadata;
import org.springframework.roo.project.ProjectOperations;
import org.springframework.roo.support.util.FileCopyUtils;
import org.springframework.roo.support.util.TemplateUtils;

/**
 * Implementation of IMB commands that are available via the Roo shell.
 */
@Component
@Service
public class ImbOperationsImpl implements ImbOperations {
    private static Logger logger = Logger.getLogger(ImbOperations.class.getName());

    @Reference
    private MetadataService metadataService;

    @Reference
    private PathResolver pathResolver;

    @Reference
    private FileManager fileManager;

    @Reference
    private ProjectOperations projectOperations;

    /**
     * ImbAspect velocity template.
     */
    private static Template aspectTemplate;

    /**
     * JAXB schemagen ant build file.
     */
    private static File schemagenBuildFile;

    static {
        try {
            ImbOperationsImpl.aspectTemplate = ImbOperationsImpl.getVelocityTemplate();
            ImbOperationsImpl.schemagenBuildFile = new File(
                    "/Users/jccastrejon/java/workspace_IMB/InstanceModelBus.Roo/src/main/resources/schemagen.xml");
        } catch (Exception e) {
            logger.log(Level.SEVERE, e.getMessage());
        }
    }

    public static Template getVelocityTemplate() throws Exception {
        Template returnValue;
        Properties velocityProperties;

        // TODO: Change to class-path search:.
        velocityProperties = new Properties();
        velocityProperties.put("resource.loader", "file");
        velocityProperties.put("file.resource.loader.class",
                "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
        velocityProperties.put("file.resource.loader.path",
                "/Users/jccastrejon/java/workspace_IMB/InstanceModelBus.Roo/src/main/resources");
        velocityProperties.put("file.resource.loader.cache", "true");
        Velocity.init(velocityProperties);

        returnValue = Velocity.getTemplate("ImbAspect.vml");
        return returnValue;
    }

    public boolean isUpdateControllersAvailable() {
        return metadataService.get(ProjectMetadata.getProjectIdentifier()) != null;
    }

    /**
     * @see mx.itesm.imb.ImbCommands#updateControllers()
     */
    public void updateControllers() {
        String antPath;
        String packageName;
        File controllerFile;
        FileDetails srcRoot;
        File configurationFile;
        String configurationPath;
        String configurationContents;
        SortedSet<FileDetails> entries;

        // Identify mvc-controllers
        antPath = pathResolver.getRoot(Path.SRC_MAIN_JAVA) + File.separatorChar + "**" + File.separatorChar
                + "*Controller.java";
        srcRoot = new FileDetails(new File(pathResolver.getRoot(Path.SRC_MAIN_JAVA)), null);
        entries = fileManager.findMatchingAntPath(antPath);

        // Update mvc-controller's methods to allow communication with the IMB
        for (FileDetails file : entries) {
            try {
                controllerFile = file.getFile();
                packageName = srcRoot.getRelativeSegment(file.getCanonicalPath()).replace(File.separatorChar, '.');
                packageName = packageName.substring(1).substring(0, packageName.lastIndexOf('.') - 1); // java
                packageName = packageName.substring(0, packageName.lastIndexOf('.')); // className
                this.writeImbAspect(
                        controllerFile.getName().substring(0, controllerFile.getName().indexOf(".java")),
                        packageName, controllerFile.getParentFile().getAbsolutePath());
                logger.log(Level.INFO, file.getCanonicalPath() + " controller updated");
            } catch (Exception e) {
                logger.log(Level.SEVERE,
                        "Error while updating " + file.getCanonicalPath() + " controller: " + e.getMessage());
            }
        }

        // Update Rest configuration
        try {
            configurationFile = new File(pathResolver.getRoot(Path.SRC_MAIN_RESOURCES)
                    + "/META-INF/spring/applicationContext-contentresolver.xml");
            configurationContents = FileUtils.readFileToString(configurationFile);

            // TODO: Change to classpath search
            configurationContents = configurationContents.replace("</beans>",
                    FileUtils.readFileToString(new File(
                            "/Users/jccastrejon/java/workspace_IMB/InstanceModelBus.Roo/src/main/resources",
                            "RestTemplate.vml")) + "</beans>");
            FileUtils.writeStringToFile(configurationFile, configurationContents);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Error updating Rest configuration: " + e.getMessage());
        }

        // Configuration file
        try {
            configurationPath = pathResolver.getIdentifier(Path.SRC_MAIN_RESOURCES,
                    "/mx/itesm/imb/configuration.properties");
            this.createFile(configurationPath, "configuration_template.properties");
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Error updating configuration file: " + e.getMessage());
        }
    }

    /**
     * @see mx.itesm.imb.ImbCommands#generateEntitiesSchemas()
     */
    @SuppressWarnings("unchecked")
    public void generateEntitiesSchemas() {
        String tns;
        int tnsIndex;
        File srcFile;
        String antPath;
        int processCode;
        Process process;
        File schemaFile;
        File schemasDir;
        String entityName;
        String packageName;
        File schemagenFile;
        int rootElementIndex;
        String rootElementName;
        List<String> enumNames;
        String schemagenContents;
        String schemaFileContents;
        List<String> outputContents;
        SortedSet<FileDetails> entries;
        List<String> typesSchemaContents;
        List<String> detailsSchemaContents;

        try {
            // Identify the classes that should generate schemas
            antPath = pathResolver.getRoot(Path.SRC_MAIN_JAVA) + File.separatorChar + "**" + File.separatorChar
                    + "*_Roo_JavaBean.aj";
            entries = fileManager.findMatchingAntPath(antPath);

            // Clean directory where the schemas will be generated
            schemasDir = new File(pathResolver.getRoot(Path.SRC_MAIN_JAVA) + "/schema_temp");

            // Generate Java Beans for the identified schemas
            for (FileDetails file : entries) {
                srcFile = file.getFile();
                entityName = srcFile.getName().replace("_Roo_JavaBean.aj", "");
                outputContents = new ArrayList<String>();

                // Format file
                packageName = "";
                for (String line : (List<String>) FileUtils.readLines(srcFile)) {
                    // Remove annotations
                    if (!line.contains("@")) {
                        // Change form aspect to class declaration
                        if (line.startsWith("privileged")) {
                            outputContents.add("@javax.xml.bind.annotation.XmlRootElement(namespace =\"http://"
                                    + packageName + "\")\n");
                            outputContents.add(line.replace("privileged", "public").replace("aspect", "class")
                                    .replace("_Roo_JavaBean", ""));
                        } else {
                            // Remove aspect details
                            outputContents.add(line.replace(entityName + ".", ""));
                        }
                    }

                    if (line.startsWith("package")) {
                        packageName = line.replace("package", "").replace(";", "").trim() + ".imb";
                    }
                }

                // Write file
                FileUtils.writeLines(new File(schemasDir, entityName + ".java"), outputContents);
                logger.log(Level.INFO, "Generating XML schema for " + srcFile);
            }

            // Copy enum types to avoid compilation errors
            antPath = pathResolver.getRoot(Path.SRC_MAIN_JAVA) + File.separatorChar + "**" + File.separatorChar
                    + "*.java";
            entries = fileManager.findMatchingAntPath(antPath);
            enumNames = new ArrayList<String>();
            for (FileDetails file : entries) {
                if (FileUtils.readFileToString(file.getFile()).contains("enum")) {
                    enumNames.add(file.getFile().getName().replace(".java", "").toLowerCase());
                    FileUtils.copyFile(file.getFile(), new File(schemasDir, file.getFile().getName()));
                }
            }

            // Execute schemagen
            schemagenFile = new File(schemasDir, "build.xml");
            schemagenContents = FileUtils.readFileToString(ImbOperationsImpl.schemagenBuildFile);
            schemagenContents = schemagenContents.replace("${output.dir}", schemasDir.getAbsolutePath());
            schemagenContents = schemagenContents.replace("${src.dir}", schemasDir.getAbsolutePath());
            FileUtils.writeStringToFile(schemagenFile, schemagenContents);
            process = Runtime.getRuntime().exec("ant -buildfile " + schemagenFile.getAbsolutePath());
            processCode = process.waitFor();

            // Error while executing schemagen
            if (processCode != 0) {
                throw new RuntimeException();
            }

            // Merge schemas and clean up
            typesSchemaContents = FileUtils.readLines(new File(schemasDir, "schema1.xsd"));
            detailsSchemaContents = FileUtils.readLines(new File(schemasDir, "schema2.xsd"));
            outputContents = new ArrayList<String>(typesSchemaContents.size() + detailsSchemaContents.size());

            // Elements
            for (String line : typesSchemaContents) {
                if (!line.contains("<xs:import") && !line.contains("</xs:schema")) {
                    if (line.contains("<xs:schema")) {
                        tnsIndex = line.indexOf("targetNamespace=") + "targetNamespace=".length() + 1;
                        tns = line.substring(tnsIndex, line.indexOf("\"", tnsIndex));
                        logger.log(Level.INFO, "index: " + tnsIndex + ", tns: " + tns);
                        outputContents.add(line.substring(0, line.length() - 1) + " xmlns:tns=\"" + tns + "\">");
                    } else {
                        outputContents.add(line.replace("type=\"", "type=\"tns:"));
                    }
                }
            }

            // Details
            for (String line : detailsSchemaContents) {
                if (!line.contains("<xs:import") && !line.contains("<?xml") && !line.contains("<xs:schema")) {
                    if (line.contains("type=")) {
                        // References to other types in the same schema
                        if (!line.contains("type=\"xs:")) {
                            outputContents.add(line.replace("type=\"", "type=\"tns:"));
                        } else {
                            outputContents.add(line);
                        }
                    } else {
                        outputContents.add(line);
                        // IMB Id
                        if (line.contains("<xs:sequence")) {
                            outputContents.add("<xs:element name=\"imbId\" type=\"xs:long\" minOccurs=\"0\"/>");
                        }
                    }
                }
            }

            // Schema file
            schemaFile = new File(pathResolver.getRoot(Path.SRC_MAIN_RESOURCES), "/schema.xsd");
            FileUtils.writeLines(schemaFile, outputContents);

            // Root element
            schemaFileContents = FileUtils.readFileToString(schemaFile);
            rootElementIndex = schemaFileContents.indexOf("xs:element name=\"");
            rootElementName = schemaFileContents.substring(rootElementIndex + "xs:element name=\"".length(),
                    schemaFileContents.indexOf("\"", rootElementIndex + "xs:element name=\"".length() + 1));
            schemaFileContents = schemaFileContents.replace("type=\"tns:" + rootElementName + "\"/>", ">");
            schemaFileContents = schemaFileContents.replace("<xs:complexType name=\"" + rootElementName + "\">",
                    "<xs:complexType>");
            schemaFileContents = schemaFileContents.replace("</xs:complexType>", "</xs:complexType></xs:element>");
            FileUtils.writeStringToFile(schemaFile, schemaFileContents);

            FileUtils.forceDelete(schemasDir);
            logger.log(Level.INFO, "XML schemas correctly generated");
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Error while generating entities schemas: " + e.getMessage(), e);
        }
    }

    /**
     * @see mx.itesm.imb.ImbCommands#generatedNotificationScheduling()
     */
    public void generatedNotificationScheduling() {
        String schedulingTask;
        File schedulingTaskFile;
        String schedulingTaskContents;
        String schedulingConfiguration;
        ProjectMetadata projectMetadata;

        // Add quartz configuration
        projectOperations.addDependency(new Dependency("opensymphony", "quartz", "1.6.0"));

        // Add http-client configuration
        projectOperations.addDependency(new Dependency("commons-httpclient", "commons-httpclient", "3.1"));

        // Copy configuration and task files
        schedulingConfiguration = pathResolver.getIdentifier(Path.SPRING_CONFIG_ROOT,
                "applicationContext-scheduling.xml");
        schedulingTask = pathResolver.getIdentifier(Path.SRC_MAIN_JAVA, "/mx/itesm/imb/NotificationTask.java");
        this.createFile(schedulingConfiguration, "applicationContext_scheduling_template.xml");
        this.createFile(schedulingTask, "NotificationTask_template.java");

        // Replace type packages
        try {
            schedulingTaskFile = new File(schedulingTask);
            projectMetadata = (ProjectMetadata) metadataService.get(ProjectMetadata.getProjectIdentifier());
            schedulingTaskContents = FileUtils.readFileToString(schedulingTaskFile);
            schedulingTaskContents = schedulingTaskContents.replace("$typePackage",
                    projectMetadata.getTopLevelPackage().getFullyQualifiedPackageName());
            FileUtils.writeStringToFile(schedulingTaskFile, schedulingTaskContents);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * 
     * @param fileIdentifier
     * @param templateName
     */
    private void createFile(final String fileIdentifier, final String templateName) {
        if (!fileManager.exists(fileIdentifier)) {
            try {
                FileCopyUtils.copy(TemplateUtils.getTemplate(getClass(), templateName),
                        fileManager.createFile(fileIdentifier).getOutputStream());
            } catch (IOException ioe) {
                throw new IllegalStateException(ioe);
            }
        }
    }

    /**
     * 
     * @param controllerName
     * @param controllerPath
     * @throws IOException
     * @throws MethodInvocationException
     * @throws ParseErrorException
     * @throws ResourceNotFoundException
     */
    private void writeImbAspect(final String controllerName, final String packageName, final String controllerPath)
            throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, IOException {
        Writer writer;
        VelocityContext context;
        List<String> packageNames;
        StringBuilder imbTypePackage;

        // Imb Type package name
        imbTypePackage = new StringBuilder("imb.");
        packageNames = Arrays.asList(packageName.replace("web", "domain").split("\\."));
        Collections.reverse(packageNames);
        for (int i = 0; i < packageNames.size(); i++) {
            imbTypePackage.append(packageNames.get(i));
            if (i < (packageNames.size() - 1)) {
                imbTypePackage.append(".");
            }
        }

        // Velocity configuration
        context = new VelocityContext();
        context.put("controllerPackage", packageName);
        context.put("controllerType", controllerName);
        context.put("type", controllerName.replace("Controller", ""));
        context.put("typePackage", packageName.replace("web", "domain"));
        context.put("imbTypePackage", imbTypePackage.toString());

        writer = new FileWriter(new File(controllerPath, controllerName + "_Roo_Imb.aj"));
        ImbOperationsImpl.aspectTemplate.merge(context, writer);
        writer.close();
    }
}