/* * Copyright 2012 Joseph Spencer. * * 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.spencernetdevelopment; import com.spencernetdevelopment.arguments.StaticPagesArguments; import com.spencernetdevelopment.arguments.StaticPagesTerminal; import static com.spencernetdevelopment.Logger.*; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Scanner; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.xml.XMLConstants; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; /** * * @author Joseph Spencer */ public class StaticPages { public static FilePath jarDir; /** * @param args the command line arguments */ public static void main(String[] args) { try { final FileUtils fileUtils = new FileUtils(); String argumentsXmlPathString = StaticPages.class. getResource("/arguments.xml").getPath(). replaceAll("^(?:file:)?(?:/(?=[A-Z]:/))?|^jar:|![^!]+$", ""); final StaticPagesArguments arguments = StaticPagesTerminal.getArguments(args); final StaticPagesConfiguration builtConfig = buildStaticPagesConfiguration(arguments); final FilePath buildDirPath = builtConfig.getBuildDirPath(); final FilePath projectDirPath = builtConfig.getProjectDirPath(); Logger.isDebug = arguments.getEnableloggingdebug(); Logger.isError = arguments.getEnableloggingerror(); Logger.isFatal = arguments.getEnableloggingfatal(); Logger.isInfo = arguments.getEnablelogginginfo(); Logger.isWarn = arguments.getEnableloggingwarn(); if(arguments.hasLogginglevel()){ switch(arguments.getLogginglevel()){ case 0: case 1: case 2: case 3: case 4: case 5: Logger.logLevel = arguments.getLogginglevel(); break; default: Logger.fatal( "Invalid argument for logging level.\n"+ "Expecting one of 0, 1, 2, 3, 4 or 5.", 1 ); } } if(isDebug)debug("user.dir: "+System.getProperty("user.dir")); if(isDebug)debug("user.home: "+System.getProperty("user.home")); if(isDebug)debug("user.name: "+System.getProperty("user.name")); if(isDebug)debug("path to arguments.xml: "+argumentsXmlPathString); FilePath argumentsXmlFilePath = FilePath.getFilePath(argumentsXmlPathString); jarDir = argumentsXmlFilePath.getParent(); if(isDebug)debug("jarDir = "+jarDir.toString()); if(arguments.getClean()){ fileUtils.clearDirectory(buildDirPath.toFile()); } if(arguments.hasNewproject()){ File sampleProjectDir = jarDir.resolve("project-template").toFile(); if(isDebug)debug("sample project dir: "+sampleProjectDir.getAbsolutePath()); if(!sampleProjectDir.exists()){ fatal("Couldn't create a new project. The project-template wasn't found next to the jar.", 1); } fileUtils.copyDirContentsToDir(sampleProjectDir, arguments.getNewproject()); info("project-template copied to: "+arguments.getNewproject().toPath()); } if(arguments.hasProjectdir()){ showFilePathDebugStatements(builtConfig); if(!buildDirPath.toFile().isDirectory()){ if(isDebug)debug("buildDir didn't exist. Creating it now..."); fileUtils.createDir(buildDirPath.toFile()); } FilePath defaultStylesheet = projectDirPath.resolve("src/xsl/pages/default.xsl"); if(isDebug)debug("defaultStylesheet: "+defaultStylesheet.toString()); if(!defaultStylesheet.toFile().isFile()){ fatal("No default stylesheet found.", 1); } ExecutorService executorService = Executors.newCachedThreadPool(); AssetResolver assetResolver = new AssetResolver(builtConfig); AssetManager assetManager = new AssetManager( builtConfig.getAssetsDirPath(), buildDirPath, fileUtils, builtConfig, assetResolver ); BreadcrumbFactory breadcrumbFactory = new BreadcrumbFactory(); FileIteratorFactory fileIteratorFactory = new FileIteratorFactory( builtConfig.getAssetsDirPath(), fileUtils ); Extensions extensions = new Extensions( breadcrumbFactory, fileIteratorFactory ); GroupedAssetTransactionManager groupedAssetTransactionManager = new GroupedAssetTransactionManager( assetManager, assetResolver, builtConfig, new FileUtils() ); RewriteManager rewriteManager = new RewriteManager( buildDirPath, fileUtils ); StreamSource pageXSD = new StreamSource( StaticPages.class.getResourceAsStream("/page.xsd")); SchemaFactory schemaFactory = SchemaFactory .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schemaFile = schemaFactory.newSchema(pageXSD); System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.icl.saxon.om.DocumentBuilderFactoryImpl"); DefaultNamespaceContext defaultNamespaceContext = new DefaultNamespaceContext(); Map<String, ExternalLinkValidator<Object>> validators = Collections .synchronizedMap(new HashMap<String, ExternalLinkValidator<Object>>()); LinkValidator linkValidator = new LinkValidator( validators, builtConfig, defaultNamespaceContext ); HTMLBuilderVisitorImpl htmlBuilderVisitor = new HTMLBuilderVisitorImpl( assetManager, assetResolver, extensions, rewriteManager, builtConfig, groupedAssetTransactionManager, linkValidator ); HTMLBuilder htmlBuilder = new HTMLBuilder( buildDirPath, builtConfig.getPagesDirPath(), getVariables(arguments), fileUtils, schemaFile, builtConfig, htmlBuilderVisitor ); htmlBuilder.setDefaultStylesheet(defaultStylesheet.toFile()); /* * We want to invoke all HTML tasks right away. LinkValidation * and other tasks are driven by analysis that is done during the * compiling of HTML. */ info("Building all pages..."); List<Callable<Object>> htmlTasks = htmlBuilder.getHTMLTasks(); synchronized(htmlTasks){ List<Future<Object>> results = executorService.invokeAll(htmlTasks); for(Future<Object> result: results){ result.get();//force exceptions to be thrown. } } info("Finished building pages."); List<Callable<Object>> postOperations = new ArrayList<>(); synchronized(validators){ if( arguments.getEnableexternallinkvalidation() && validators.size() > 0 ){ for(Callable<Object> obj:validators.values()){ postOperations.add(obj); } } } List<GroupedAssetTask<Object>> groupedAssetTasks = groupedAssetTransactionManager.getGroupedAssetTasks(); synchronized(groupedAssetTasks){ if(groupedAssetTasks.size() > 0){ for(Callable<Object> obj: groupedAssetTasks){ postOperations.add(obj); } } } if(postOperations.size() > 0){ List<Future<Object>> results = executorService.invokeAll(postOperations); for(Future<Object> result: results){ result.get();//force exceptions to be thrown } } executorService.shutdown(); rewriteManager.applyRewrites(); if(builtConfig.isEnableDevMode()){ createRefreshJS( buildDirPath.resolve("refresh.js").toFile(), System.currentTimeMillis(), fileUtils ); } } else { Logger.warn("No project dir was specified. Some arguments may be ignored."); } } catch(Throwable exc){ fatal("Failed for the following reason: ", 1, exc); } } private static Properties getVariables(StaticPagesArguments arguments) throws IOException { Properties variables = new Properties(); variables.load( StaticPages.class.getResourceAsStream( "/default_variables.properties" ) ); if(arguments.hasVariables()){ File variablesFile = arguments.getVariables(); if(variablesFile.isFile()){ if(isDebug){ debug("Attempting to use user supplied variables."); debug( "The path to the variables is: "+ variablesFile.getAbsolutePath() ); } variables.load(new FileReader(variablesFile)); } else { throw new IOException( "The supplied variables path didn't result in a file: "+ "'"+variablesFile.getAbsolutePath()+"' was the path." ); } } return variables; } private static StaticPagesConfiguration buildStaticPagesConfiguration( StaticPagesArguments arguments ) throws IOException{ StaticPagesConfiguration.Builder config = new StaticPagesConfiguration.Builder(); config .setEnableCompression(arguments.getEnablecompression()) .setEnableDevMode(arguments.getEnabledevmode()); if( arguments.getEnabledevmode() && arguments.hasDevassetprefixinbrowser() ){ config.setAssetPrefixInBrowser( arguments.getDevassetprefixinbrowser() ); } else if(arguments.hasAssetprefixinbrowser()){ config.setAssetPrefixInBrowser(arguments.getAssetprefixinbrowser()); } if(arguments.getEnableassetfingerprinting()){ config.setAssetFingerprint( ".UTC"+(System.currentTimeMillis()/1000) ); } config.setPrefixToIgnoreFilesWith(arguments.getPrefixtoignorefiles()); File projectDir = arguments.getProjectdir(); if(isDebug)debug("projectDir: "+projectDir.getAbsolutePath()); FilePath projectDirPath = FilePath.getFilePath( projectDir.getAbsolutePath() ); FilePath buildDirPath = projectDirPath.resolve("build"); FilePath srcDirPath = projectDirPath.resolve("src"); config .setProjectDirPath(projectDirPath) .setPagesDirPath(projectDirPath.resolve("src/xml/pages")) .setViewsDirPath(projectDirPath.resolve("src/xml/views")) .setXmlResourcesDirPath( projectDirPath.resolve("src/xml/resources") ) .setBuildDirPath(buildDirPath) .setSrcDirPath(srcDirPath) .setXslDirPath(srcDirPath.resolve("xsl")) .setAssetsDirPath(srcDirPath.resolve("assets")) .setMaxDataURISizeInBytes( arguments.getMaxdataurisizeinbytes() ) .setMaxTimeToWaitForExternalLinkValidation( arguments.getMaxwaittimetovalidateexternallink() ); return config.build(); } private static void showFilePathDebugStatements( StaticPagesConfiguration config ){ FilePath projectDirPath = config.getProjectDirPath(); FilePath pagesDirPath = config.getPagesDirPath(); FilePath viewsDirPath = config.getViewsDirPath(); FilePath xmlResourcesDirPath = config.getXmlResourcesDirPath(); FilePath buildDirPath = config.getBuildDirPath(); FilePath srcDirPath = config.getSrcDirPath(); FilePath xslDirPath = config.getXslDirPath(); FilePath assetsDirPath = config.getAssetsDirPath(); if(isDebug)debug("asset prefix in browser: "+config.getAssetPrefixInBrowser()); if(isDebug)debug("asset fingerprint: "+config.getAssetFingerprint()); if(isDebug)debug("prefix to ignore files with: "+config.getPrefixToIgnoreFilesWith()); if(isDebug)debug("projectDirPath: "+projectDirPath.toString()); if(isDebug)debug("pagesDirPath: "+pagesDirPath.toString()); if(isDebug)debug("viewsDirPath: "+viewsDirPath.toString()); if(isDebug)debug("xmlResourcesDirPath: "+xmlResourcesDirPath.toString()); if(isDebug)debug("buildDirPath: "+buildDirPath.toString()); if(isDebug)debug("srcDirPath: "+srcDirPath.toString()); if(isDebug)debug("xslDirPath: "+xslDirPath.toString()); if(isDebug)debug("assetDirPath: "+assetsDirPath.toString()); } private static void createRefreshJS( File output, long timestamp, FileUtils fileUtils ) throws IOException { String content; if(isDebug)debug("creating refresh.js"); InputStream refreshJS = StaticPages.class.getResourceAsStream( "/refresh.js"); if(refreshJS != null){ content = new Scanner(refreshJS, "UTF-8").useDelimiter("\\A").next(). replace("stamp=0", "stamp="+timestamp); fileUtils.createFile(output); fileUtils.putString(output, content); } else { if(isDebug)debug("couldn't find refresh.js in the jar"); } } }