001package org.andromda.maven.plugin.andromdapp.hibernate; 002 003import java.io.File; 004import java.lang.reflect.Method; 005import java.sql.Connection; 006import java.util.ArrayList; 007import java.util.Arrays; 008import java.util.List; 009import java.util.Map; 010import org.andromda.core.common.ClassUtils; 011import org.andromda.maven.plugin.andromdapp.SchemaManagement; 012import org.andromda.maven.plugin.andromdapp.SchemaManagementException; 013import org.apache.commons.lang.ObjectUtils; 014import org.apache.commons.lang.StringUtils; 015import org.apache.log4j.Logger; 016import org.codehaus.plexus.util.DirectoryScanner; 017 018/** 019 * A Hibernate management object. 020 * 021 * @author Chad Brandon 022 */ 023public abstract class HibernateSchemaManagement 024 implements SchemaManagement 025{ 026 /** 027 * getLogger(HibernateSchemaManagement.class) 028 */ 029 protected static Logger logger = Logger.getLogger(HibernateSchemaManagement.class); 030 031 /** 032 * The Hibernate 2 schema export class name. 033 */ 034 protected static final String HIBERNATE_2_PACKAGE = "net.sf.hibernate.tool.hbm2ddl"; 035 036 /** 037 * The Hibernate 3 schema export class name. 038 */ 039 protected static final String HIBERNATE_3_PACKAGE = "org.hibernate.tool.hbm2ddl"; 040 041 /** 042 * The Hibernate version 043 */ 044 private String version; 045 046 /** 047 * Sets the version of Hibernate to target. 048 * 049 * @param version the version of Hibernate to target. 050 */ 051 public void setVersion(final String version) 052 { 053 this.version = version; 054 } 055 056 /** 057 * Retrieves the class that performs the execution work. 058 * 059 * @return the Hibernate class that performs the work. 060 */ 061 protected Class getExecutionClass() 062 { 063 Class hibernateClass = null; 064 String hibernate2ClassName = null; 065 String hibernate3ClassName = null; 066 try 067 { 068 hibernate3ClassName = HIBERNATE_3_PACKAGE + '.' + this.getExecutionClassName(); 069 hibernateClass = ClassUtils.loadClass(hibernate3ClassName); 070 } 071 catch (Exception exception) 072 { 073 // - ignore, means we can't find the Hibernate 3 class 074 } 075 try 076 { 077 hibernate2ClassName = HIBERNATE_2_PACKAGE + '.' + this.getExecutionClassName(); 078 hibernateClass = ClassUtils.loadClass(hibernate2ClassName); 079 } 080 catch (Exception exception) 081 { 082 // - ignore, means we can't find the Hibernate 2 class 083 } 084 if (hibernateClass == null) 085 { 086 throw new RuntimeException( 087 "There appear to be no Hibernate 2 or 3 jars are your classpath, because neither '" + 088 hibernate2ClassName + "', nor '" + hibernate3ClassName + "' could be found"); 089 } 090 return hibernateClass; 091 } 092 093 /** 094 * Returns the current Hibernate version this management object 095 * is targetting. 096 * 097 * @return the Hibernate version (2 or 3). 098 */ 099 protected String getVersion() 100 { 101 return this.version; 102 } 103 104 /** 105 * Stores the path to which output should be written. 106 */ 107 private String outputPath; 108 109 /** 110 * Sets the path to which the output should be written. 111 * 112 * @param outputPath 113 */ 114 public void setOutputPath(final String outputPath) 115 { 116 this.outputPath = outputPath; 117 } 118 119 /** 120 * Attempts to retrieve the given property with the given <code>name</code>. 121 * 122 * @param properties the properties from which to retrieve the property. 123 * @param name the name of the property to retrieve. 124 * @return the value of the property. 125 */ 126 protected String getProperty( 127 final Map properties, 128 final String name) 129 { 130 final String value = ObjectUtils.toString(properties.get(name)); 131 return value; 132 } 133 134 /** 135 * Attempts to retrieve the given property with the given <code>name</code>. 136 * If the property isn't found an exception is thrown. 137 * 138 * @param properties the properties from which to retrieve the property. 139 * @param name the name of the property to retrieve. 140 * @return the value of the property. 141 */ 142 protected String getRequiredProperty( 143 final Map properties, 144 final String name) 145 { 146 final String value = ObjectUtils.toString(properties.get(name)); 147 if (StringUtils.isBlank(value)) 148 { 149 throw new SchemaManagementException("The '" + name + "' must be specified"); 150 } 151 return value; 152 } 153 154 /** 155 * Gets the path to which output should be written. 156 * 157 * @return the output path. 158 */ 159 protected String getOutputPath() 160 { 161 return this.outputPath; 162 } 163 164 /** 165 * Returns the name of the class that performs the execution. 166 * 167 * @return the execution class. 168 */ 169 protected abstract String getExecutionClassName(); 170 171 /** 172 * @see org.andromda.maven.plugin.andromdapp.SchemaManagement#execute(java.sql.Connection, java.util.Map) 173 */ 174 public String execute( 175 Connection connection, 176 java.util.Map options) 177 throws Exception 178 { 179 final String hibernateDialect = "hibernate.dialect"; 180 System.setProperty( 181 hibernateDialect, 182 this.getRequiredProperty( 183 options, 184 hibernateDialect)); 185 final List<String> argumentList = this.getArguments(options); 186 final String[] arguments = argumentList.toArray(new String[argumentList.size()]); 187 final Class executionClass = this.getExecutionClass(); 188 final Method method = executionClass.getMethod( 189 "main", 190 new Class[] {String[].class}); 191 method.invoke( 192 executionClass, 193 new Object[] {arguments}); 194 195 return this.getExecutionOuputPath(options); 196 } 197 198 /** 199 * Returns the path of the execution output file. 200 * 201 * @param options the options from which to retrieve properties. 202 * @return the output path. 203 */ 204 protected abstract String getExecutionOuputPath(final Map options); 205 206 /** 207 * Retrieves the arguments common to all Hibernate schema management 208 * tasks. 209 * 210 * @param options the options from which to retrieve any required properties. 211 * @return the list of common arguments. 212 */ 213 private List<String> getArguments(final Map options) 214 throws Exception 215 { 216 final List<String> mappingFiles = 217 this.getMappingFilesList( 218 this.getRequiredProperty( 219 options, 220 "mappingFileExtension"), 221 this.getRequiredProperty( 222 options, 223 "mappingsLocation")); 224 final String[] args = new String[] {"--delimiter=;", "--format"}; 225 final List<String> arguments = new ArrayList<String>(Arrays.asList(args)); 226 arguments.addAll(mappingFiles); 227 this.addArguments( 228 options, 229 arguments); 230 return arguments; 231 } 232 233 /** 234 * Adds any arguments required by the specialized class. 235 * 236 * @param options any options from which to retrieve argument values. 237 * @param arguments the list of arguments to add. 238 * @throws Exception 239 */ 240 protected abstract void addArguments( 241 final Map options, 242 final List<String> arguments) throws Exception; 243 244 /** 245 * Retrieves all mapping files having the given <code>extension</code> 246 * existing in the <code>baseDirectory</code> or any of its sub directories. 247 * 248 * @param extension the mapping file extension 249 * @param baseDirectory the directory from which to perform the search. 250 * @return the list of mapping files 251 */ 252 protected List<String> getMappingFilesList( 253 final String extension, 254 final String baseDirectory) 255 { 256 final DirectoryScanner scanner = new DirectoryScanner(); 257 scanner.setBasedir(baseDirectory); 258 scanner.setIncludes(new String[] {"**/*." + extension}); 259 scanner.setExcludes(null); 260 scanner.scan(); 261 262 final List<String> files = new ArrayList<String>(); 263 for (String path : Arrays.asList(scanner.getIncludedFiles())) 264 { 265 files.add(new File( 266 baseDirectory, 267 path).toString()); 268 } 269 return files; 270 } 271}