All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.isomorphic.maven.mojo.reify.ImportMojo Maven / Gradle / Ivy

Go to download

An officially supported collection of goals useful for using SmartClient / SmartGWT products in a Maven environment.

There is a newer version: 1.4.5
Show newest version
package com.isomorphic.maven.mojo.reify;

import static com.isomorphic.util.ErrorMessage.Severity.ERROR;
import static com.isomorphic.util.ErrorMessage.Severity.INFO;
import static com.isomorphic.util.ErrorMessage.Severity.WARN;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.URI;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.settings.Proxy;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.isomorphic.maven.mojo.AbstractBaseMojo;
import com.isomorphic.maven.util.ArchiveUtils;
import com.isomorphic.maven.util.HttpRequestManager;
import com.isomorphic.maven.util.LoggingCountingOutputStream;
import com.isomorphic.tools.ReifyDataSourceValidator;
import com.isomorphic.util.ErrorMessage;
import com.isomorphic.util.ErrorMessage.Severity;
import com.isomorphic.util.ErrorReport;

import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.TemplateExceptionHandler;
import net.htmlparser.jericho.OutputDocument;
import net.htmlparser.jericho.Source;

/**
 * Provides for single-step download and extraction of assets hosted on the Reify platform.
 * While there is nothing to prevent a user from modifying the imported resources, changes 
 * should almost always be made using Reify and then re-imported. If necessary, use the API 
 * (e.g., RPCManager.createScreen, Canvas.getByLocalId) to modify imported screen definitions 
 * at runtime.  Imported MockDataSources can simply be replaced using e.g., SQLDataSources 
 * having the same ID in another directory - there is no reason to modify the contents of the 
 * 'mock' subdirectory.
 * 

* To encourage recommended usage, the reify-import goal takes steps to detect local changes * and fail when any are found. Refer to the {@link #skipOverwriteProtection} * parameter for details. Further, a validation step (optional, see {@link ImportMojo#skipValidationOnImport}) * attempts to detect commonly found discrepancies * between your MockDataSources and working DataSources. *

* The Reify for Developers * documentation topic contains further discussion around best practices during the design / development cycle. *

* If you've built your project using one of the Maven archetypes for either * SmartGWT * or * SmartClient, * you should have a skeleton configuration in you POM already. if not, add something like the following: * *

 * <pluginManagement>
 *     <plugins>
 *         <plugin>
 *             <groupId>com.isomorphic</groupId>
 *             <artifactId>isc-maven-plugin</artifactId>
 *             <version>1.4.0-SNAPSHOT</version>
 *             <!-- the m2pluginextras dependency will be required when skipValidationOnImport = false -->
 *             <dependencies>
 *                 <dependency>
 *                     <groupId>com.isomorphic.extras</groupId>
 *                     <artifactId>isomorphic-m2pluginextras</artifactId>
 *                    <version>${smartgwt.version}</version>
 *                 </dependency>       
 *             </dependencies>
 *         </plugin>
 *     </plugins>
 * </pluginManagement>                
 * 
 * <build>
 *     <plugins>
 *       <plugin>
 *           <groupId>com.isomorphic</groupId>
 *           <artifactId>isc-maven-plugin</artifactId>
 *           <configuration>
 *             <smartclientRuntimeDir>${project.parent.build.directory}/gwt/launcherDir/myapplication/sc</smartclientRuntimeDir>
 *             <dataSourcesDir>WEB-INF/ds/classic-models</dataSourcesDir>
 *           </configuration>
 *       </plugin>
 *     </plugins>
 * </build>
 * 
* and check that the SmartClient runtime has been extracted to the configured location * (via e.g., mvn war:exploded, mvn jetty:run). */ // Set requiresProject: false so that we can run the whole thing from an Ant project w/ no POM @Mojo(name="reify-import", requiresProject=false) public class ImportMojo extends AbstractBaseMojo { /** * The full URL of the Reify site hosting your project/s. Useful when running your own * Reify OnSite * instance, at e.g., 'http://localhost:8080/create/'. * * @since 1.4.2 */ @Parameter(property = "serverUrl", defaultValue = "https://create.reify.com") protected String serverUrl; /** * The id of a server * configuration containing authentication credentials for the * Reify site specified by {@link ImportMojo#serverUrl}, used to download exported projects. * * @since 1.4.0 */ @Parameter(property = "serverId", defaultValue = "smartclient-developer") protected String serverId; /** * The directory to which the archive is downloaded and unpacked. Note that this is * not the final destination of exported assets. For that, see {@link ImportMojo#webappDir}. * * @since 1.4.0 */ @Parameter(property = "workdir", defaultValue = "${project.build.directory}/reify") protected File workdir; /** * The directory containing web application sources. * * @since 1.4.0 */ @Parameter(property = "webappDir", defaultValue = "${project.basedir}/src/main/webapp") protected File webappDir; /** * The directory containing the Isomorphic runtime. The default value is appropriate for * the path created by a typical mvn war:exploded invocation. Alternatively, set this to * the path created by mvn jetty:run, or any other path where an appropriate SmartClient * runtime may be found. * * Note that SmartGWT users may need to change the value to something like: *

* * ${project.build.directory}/${project.build.finalName}/${gwtModuleName}/sc * * * @since 1.4.0 */ @Parameter(property = "smartclientRuntimeDir", defaultValue="${project.build.directory}/${project.build.finalName}/isomorphic") protected File smartclientRuntimeDir; /** * If true, the import process will create a JSP launcher that loads the given project/s. * The file's name and location can be configured via {@link #testJspPathname}. * * @since 1.4.0 */ @Parameter(property = "includeTestJsp", defaultValue = "false") protected boolean includeTestJsp; /** * The name (and optional path, relative to {@link #webappDir}) of the JSP launcher to be * created when {@link #includeTestJsp} is true. * * @since 1.4.0 */ @Parameter(property = "testJspPathname", defaultValue = "${projectName}.run.jsp") protected String testJspPathname; /** * If true, the import process will create an HTML launcher that loads the given project/s. * The file's name and location can be configured via {@link #testHtmlPathname}. * * @since 1.4.0 */ @Parameter(property = "includeTestHtml", defaultValue = "false") protected boolean includeTestHtml; /** * The name (and optional path, relative to {@link #webappDir}) of the HTML launcher to be * created when {@link #includeTestHtml} is true. * * @since 1.4.0 */ @Parameter(property = "testHtmlPathname", defaultValue = "${projectName}.run.html") protected String testHtmlPathname; /** * The directory, relative to {@link #webappDir}), in which your project's working * datasources (i.e., other than mocks) reside. *

* Note that this will need to conform to the webapp's server.properties * project.datasources configuration. * * @since 1.4.0 */ @Parameter(property = "dataSourcesDir", defaultValue = "WEB-INF/ds") protected String dataSourcesDir; /** * The directory, relative to {@link #webappDir}), in which exported MockDataSources * should ultimately reside. *

* Note that this will need to conform to the webapp's server.properties * project.datasources configuration. * * @since 1.4.0 */ @Parameter(property = "mockDataSourcesDir", defaultValue = "WEB-INF/ds/mock") protected String mockDataSourcesDir; /** * When true, DataSource validation will be skipped following import. The * {@link ValidateMojo} can still be executed independently at any time. * * @since 1.4.0 */ @Parameter(property = "skipValidationOnImport", defaultValue = "false") protected boolean skipValidationOnImport; /** * One of INFO, ERROR, WARN that will determine the level of severity tolerated in any * validation error. Any error at or above this threshold will result in "BUILD FAILURE". * * @since 1.4.0 */ @Parameter(property = "validationFailureThreshold", defaultValue = "ERROR") protected Severity validationFailureThreshold; /** * The directory in which exported screens should ultimately reside, relative to * {@link #webappDir}. Note that this will need to conform to the webapp's * server.properties project.ui configuration. * * @since 1.4.0 */ @Parameter(property = "uiDir", defaultValue = "WEB-INF/ui") protected String uiDir; /** * The directory to which the exported project file should ultimately reside, relative to * {@link #webappDir}. Note that this will need to conform to the webapp's * server.properties project.project configuration. * * @since 1.4.0 */ @Parameter(property="projectFileDir", defaultValue = "WEB-INF/ui") protected String projectFileDir; /** * If true, the project's welcome files will be modified to include a script block that * loads the imported project. Note that the loaded project is not drawn - for that, * refer to {@link #drawOnWelcomeFiles}. Welcome files are determined by scanning the * project's web.xml file for the standard welcome-files declaration. If none is found, * the webroot is searched for files named index.jsp and index.html. *

* Subsequent imports of other projects append the newly imported project name to the * existing one/s. * * @since 1.4.0 */ @Parameter(property="modifyWelcomeFiles", defaultValue = "false") protected boolean modifyWelcomeFiles; /** * Like {@link #modifyWelcomeFiles}, except this variant will draw the project's first * screen when all of its screens have been loaded. * * @since 1.4.0 */ @Parameter(property="drawOnWelcomeFiles", defaultValue = "false") protected boolean drawOnWelcomeFiles; /** * The name of the project as it's known by the reify.com environment. * * @since 1.4.0 */ @Parameter(property="projectName", defaultValue = "${project.artifactId}", required=true) protected String projectName; private String projectFileName; private String zipFileName; /** * When a project is imported, its screen and datasource assets are marked with a checksum * representing the contents of each file. Subsequent imports are preceded by a check to * make sure each of these checksums still match the file's content. In the event that * any do not, the import fails by default. *

* To override this behavior, you may set this parameter value to true, in * which case the file will simply be overwritten. Use this feature at your own risk. * * @since 1.4.0 */ @Parameter(property="skipOverwriteProtection", defaultValue = "false") private boolean skipOverwriteProtection; private UsernamePasswordCredentials credentials; private Configuration freemarkerConfig; private Proxy proxy; private HttpHost host; private HttpRequestManager httpWorker; public ImportMojo() { // we'll use a freemarker template to construct the request for project metadata ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), ""); freemarkerConfig = new Configuration(Configuration.VERSION_2_3_28); freemarkerConfig.setTemplateLoader(ctl); freemarkerConfig.setDefaultEncoding("UTF-8"); freemarkerConfig.setLogTemplateExceptions(false); freemarkerConfig.setWrapUncheckedExceptions(true); freemarkerConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); } /** * After ensuring there are no local modifications (unless otherwise configured), downloads * and installs Reify project contents to the local project environment. */ @Override public void execute() throws MojoExecutionException, MojoFailureException { try { setHost(serverUrl); // derive filenames from project name zipFileName = projectName + ".proj.zip"; projectFileName = projectName + ".proj.xml"; // check to make sure there are no local changes, unless configured otherwise if (! skipOverwriteProtection) { checkForLocalModifications(); } // allow explicit configuration from ImportTask (for Ant builds) if (credentials == null) { credentials = getCredentials(serverId); } if (credentials == null) { throw new MojoExecutionException("Reify credentials have not been configured. Check Maven settings for the '" + serverId + "' server."); } // allow for manual construction of the Proxy (again, for Ant builds) httpWorker = new HttpRequestManager(host, credentials, settings != null ? settings.getActiveProxy() : proxy); httpWorker.login(); // get fresh project metadata and archive from the server Document project = downloadProjectDocument(); File archive = downloadProjectArchive(project); getLog().info(String.format("Importing Reify project assets from download at '%s'...", archive.getCanonicalPath())); File unpacked = new File(workdir, projectName); ArchiveUtils.unzip(archive, unpacked); // update the new project file with checksums of file content for overwrite protection on future imports writeProjectFile(project, unpacked); // and copy the result to application source FileUtils.copyDirectory(unpacked, webappDir); // finally, if the user has for some reason decided they want us to mangle their source, do so if (modifyWelcomeFiles || drawOnWelcomeFiles) { modifyWelcomeFiles(); } // and validate whatever live datasources exist against the newly imported mocks if (! skipValidationOnImport) { getLog().info("Validating MockDataSources against any working DataSources..."); validate(); } } catch (MojoExecutionException e) { throw e; } catch (Exception e) { throw new MojoExecutionException("Import Error", e); } finally { try { httpWorker.logout(); } catch (Exception ignore) {} } } /** * Compares mock DataSources to live, logging findings and throwing an Exception if and * when the {@link #validationFailureThreshold} is exceeded. */ protected void validate() { try { ReifyDataSourceValidator validator = new ReifyDataSourceValidator(smartclientRuntimeDir.getCanonicalPath(), webappDir + "/" + dataSourcesDir); validator.setMockDataSourcesBasePath(webappDir + "/" + mockDataSourcesDir); List result = validator.verify(); boolean fail = false; if (! result.isEmpty()) { for (ErrorReport report : result) { for (String key : report.keySet()) { List errors = report.getErrors(key); for (ErrorMessage msg : errors) { String output = null; if (key.equals(report.getDataSourceId())) { output = String.format("%s: %s", report.getDataSourceId(), msg.getErrorString()); } else { output = String.format("%s.%s: %s", report.getDataSourceId(), key, msg.getErrorString()); } Severity severity = msg.getSeverity(); if (severity.compareTo(validationFailureThreshold) >= 0) { fail = true; } if (severity == INFO) { getLog().info(output); } if (msg.getSeverity() == WARN) { getLog().warn(output); } if (msg.getSeverity() == ERROR) { getLog().error(output); } } } } } else { getLog().info("No validation errors were found."); } if (fail) { throw new MojoExecutionException("Mock DataSource validation failure. Please refer to ReifyDataSourceValidator log output for detailed report."); } } catch (Exception e) { throw new RuntimeException(e); } } /** * Checks for local modifications, as documented at {@link #skipOverwriteProtection}}, * and fails when any local changes are detected. *

* Note that files are expected in the configured locations - screens in {@link #uiDir} * and datasources in {@link #mockDataSourcesDir} / {@link #dataSourcesDir} * subdirectories). * * @throws MojoExecutionException when any local changes are detected * @throws Exception on any other error */ private void checkForLocalModifications() throws MojoExecutionException, Exception { File projectFile = new File(webappDir, projectFileDir + "/" + projectFileName); if (! projectFile.exists()) { //LOGGER.info("Project file does not exist at '{}', but will be created during import.", projectFile.getCanonicalPath()); getLog().info(String.format("Project file does not exist at '%s', but will be created during import.", projectFile.getCanonicalPath())); return; } SAXReader reader = new SAXReader(); Document document = reader.read(projectFile); String msg = "File '%s' appears to have been modified since the last import. Aborting to provide an opprtunity to investigate. \n" + "You can either revert your changes, delete the file, or remove its checksum from the project file to continue. \n" + "You can also disable the check for this and all other files using the skipOverwriteProtection parameter."; List screens = getScreenNodes(document); for (Node screen : screens) { String expected = screen.valueOf("checksum"); if (expected.isEmpty()) { continue; } File file = getScreen(screen, webappDir); if (! file.exists()) { continue; } String actual = Files.asByteSource(file).hash(Hashing.sha256()).toString(); if (!actual.equals(expected)) { getLog().debug(String.format("Checksum mismatch - Expected: '%s' Actual: '%s'", expected, actual)); throw new MojoExecutionException(String.format(msg, file.getCanonicalPath())); } } List datasources = getDataSourceNodes(document); for (Node ds : datasources) { String expected = ds.valueOf("checksum"); if (expected.isEmpty()) { continue; } File file = getDataSource(ds, webappDir); if (! file.exists()) { continue; } String actual = Files.asByteSource(file).hash(Hashing.sha256()).toString(); if (!actual.equals(expected)) { getLog().debug(String.format("Checksum mismatch - Expected: '%s' Actual: '%s'", expected, actual)); throw new MojoExecutionException(String.format(msg, file.getCanonicalPath())); } } } /** * Requests the named project's metadata from the reify server. * * @return Document containing the result. * @throws Exception when any error occurs */ private Document downloadProjectDocument() throws Exception { getLog().info("Contacting server for Reify project metadata..."); HttpGet request = new HttpGet("/isomorphic/RESTHandler/hostedProjects?fileName=" + URLEncoder.encode(projectName) + "&isc_dataFormat=xml"); HttpResponse response = httpWorker.execute(request); String body = null; try { body = EntityUtils.toString(response.getEntity()); Document metadata = DocumentHelper.parseText(body); Node fileContents = metadata.selectSingleNode("//fileContents"); String project = fileContents.getText(); return DocumentHelper.parseText(project); } catch (Exception e) { getLog().error("Response from server:" + System.getProperty("line.separator") + body); throw new Exception(String.format("Unexpected response to request for project file. Check that user '%s' is able to access the project named '%s'", credentials.getUserName(), projectName)); } } private boolean isSmartGWTBuild() { // SmartGWT builds have their modules directory directly under $smartclientRuntimeDir, // as opposed to SmartClient, which expects it at $smartclientRuntimeDir/system/modules return FileUtils.getFile(smartclientRuntimeDir, "modules").exists(); } private String getIsomorphicDirPath(String relativeToPath) { String[] parentDirectories = relativeToPath.split("/"); int parentDirectoryCount = parentDirectories == null ? 0 : parentDirectories.length; String prefix = ""; for (int i=1; i < parentDirectoryCount; i++) { prefix = "../" + prefix; } String name = null; // e.g., myapplication/sc vs isomorphic if (isSmartGWTBuild()) { name = smartclientRuntimeDir.getParentFile().getName() + "/" + smartclientRuntimeDir.getName(); } else { name = smartclientRuntimeDir.getName(); } return prefix + name; } /** * Requests the named project's export archive, including all screens and all datasources, * downloads it, and saves it to {@link #workdir}. * * @param project metadata used to provide the names of requested assets * @return zip file containing the export result * @throws Exception when any error occurs */ private File downloadProjectArchive(Document project) throws Exception { Map context = new HashMap(); context.put("projectName", projectName); context.put("datasourcesDir", dataSourcesDir); context.put("mockDatasourcesDir", mockDataSourcesDir); context.put("uiDir", uiDir); context.put("projectFileDir", projectFileDir); context.put("projectFileName", projectFileName); context.put("zipFileName", zipFileName); context.put("screens", getScreenNames(project)); context.put("datasources", getDataSourceNames(project)); context.put("includeTestJsp", includeTestJsp); context.put("testJspPathname", testJspPathname); StringWriter jspWriter = new StringWriter(); freemarkerConfig.getTemplate("TestJspFileContent.ftl").process(context, jspWriter); context.put("jspFileContent", StringEscapeUtils.escapeHtml4(jspWriter.toString())); context.put("includeTestHtml", includeTestHtml); context.put("testHtmlPathname", testHtmlPathname); StringWriter htmlWriter = new StringWriter(); context.put("isomorphicDir", getIsomorphicDirPath(testHtmlPathname)); context.put("modulesDir", isSmartGWTBuild() ? "modules" : "system/modules"); freemarkerConfig.getTemplate("TestHtmlFileContent.ftl").process(context, htmlWriter); context.put("htmlFileContent", StringEscapeUtils.escapeHtml4(htmlWriter.toString())); StringWriter messageWriter = new StringWriter(); freemarkerConfig.getTemplate("ProjectExportRequestParameter.ftl").process(context, messageWriter); List params = new ArrayList(); params.add(new BasicNameValuePair("_transaction", messageWriter.toString())); HttpPost request = new HttpPost("/isomorphic/IDACall?isc_rpc=1"); request.setEntity(new UrlEncodedFormEntity(params)); getLog().info(String.format("Downloading '%s' project export from '%s'...", projectName, host.getHostName())); HttpResponse response = httpWorker.execute(request); HttpEntity entity = response.getEntity(); if (! "application/zip".equals(entity.getContentType().getValue())) { throw new MojoExecutionException("Response does not contain zip file contents:\n" + EntityUtils.toString(entity)); } FileUtils.forceMkdir(workdir); FileUtils.cleanDirectory(workdir); File zip = new File(workdir + "/" + zipFileName); OutputStream outputStream = null; try { outputStream = new LoggingCountingOutputStream(new FileOutputStream(zip), entity.getContentLength()); entity.writeTo(outputStream); } catch (Exception e) { throw new MojoExecutionException("Error writing file to '" + zip.getAbsolutePath() + "'", e); } finally { IOUtils.closeQuietly(outputStream); } return zip; } /** * Calculates checksums for every file in the downloaded archive, writes them to * the given project file, and stores the result on disk at a folder named for * {@link #projectFileDir}, relative to the given parent. * * @param project metadata used to provide the names of requested assets * @param parent the parent directory * @throws Exception whenany error occurs */ private void writeProjectFile(Document project, File parent) throws Exception { for (Node screen : getScreenNodes(project)) { File file = getScreen(screen, parent); String checksum = Files.asByteSource(file).hash(Hashing.sha256()).toString(); Element element = ((Element) screen).addElement("checksum"); element.setText(checksum); } for (Node datasource : getDataSourceNodes(project)) { File file = getDataSource(datasource, parent); String checksum = Files.asByteSource(file).hash(Hashing.sha256()).toString(); Element element = ((Element) datasource).addElement("checksum"); element.setText(checksum); } // pretty print the file with changes File projectFile = FileUtils.getFile(parent, projectFileDir, projectFileName); OutputFormat purdy = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter(new FileWriter(projectFile), purdy); writer.write(project); writer.flush(); writer.close(); } private void modifyWelcomeFiles() throws Exception { File welcomeFilesConfig = new File(webappDir, "WEB-INF/web.xml"); if (! welcomeFilesConfig.exists()) { String msg = String.format("No web.xml found at '%s'", welcomeFilesConfig.getCanonicalPath()); throw new RuntimeException(msg); } List welcomeFiles = new ArrayList(); SAXReader reader = new SAXReader(); Document webXml = reader.read(welcomeFilesConfig); XPath xpath = webXml.createXPath("//jee:welcome-file"); xpath.setNamespaceURIs(ImmutableMap.of("jee", "http://java.sun.com/xml/ns/javaee")); List list = xpath.selectNodes(webXml); for (Node node : list) { String val = node.getStringValue(); File file = FileUtils.getFile(webappDir, val); if (! file.exists()) { getLog().warn(String.format("Welcome file '{}' not found. Skipping.", val)); continue; } welcomeFiles.add(file); } if (welcomeFiles.isEmpty()) { File jsp = FileUtils.getFile(webappDir, "index.jsp"); File html = FileUtils.getFile(webappDir, "index.html"); if (jsp.exists()) { welcomeFiles.add(jsp); } if (html.exists()) { welcomeFiles.add(html); } } for (File file : welcomeFiles) { String extension = FilenameUtils.getExtension(file.getCanonicalPath()).toLowerCase(); Source source=new Source(file); OutputDocument target=new OutputDocument(source); net.htmlparser.jericho.Element scriptElement = source.getElementById("isc-maven-plugin.reify-import.modifyWelcomeFiles"); Set projectNames = new LinkedHashSet(); if (scriptElement != null) { if ("jsp".equals(extension)) { String html = scriptElement.toString().trim(); int start = html.toLowerCase().indexOf("name=\"") + 6; int end = html.indexOf("\"", start); String val = html.substring(start, end); projectNames.addAll(Sets.newHashSet(val.split(","))); } else { String src = scriptElement.getAttributeValue("src"); int start = src.indexOf("projectName=") + 12; int end = src.indexOf("&", start); String val = src.substring(start, end); projectNames.addAll(Sets.newHashSet(val.split(","))); } } projectNames.add(projectName); String template = "LoadProjectScriptFragment.ftl"; if ("jsp".equals(extension)) { template = "LoadProjectTagFragment.ftl"; } Map context = ImmutableMap.of( "isomorphicDir", getIsomorphicDirPath(testHtmlPathname), "projects", projectNames.toArray(), "draw", drawOnWelcomeFiles); StringWriter tagWriter = new StringWriter(); freemarkerConfig.getTemplate(template).process(context, tagWriter); if (scriptElement != null) { target.replace(scriptElement, tagWriter.toString()); } else { // for now just drop the script at the end of the body int index = source.getFirstElement("body").getEndTag().getBegin(); target.insert(index, tagWriter.toString()); } FileUtils.write(file, target.toString()); } } /* * Convenience methods for returning various representations of screens from xml document */ private List getScreenNodes(Document project) { return project.selectNodes("/Project/screens/root/children/TreeNode"); } private List getScreenNames(Document project) { List nodes = getScreenNodes(project); List names = new ArrayList(); for (Node node : nodes) { names.add(getScreenName(node)); } return names; } private String getScreenName(Node screen) { return screen.valueOf("fileName"); } private File getScreen(Node metadata, File parent) { return FileUtils.getFile(parent, uiDir, getScreenName(metadata) + ".ui.xml"); } /* * Convenience methods for returning various representations of datasources from xml doc */ private List getDataSourceNodes(Document project) { return project.selectNodes("/Project/datasources/Record"); } private List getDataSourceNames(Document project) { List nodes = getDataSourceNodes(project); List names = new ArrayList(); for (Node node : nodes) { names.add(getDataSourceName(node)); } return names; } private String getDataSourceName(Node ds) { return ds.valueOf("dsName"); } private File getDataSource(Node metadata, File parent) { String name = getDataSourceName(metadata); // Check 'mock' subdirectory first, fallback to datasourcesDir if not found. File file = FileUtils.getFile(parent, mockDataSourcesDir, name + ".ds.xml"); if (! file.exists()) { file = FileUtils.getFile(parent, dataSourcesDir, name + ".ds.xml"); } return file; } /* * Setters to allow execution from an Ant build (ImportTask) */ protected void setHost(String uri) { this.host = URIUtils.extractHost(URI.create(uri)); } protected void setWorkdir(File workdir) { this.workdir = workdir; } protected void setWebappDir(File webappDir) { this.webappDir = webappDir; } protected void setSmartclientRuntimeDir(File smartclientRuntimeDir) { this.smartclientRuntimeDir = smartclientRuntimeDir; } protected void setIncludeTestJsp(boolean includeTestJsp) { this.includeTestJsp = includeTestJsp; } protected void setTestJspPathname(String testJspPathname) { this.testJspPathname = testJspPathname; } protected void setIncludeTestHtml(boolean includeTestHtml) { this.includeTestHtml = includeTestHtml; } protected void setTestHtmlPathname(String testHtmlPathname) { this.testHtmlPathname = testHtmlPathname; } protected void setDataSourcesDir(String dataSourcesDir) { this.dataSourcesDir = dataSourcesDir; } protected void setMockDataSourcesDir(String mockDataSourcesDir) { this.mockDataSourcesDir = mockDataSourcesDir; } protected void setSkipValidationOnImport(boolean skipValidationOnImport) { this.skipValidationOnImport = skipValidationOnImport; } protected void setValidationFailureThreshold(Severity validationFailureThreshold) { this.validationFailureThreshold = validationFailureThreshold; } protected void setUiDir(String uiDir) { this.uiDir = uiDir; } protected void setProjectFileDir(String projectFileDir) { this.projectFileDir = projectFileDir; } protected void setModifyWelcomeFiles(boolean modifyWelcomeFiles) { this.modifyWelcomeFiles = modifyWelcomeFiles; } protected void setDrawOnWelcomeFiles(boolean drawOnWelcomeFiles) { this.drawOnWelcomeFiles = drawOnWelcomeFiles; } protected void setProjectName(String projectName) { this.projectName = projectName; } protected void setProjectFileName(String projectFileName) { this.projectFileName = projectFileName; } protected void setZipFileName(String zipFileName) { this.zipFileName = zipFileName; } protected void setSkipOverwriteProtection(boolean skipOverwriteProtection) { this.skipOverwriteProtection = skipOverwriteProtection; } protected void setCredentials(UsernamePasswordCredentials credentials) { this.credentials = credentials; } protected void setProxy(Proxy proxy) { this.proxy = proxy; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy