Java tutorial
/******************************************************************************* * Copyright (c) 2015 LegSem. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v2.1 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * LegSem - initial API and implementation ******************************************************************************/ package com.legstar.codegen; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.StringWriter; import java.io.Writer; import java.net.InetAddress; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.nio.charset.Charset; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Map; import java.util.Random; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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; /** * Various utility methods which are mostly useful for code generation using * velocity templates. */ public final class CodeGenUtil { /** Generated code has reference to generation date following this format. */ public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss"; /** Used to generate random serial version IDs. */ private static Random mRandom = new Random(); /** Suffix used for JAXB type variable names. */ public static final String JAXB_TYPE_SUFFIX = "Type"; /** Get the platform specific line separator. */ public static final String CRLF = System.getProperty("line.separator"); /** Logger. */ private static final Log LOG = LogFactory.getLog(CodeGenUtil.class); /** * Defeats instantiation. Utility class. */ private CodeGenUtil() { } /** * Check that a directory is valid. * * @param dir the directory name to check * @param create true if directory should be created when not found * @param errorDirName name to refer to if an error occurs */ public static void checkDirectory(final String dir, final boolean create, final String errorDirName) { try { checkDirectory(dir, create); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(errorDirName + ": " + e.getMessage()); } } /** * Check that a directory is valid. * * @param fdir the directory name to check * @param create true if directory should be created when not found * @param errorDirName name to refer to if an error occurs */ public static void checkDirectory(final File fdir, final boolean create, final String errorDirName) { try { checkDirectory(fdir, create); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(errorDirName + ": " + e.getMessage()); } } /** * Check that a directory is valid. * * @param dir the directory name to check * @param create true if directory should be created when not found */ public static void checkDirectory(final String dir, final boolean create) { if (dir == null || dir.length() == 0) { throw (new IllegalArgumentException("No directory name was specified")); } checkDirectory(new File(dir), create); } /** * Check that a directory is valid. * * @param fdir the directory to check * @param create true if directory should be created when not found */ public static void checkDirectory(final File fdir, final boolean create) { if (fdir == null) { throw (new IllegalArgumentException("No directory name was specified")); } if (!fdir.exists()) { if (!create) { throw (new IllegalArgumentException(fdir.getName() + " does not exist")); } else { if (!fdir.mkdirs()) { throw (new IllegalArgumentException("Could not create directory " + fdir.getName())); } else { return; } } } if (!fdir.isDirectory()) { throw (new IllegalArgumentException(fdir.getName() + " is not a directory")); } if (!fdir.canWrite()) { throw (new IllegalArgumentException("Directory " + fdir.getName() + " is not writable")); } } /** * Retrieve a file. Given a directory name and a filename, this creates a * File according to the following rules: * <ul> * <li>If the filename is absolute, the directory name is ignored</li> * <li>If the directory is not null, it is assumed to exist</li> * <li>If the directory is not null and the filename is not absolute, then * filename is appended to directory</li> * </ul> * * @param dir parent directory * @param filename absolute or relative file name * @return a File */ public static File getFile(final String dir, final String filename) { File file = new File(filename); if (file.isAbsolute()) { return file; } if (dir == null || dir.length() == 0) { return new File(filename); } return new File(dir, filename); } /** * Retrieve a file. Given a directory and a filename, this creates a File * according to the following rules: * <ul> * <li>If the filename is absolute, the directory name is ignored</li> * <li>Otherwise, filename is appended to directory</li> * </ul> * * @param fdir parent directory * @param filename absolute or relative file name * @return a File */ public static File getFile(final File fdir, final String filename) { File file = new File(filename); if (file.isAbsolute()) { return file; } return new File(fdir, filename); } /** * @deprecated use com.legstar.coxb.util.Utils#toClassName instead. Create a * valid Java class name from a given noun. * * @param noun the characters to turn into a java class name * @return the Java class name */ public static String classNormalize(final String noun) { String className = null; if (noun != null && noun.length() > 0) { className = noun.substring(0, 1).toUpperCase(); if (noun.length() > 1) { className += noun.substring(1, noun.length()); } } return className; } /** * Given a package name, this method returns the relative path location of * the java files. A package like seg1.seg2.seg3 becomes /seg1/seg2/seg3/ * * @param packageName the package name * @return the relative location of java files */ public static String relativeLocation(final String packageName) { if (packageName == null || packageName.length() == 0) { return ""; } String loc = packageName.replace('.', '/'); if (loc.charAt(0) != '/') { loc = '/' + loc; } if (loc.charAt(loc.length() - 1) != '/') { loc += '/'; } return loc; } /** * Given a root directory name and a package name, returns the location for * class files. Optionally the location can be physically created. * * @param rootDirName the root directory name. * @param packageName the package name or null if none * @param create true if directory should be created when not found * @return an existing location to store class files */ public static String classFilesLocation(final String rootDirName, final String packageName, final boolean create) { if (rootDirName == null || rootDirName.length() == 0) { throw (new IllegalArgumentException("No root directory name was specified")); } String dir; if (packageName != null && packageName.length() > 0) { dir = rootDirName + '/' + CodeGenUtil.relativeLocation(packageName); } else { dir = rootDirName; } if (create) { CodeGenUtil.checkDirectory(dir, true); } return dir; } /** * Concatenates the path derived from a package name to a root directory. * * @param rootDir the root directory. Optionally the location can be * physically created. * @param packageName the package name * @param create true if directory should be created when not found * @return the file derived from concatenating the root directory with the * package path. */ public static File classFilesLocation(final File rootDir, final String packageName, final boolean create) { File dir = rootDir; if (packageName != null && packageName.length() > 0) { dir = new File(rootDir, CodeGenUtil.relativeLocation(packageName)); } if (create) { CodeGenUtil.checkDirectory(dir, true); } return dir; } /** * Setup Velocity so that it searches for templates in the classpath. * <p/> * In order to work around issue 158 that arises when velocity dynamically * loaded classes are already in the context classloader parent, we * temporarily switch to a new context classloader that sees our plugin * classes and dependencies only. * * @throws CodeGenVelocityException if setup fails */ public static void initVelocity() throws CodeGenVelocityException { ClassLoader loader = Thread.currentThread().getContextClassLoader(); try { Velocity.addProperty("resource.loader", "classpath"); Velocity.addProperty("classpath.resource.loader.description", "Velocity Classpath Resource Loader"); Velocity.addProperty("classpath.resource.loader.class", "org.apache.velocity.runtime.resource.loader." + "ClasspathResourceLoader"); Velocity.addProperty("classpath.resource.loader.cache", true); Thread.currentThread().setContextClassLoader(Velocity.class.getClassLoader()); Velocity.init(); } catch (Exception e) { throw new CodeGenVelocityException(e); } finally { Thread.currentThread().setContextClassLoader(loader); } } /** * A simple context to use by generation templates. * * @param generatorName generator name * @return a velocity context */ public static VelocityContext getContext(final String generatorName) { VelocityContext context = new VelocityContext(); context.put("formattedDate", now()); context.put("generatorName", generatorName); return context; } /** * Apply a velocity template taken from a code generation make xml. * * @param generatorName the generator name * @param templateName the velocity template to apply * @param modelName the model name * @param model the model providing data for velocity templates * @param parameters additional parameters to pass to template * @param targetFile the file to generate using default charset * @throws CodeGenMakeException if processing fails */ public static void processTemplate(final String generatorName, final String templateName, final String modelName, final Object model, final Map<String, Object> parameters, final File targetFile) throws CodeGenMakeException { processTemplate(generatorName, templateName, modelName, model, parameters, targetFile, null); } /** * Apply a velocity template taken from a code generation make xml. * * @param generatorName the generator name * @param templateName the velocity template to apply * @param modelName the model name * @param model the model providing data for velocity templates * @param parameters additional parameters to pass to template * @param targetFile the file to generate * @param targetCharsetName the target character set. null is interpreted as * the default encoding * @throws CodeGenMakeException if processing fails */ public static void processTemplate(final String generatorName, final String templateName, final String modelName, final Object model, final Map<String, Object> parameters, final File targetFile, final String targetCharsetName) throws CodeGenMakeException { if (LOG.isDebugEnabled()) { LOG.debug("Processing template"); LOG.debug("Template name = " + templateName); LOG.debug("Target file = " + targetFile); LOG.debug("Target charset name = " + targetCharsetName); if (parameters != null) { for (String key : parameters.keySet()) { Object value = parameters.get(key); LOG.debug("Parameter " + key + " = " + value); } } } VelocityContext context = CodeGenUtil.getContext(generatorName); context.put(modelName, model); context.put("serialVersionID", Long.toString(mRandom.nextLong()) + 'L'); if (parameters != null) { for (String key : parameters.keySet()) { context.put(key, parameters.get(key)); } } StringWriter w = new StringWriter(); try { Velocity.mergeTemplate(templateName, "UTF-8", context, w); Writer out = null; try { FileOutputStream fos = new FileOutputStream(targetFile); OutputStreamWriter osw; if (targetCharsetName == null) { osw = new OutputStreamWriter(fos); } else { osw = new OutputStreamWriter(fos, targetCharsetName); } out = new BufferedWriter(osw); out.write(w.toString()); } catch (IOException e) { throw new CodeGenMakeException(e); } finally { if (out != null) { out.close(); } } } catch (ResourceNotFoundException e) { throw new CodeGenMakeException(e); } catch (ParseErrorException e) { throw new CodeGenMakeException(e); } catch (MethodInvocationException e) { throw new CodeGenMakeException(e); } catch (Exception e) { throw new CodeGenMakeException(e); } } /** * Formats todays date and time. * * @return a formatted date */ public static String now() { Calendar cal = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW); return sdf.format(cal.getTime()); } /** * Checks that a URI is valid and HTTP scheme. * * @param httpUri the URI to check * @throws CodeGenMakeException if URI has wrong syntax */ public static void checkHttpURI(final String httpUri) throws CodeGenMakeException { try { if (httpUri == null || httpUri.length() == 0) { throw new CodeGenMakeException("You must specify a valid URI"); } URI uri = new URI(httpUri); if (uri.getScheme() == null || uri.getScheme().compareToIgnoreCase("http") != 0) { throw new CodeGenMakeException("URI " + uri + " must have http scheme"); } } catch (URISyntaxException e) { throw new CodeGenMakeException(e); } } /** * Checks that a character set is valid. * * @param charset the character set * @see java.nio.charset.Charset * @throws CodeGenMakeException if character set not supported */ public static void checkCharset(final String charset) throws CodeGenMakeException { if (charset == null || charset.length() == 0) { throw new CodeGenMakeException("You must specify a valid character set"); } if (!Charset.isSupported(charset)) { throw new CodeGenMakeException("Character set " + charset + " is not supported"); } } /** * Field names are derived from property names by lower casing the first * character. * * @param propertyName the property name * @return a valid field name or null if property name is empty */ public static String fieldNameFromPropertyName(final String propertyName) { String fieldName = null; if (propertyName != null && propertyName.length() > 0) { fieldName = propertyName.substring(0, 1).toLowerCase(); if (propertyName.length() > 1) { fieldName += propertyName.substring(1, propertyName.length()); } } return fieldName; } /** * Property names are derived from field names by upper casing the first * character. * * @param fieldName the field name * @return a valid property name or null if field name is empty */ public static String propertyNameFromFieldName(final String fieldName) { String propertyName = null; if (fieldName != null && fieldName.length() > 0) { propertyName = fieldName.substring(0, 1).toUpperCase(); if (fieldName.length() > 1) { propertyName += fieldName.substring(1, fieldName.length()); } } return propertyName; } /** * Property names are derived from jaxb type names by stripping the type * suffix (if any). * * @param jaxbType the jaxb type name * @return a valid property name or null if jaxb type name is empty */ public static String propertyNameFromJaxbType(final String jaxbType) { String propertyName = null; if (jaxbType != null && jaxbType.length() > 0) { propertyName = jaxbType; if (propertyName.endsWith(JAXB_TYPE_SUFFIX)) { propertyName = propertyName.substring(0, propertyName.length() - JAXB_TYPE_SUFFIX.length()); } } return propertyName; } /** * Retrieve the IP address of the generation machine . * * @return the local machine IP address */ public static String getLocalIPAddress() { try { InetAddress addr = InetAddress.getLocalHost(); byte[] ipAddr = addr.getAddress(); String ipAddrStr = ""; for (int i = 0; i < ipAddr.length; i++) { if (i > 0) { ipAddrStr += "."; } ipAddrStr += ipAddr[i] & 0xFF; } return ipAddrStr; } catch (UnknownHostException e) { return ""; } } }