1 package de.juplo.plugins.hibernate4;
4 * Copyright 2001-2005 The Apache Software Foundation.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 import com.pyx4j.log4j.MavenLogAppender;
21 import java.io.FileInputStream;
22 import java.io.FileNotFoundException;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.ObjectInputStream;
27 import java.io.ObjectOutputStream;
28 import java.math.BigInteger;
30 import java.net.URLClassLoader;
31 import java.security.MessageDigest;
32 import java.security.NoSuchAlgorithmException;
33 import java.sql.Connection;
34 import java.sql.Driver;
35 import java.sql.DriverManager;
36 import java.sql.DriverPropertyInfo;
37 import java.sql.SQLException;
38 import java.sql.SQLFeatureNotSupportedException;
39 import java.util.Comparator;
40 import java.util.Enumeration;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.List;
45 import java.util.Map.Entry;
46 import java.util.Properties;
48 import java.util.TreeSet;
49 import java.util.logging.Logger;
50 import java.util.regex.Matcher;
51 import java.util.regex.Pattern;
52 import javax.persistence.Embeddable;
53 import javax.persistence.Entity;
54 import javax.persistence.MappedSuperclass;
55 import org.apache.maven.artifact.Artifact;
56 import org.apache.maven.model.Resource;
57 import org.apache.maven.plugin.AbstractMojo;
58 import org.apache.maven.plugin.MojoExecutionException;
59 import org.apache.maven.plugin.MojoFailureException;
60 import org.apache.maven.project.MavenProject;
61 import org.hibernate.cfg.NamingStrategy;
62 import org.hibernate.envers.configuration.spi.AuditConfiguration;
63 import org.hibernate.tool.hbm2ddl.SchemaExport;
64 import org.hibernate.tool.hbm2ddl.SchemaExport.Type;
65 import org.hibernate.tool.hbm2ddl.Target;
66 import org.scannotation.AnnotationDB;
70 * Goal which extracts the hibernate-mapping-configuration and
71 * exports an according SQL-database-schema.
74 * @phase process-classes
76 * @requiresDependencyResolution runtime
78 public class Hbm2DdlMojo extends AbstractMojo
80 public final static String EXPORT_SKIPPED_PROPERTY = "hibernate.export.skipped";
82 public final static String DRIVER_CLASS = "hibernate.connection.driver_class";
83 public final static String URL = "hibernate.connection.url";
84 public final static String USERNAME = "hibernate.connection.username";
85 public final static String PASSWORD = "hibernate.connection.password";
86 public final static String DIALECT = "hibernate.dialect";
87 public final static String NAMING_STRATEGY="hibernate.ejb.naming_strategy";
88 public final static String ENVERS = "hibernate.export.envers";
90 public final static String MD5S = "hibernate4-generatedschema.md5s";
92 private final static Pattern split = Pattern.compile("[^,\\s]+");
98 * Only needed internally.
100 * @parameter property="project"
104 private MavenProject project;
109 * Only needed internally.
111 * @parameter property="project.build.directory"
115 private String buildDirectory;
118 * Classes-Directory to scan.
120 * This parameter defaults to the maven build-output-directory for classes.
121 * Additionally, all dependencies are scanned for annotated classes.
123 * @parameter property="project.build.outputDirectory"
126 private String outputDirectory;
129 * Whether to scan test-classes too, or not.
131 * If this parameter is set to <code>true</code> the test-classes of the
132 * artifact will be scanned for hibernate-annotated classes additionally.
134 * @parameter property="hibernate.export.scan_testclasses" default-value="false"
137 private boolean scanTestClasses;
140 * Dependency-Scopes, that should be scanned for annotated classes.
142 * By default, only dependencies in the scope <code>compile</code> are
143 * scanned for annotated classes. Multiple scopes can be seperated by
144 * white space or commas.
146 * If you do not want any dependencies to be scanned for annotated
147 * classes, set this parameter to <code>none</code>.
149 * The plugin does not scan for annotated classes in transitive
150 * dependencies. If some of your annotated classes are hidden in a
151 * transitive dependency, you can simply add that dependency explicitly.
153 * @parameter property="hibernate.export.scan_dependencies" default-value="compile"
156 private String scanDependencies;
159 * Test-Classes-Directory to scan.
161 * This parameter defaults to the maven build-output-directory for
164 * This parameter is only used, when <code>scanTestClasses</code> is set
165 * to <code>true</code>!
167 * @parameter property="project.build.testOutputDirectory"
170 private String testOutputDirectory;
175 * If set to <code>true</code>, the execution is skipped.
177 * A skipped execution is signaled via the maven-property
178 * <code>${hibernate.export.skipped}</code>.
180 * The execution is skipped automatically, if no modified or newly added
181 * annotated classes are found and the dialect was not changed.
183 * @parameter property="hibernate.skip" default-value="${maven.test.skip}"
186 private boolean skip;
191 * Force execution, even if no modified or newly added annotated classes
192 * where found and the dialect was not changed.
194 * <code>skip</code> takes precedence over <code>force</code>.
196 * @parameter property="hibernate.export.force" default-value="false"
199 private boolean force;
204 * @parameter property="hibernate.connection.driver_class"
207 private String driverClassName;
212 * @parameter property="hibernate.connection.url"
220 * @parameter property="hibernate.connection.username"
223 private String username;
228 * @parameter property="hibernate.connection.password"
231 private String password;
236 * @parameter property="hibernate.dialect"
239 private String hibernateDialect;
242 * Hibernate Naming Strategy
244 * @parameter property="hibernate.ejb.naming_strategy"
247 private String hibernateNamingStrategy;
250 * Path to Hibernate configuration file.
252 * @parameter default-value="${project.build.outputDirectory}/hibernate.properties"
255 private String hibernateProperties;
258 * List of Hibernate-Mapping-Files (XML).
259 * Multiple files can be separated with white-spaces and/or commas.
261 * @parameter property="hibernate.mapping"
264 private String hibernateMapping;
267 * Target of execution:
269 * <li><strong>NONE</strong> only export schema to SQL-script (forces execution, signals skip)</li>
270 * <li><strong>EXPORT</strong> create database (<strong>DEFAULT!</strong>). forces execution, signals skip)</li>
271 * <li><strong>SCRIPT</strong> export schema to SQL-script and print it to STDOUT</li>
272 * <li><strong>BOTH</strong></li>
275 * A database connection is only needed for EXPORT and BOTH, but a
276 * Hibernate-Dialect must always be chosen.
278 * @parameter property="hibernate.export.target" default-value="EXPORT"
281 private String target;
286 * <li><strong>NONE</strong> do nothing - just validate the configuration</li>
287 * <li><strong>CREATE</strong> create database-schema</li>
288 * <li><strong>DROP</strong> drop database-schema</li>
289 * <li><strong>BOTH</strong> (<strong>DEFAULT!</strong>)</li>
292 * If NONE is choosen, no databaseconnection is needed.
294 * @parameter property="hibernate.export.type" default-value="BOTH"
302 * @parameter property="hibernate.export.schema.filename" default-value="${project.build.directory}/schema.sql"
305 private String outputFile;
308 * Delimiter in output-file.
310 * @parameter property="hibernate.export.schema.delimiter" default-value=";"
313 private String delimiter;
316 * Format output-file.
318 * @parameter property="hibernate.export.schema.format" default-value="true"
321 private boolean format;
324 * Generate envers schema for auditing tables.
326 * @parameter property="hibernate.export.envers" default-value="false"
329 private boolean envers;
333 public void execute()
335 MojoFailureException,
336 MojoExecutionException
340 getLog().info("Execution of hibernate4-maven-plugin:export was skipped!");
341 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
345 Map<String,String> md5s;
346 boolean modified = false;
347 File saved = new File(buildDirectory + File.separator + MD5S);
349 if (saved.isFile() && saved.length() > 0)
353 FileInputStream fis = new FileInputStream(saved);
354 ObjectInputStream ois = new ObjectInputStream(fis);
355 md5s = (HashMap<String,String>)ois.readObject();
360 md5s = new HashMap<String,String>();
361 getLog().warn("Cannot read timestamps from saved: " + e);
366 md5s = new HashMap<String,String>();
369 saved.createNewFile();
371 catch (IOException e)
373 getLog().debug("Cannot create file \"" + saved.getPath() + "\" for timestamps: " + e);
377 ClassLoader classLoader = null;
380 getLog().debug("Creating ClassLoader for project-dependencies...");
381 List<String> classpathFiles = project.getCompileClasspathElements();
383 classpathFiles.addAll(project.getTestClasspathElements());
384 URL[] urls = new URL[classpathFiles.size()];
385 for (int i = 0; i < classpathFiles.size(); ++i)
387 getLog().debug("Dependency: " + classpathFiles.get(i));
388 urls[i] = new File(classpathFiles.get(i)).toURI().toURL();
390 classLoader = new URLClassLoader(urls, getClass().getClassLoader());
394 getLog().error("Error while creating ClassLoader!", e);
395 throw new MojoExecutionException(e.getMessage());
398 Set<Class<?>> classes =
399 new TreeSet<Class<?>>(
400 new Comparator<Class<?>>() {
402 public int compare(Class<?> a, Class<?> b)
404 return a.getName().compareTo(b.getName());
411 AnnotationDB db = new AnnotationDB();
412 File dir = new File(outputDirectory);
415 getLog().info("Scanning directory " + outputDirectory + " for annotated classes...");
416 URL dirUrl = dir.toURI().toURL();
417 db.scanArchives(dirUrl);
421 dir = new File(testOutputDirectory);
424 getLog().info("Scanning directory " + testOutputDirectory + " for annotated classes...");
425 URL dirUrl = dir.toURI().toURL();
426 db.scanArchives(dirUrl);
429 if (scanDependencies != null)
431 Matcher matcher = split.matcher(scanDependencies);
432 while (matcher.find())
434 getLog().info("Scanning dependencies for scope " + matcher.group());
435 for (Artifact artifact : project.getDependencyArtifacts())
437 if (!artifact.getScope().equalsIgnoreCase(matcher.group()))
439 if (artifact.getFile() == null)
442 "Cannot scan dependency " +
444 ": no JAR-file available!"
449 "Scanning dependency " +
451 " for annotated classes..."
453 db.scanArchives(artifact.getFile().toURI().toURL());
458 Set<String> classNames = new HashSet<String>();
459 if (db.getAnnotationIndex().containsKey(Entity.class.getName()))
460 classNames.addAll(db.getAnnotationIndex().get(Entity.class.getName()));
461 if (db.getAnnotationIndex().containsKey(MappedSuperclass.class.getName()))
462 classNames.addAll(db.getAnnotationIndex().get(MappedSuperclass.class.getName()));
463 if (db.getAnnotationIndex().containsKey(Embeddable.class.getName()))
464 classNames.addAll(db.getAnnotationIndex().get(Embeddable.class.getName()));
466 MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
467 for (String name : classNames)
469 Class<?> annotatedClass = classLoader.loadClass(name);
470 classes.add(annotatedClass);
471 String resourceName = annotatedClass.getName();
472 resourceName = resourceName.substring(resourceName.lastIndexOf(".") + 1, resourceName.length()) + ".class";
475 .getResourceAsStream(resourceName);
476 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
478 while((i = is.read(buffer)) > -1)
479 digest.update(buffer, 0, i);
481 byte[] bytes = digest.digest();
482 BigInteger bi = new BigInteger(1, bytes);
483 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
484 String oldMd5 = !md5s.containsKey(name) ? "" : md5s.get(name);
485 if (!newMd5.equals(oldMd5))
487 getLog().debug("Found new or modified annotated class: " + name);
489 md5s.put(name, newMd5);
493 getLog().debug(oldMd5 + " -> class unchanged: " + name);
497 catch (ClassNotFoundException e)
499 getLog().error("Error while adding annotated classes!", e);
500 throw new MojoExecutionException(e.getMessage());
504 getLog().error("Error while scanning!", e);
505 throw new MojoFailureException(e.getMessage());
508 if (classes.isEmpty())
510 if (hibernateMapping == null || hibernateMapping.isEmpty())
511 throw new MojoFailureException("No annotated classes found in directory " + outputDirectory);
515 getLog().debug("Detected classes with mapping-annotations:");
516 for (Class<?> annotatedClass : classes)
517 getLog().debug(" " + annotatedClass.getName());
521 Properties properties = new Properties();
523 /** Try to read configuration from properties-file */
526 File file = new File(hibernateProperties);
529 getLog().info("Reading properties from file " + hibernateProperties + "...");
530 properties.load(new FileInputStream(file));
533 getLog().info("No hibernate-properties-file found! (Checked path: " + hibernateProperties + ")");
535 catch (IOException e)
537 getLog().error("Error while reading properties!", e);
538 throw new MojoExecutionException(e.getMessage());
541 /** Overwrite values from properties-file or set, if given */
542 if (driverClassName != null)
544 if (properties.containsKey(DRIVER_CLASS))
546 "Overwriting property " +
547 DRIVER_CLASS + "=" + properties.getProperty(DRIVER_CLASS) +
548 " with the value " + driverClassName
551 getLog().debug("Using the value " + driverClassName);
552 properties.setProperty(DRIVER_CLASS, driverClassName);
556 if (properties.containsKey(URL))
558 "Overwriting property " +
559 URL + "=" + properties.getProperty(URL) +
560 " with the value " + url
563 getLog().debug("Using the value " + url);
564 properties.setProperty(URL, url);
566 if (username != null)
568 if (properties.containsKey(USERNAME))
570 "Overwriting property " +
571 USERNAME + "=" + properties.getProperty(USERNAME) +
572 " with the value " + username
575 getLog().debug("Using the value " + username);
576 properties.setProperty(USERNAME, username);
578 if (password != null)
580 if (properties.containsKey(PASSWORD))
582 "Overwriting property " +
583 PASSWORD + "=" + properties.getProperty(PASSWORD) +
584 " with value " + password
587 getLog().debug("Using value " + password + " for property " + PASSWORD);
588 properties.setProperty(PASSWORD, password);
590 if (hibernateDialect != null)
592 if (properties.containsKey(DIALECT))
594 "Overwriting property " +
595 DIALECT + "=" + properties.getProperty(DIALECT) +
596 " with value " + hibernateDialect
600 "Using value " + hibernateDialect + " for property " + DIALECT
602 properties.setProperty(DIALECT, hibernateDialect);
606 hibernateDialect = properties.getProperty(DIALECT);
608 if ( hibernateNamingStrategy != null )
610 if ( properties.contains(NAMING_STRATEGY))
612 "Overwriting property " +
613 NAMING_STRATEGY + "=" + properties.getProperty(NAMING_STRATEGY) +
614 " with value " + hibernateNamingStrategy
618 "Using value " + hibernateNamingStrategy + " for property " +
621 properties.setProperty(NAMING_STRATEGY, hibernateNamingStrategy);
624 /** The generated SQL varies with the dialect! */
625 if (md5s.containsKey(DIALECT))
627 String dialect = properties.getProperty(DIALECT);
628 if (md5s.get(DIALECT).equals(dialect))
629 getLog().debug("SQL-dialect unchanged.");
635 getLog().debug("SQL-dialect was unset.");
636 md5s.remove(DIALECT);
640 getLog().debug("SQL-dialect changed: " + dialect);
641 md5s.put(DIALECT, dialect);
647 String dialect = properties.getProperty(DIALECT);
651 md5s.put(DIALECT, properties.getProperty(DIALECT));
655 /** The generated SQL varies with the envers-configuration */
656 if (md5s.get(ENVERS) != null)
658 if (md5s.get(ENVERS).equals(Boolean.toString(envers)))
659 getLog().debug("Envers-Configuration unchanged. Enabled: " + envers);
662 getLog().debug("Envers-Configuration changed. Enabled: " + envers);
664 md5s.put(ENVERS, Boolean.toString(envers));
670 md5s.put(ENVERS, Boolean.toString(envers));
673 if (properties.isEmpty())
675 getLog().error("No properties set!");
676 throw new MojoFailureException("Hibernate configuration is missing!");
679 final ValidationConfiguration config = new ValidationConfiguration(hibernateDialect);
681 config.setProperties(properties);
683 if ( properties.containsKey(NAMING_STRATEGY))
685 String namingStrategy = properties.getProperty(NAMING_STRATEGY);
686 getLog().debug("Explicitly set NamingStrategy: " + namingStrategy);
689 @SuppressWarnings("unchecked")
690 Class<NamingStrategy> namingStrategyClass = (Class<NamingStrategy>) Class.forName(namingStrategy);
691 config.setNamingStrategy(namingStrategyClass.newInstance());
695 getLog().error("Error setting NamingStrategy", e);
696 throw new MojoExecutionException(e.getMessage());
700 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
701 Connection connection = null;
702 MavenLogAppender.startPluginLog(this);
706 * Change class-loader of current thread, so that hibernate can
707 * see all dependencies!
709 Thread.currentThread().setContextClassLoader(classLoader);
711 getLog().debug("Adding annotated classes to hibernate-mapping-configuration...");
712 // build annotated packages
713 Set<String> packages = new HashSet<String>();
714 for (Class<?> annotatedClass : classes)
716 String packageName = annotatedClass.getPackage().getName();
717 if (!packages.contains(packageName))
719 getLog().debug("Add package " + packageName);
720 packages.add(packageName);
721 config.addPackage(packageName);
722 getLog().debug("type definintions" + config.getTypeDefs());
724 getLog().debug("Class " + annotatedClass);
725 config.addAnnotatedClass(annotatedClass);
728 if (hibernateMapping != null)
732 MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
733 for (String filename : hibernateMapping.split("[\\s,]+"))
735 // First try the filename as absolute/relative path
736 File file = new File(filename);
739 // If the file was not found, search for it in the resource-directories
740 for (Resource resource : project.getResources())
742 file = new File(resource.getDirectory() + File.separator + filename);
747 if (file != null && file.exists())
749 InputStream is = new FileInputStream(file);
750 byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
752 while((i = is.read(buffer)) > -1)
753 digest.update(buffer, 0, i);
755 byte[] bytes = digest.digest();
756 BigInteger bi = new BigInteger(1, bytes);
757 String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
758 String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename);
759 if (!newMd5.equals(oldMd5))
761 getLog().debug("Found new or modified mapping-file: " + filename);
763 md5s.put(filename, newMd5);
767 getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename);
769 getLog().debug("Adding mappings from XML-configurationfile: " + file);
770 config.addFile(file);
773 throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
776 catch (NoSuchAlgorithmException e)
778 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
780 catch (FileNotFoundException e)
782 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
784 catch (IOException e)
786 throw new MojoFailureException("Cannot calculate MD5 sums!", e);
790 Target target = null;
793 target = Target.valueOf(this.target.toUpperCase());
795 catch (IllegalArgumentException e)
797 getLog().error("Invalid value for configuration-option \"target\": " + this.target);
798 getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH");
799 throw new MojoExecutionException("Invalid value for configuration-option \"target\"");
804 type = Type.valueOf(this.type.toUpperCase());
806 catch (IllegalArgumentException e)
808 getLog().error("Invalid value for configuration-option \"type\": " + this.type);
809 getLog().error("Valid values are: NONE, CREATE, DROP, BOTH");
810 throw new MojoExecutionException("Invalid value for configuration-option \"type\"");
813 if (target.equals(Target.SCRIPT) || target.equals(Target.NONE))
815 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
819 && !target.equals(Target.SCRIPT)
820 && !target.equals(Target.NONE)
824 getLog().info("No modified annotated classes or mapping-files found and dialect unchanged.");
825 getLog().info("Skipping schema generation!");
826 project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
830 getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
831 for (Entry<Object,Object> entry : properties.entrySet())
832 getLog().info(" " + entry.getKey() + " = " + entry.getValue());
837 * The connection must be established outside of hibernate, because
838 * hibernate does not use the context-classloader of the current
839 * thread and, hence, would not be able to resolve the driver-class!
841 getLog().debug("Target: " + target + ", Type: " + type);
851 Class driverClass = classLoader.loadClass(properties.getProperty(DRIVER_CLASS));
852 getLog().debug("Registering JDBC-driver " + driverClass.getName());
853 DriverManager.registerDriver(new DriverProxy((Driver)driverClass.newInstance()));
855 "Opening JDBC-connection to "
856 + properties.getProperty(URL)
858 + properties.getProperty(USERNAME)
860 + properties.getProperty(PASSWORD)
862 connection = DriverManager.getConnection(
863 properties.getProperty(URL),
864 properties.getProperty(USERNAME),
865 properties.getProperty(PASSWORD)
870 catch (ClassNotFoundException e)
872 getLog().error("Dependency for driver-class " + properties.getProperty(DRIVER_CLASS) + " is missing!");
873 throw new MojoExecutionException(e.getMessage());
877 getLog().error("Cannot establish connection to database!");
878 Enumeration<Driver> drivers = DriverManager.getDrivers();
879 if (!drivers.hasMoreElements())
880 getLog().error("No drivers registered!");
881 while (drivers.hasMoreElements())
882 getLog().debug("Driver: " + drivers.nextElement());
883 throw new MojoExecutionException(e.getMessage());
886 config.buildMappings();
890 getLog().info("Automatic auditing via hibernate-envers enabled!");
891 AuditConfiguration.getFor(config);
894 SchemaExport export = new SchemaExport(config, connection);
895 export.setDelimiter(delimiter);
896 export.setFormat(format);
898 File outF = new File(outputFile);
900 if (!outF.isAbsolute())
902 // Interpret relative file path relative to build directory
903 outF = new File(buildDirectory, outputFile);
904 getLog().info("Adjusted relative path, resulting path is " + outF.getPath());
907 // Ensure that directory path for specified file exists
908 File outFileParentDir = outF.getParentFile();
909 if (null != outFileParentDir && !outFileParentDir.exists())
913 getLog().info("Creating directory path for output file:" + outFileParentDir.getPath());
914 outFileParentDir.mkdirs();
918 getLog().error("Error creating directory path for output file: " + e.getLocalizedMessage());
922 export.setOutputFile(outF.getPath());
923 export.execute(target, type);
925 for (Object exception : export.getExceptions())
926 getLog().debug(exception.toString());
930 /** Stop Log-Capturing */
931 MavenLogAppender.endPluginLog(this);
933 /** Restore the old class-loader (TODO: is this really necessary?) */
934 Thread.currentThread().setContextClassLoader(contextClassLoader);
936 /** Close the connection */
939 if (connection != null)
942 catch (SQLException e)
944 getLog().error("Error while closing connection: " + e.getMessage());
948 /** Write md5-sums for annotated classes to file */
951 FileOutputStream fos = new FileOutputStream(saved);
952 ObjectOutputStream oos = new ObjectOutputStream(fos);
953 oos.writeObject(md5s);
959 getLog().error("Cannot write md5-sums to file: " + e);
964 * Needed, because DriverManager won't pick up drivers, that were not
965 * loaded by the system-classloader!
967 * http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-fromodifiedm-an-arbitrary-location
969 static final class DriverProxy implements Driver
971 private final Driver target;
973 DriverProxy(Driver target)
976 throw new NullPointerException();
977 this.target = target;
980 public java.sql.Driver getTarget()
986 public boolean acceptsURL(String url) throws SQLException
988 return target.acceptsURL(url);
992 public java.sql.Connection connect(
994 java.util.Properties info
999 return target.connect(url, info);
1003 public int getMajorVersion()
1005 return target.getMajorVersion();
1009 public int getMinorVersion()
1011 return target.getMinorVersion();
1015 public DriverPropertyInfo[] getPropertyInfo(
1022 return target.getPropertyInfo(url, info);
1026 public boolean jdbcCompliant()
1028 return target.jdbcCompliant();
1032 * This Method cannot be annotated with @Override, becaus the plugin
1033 * will not compile then under Java 1.6!
1035 public Logger getParentLogger() throws SQLFeatureNotSupportedException
1037 throw new SQLFeatureNotSupportedException("Not supported, for backward-compatibility with Java 1.6");
1041 public String toString()
1043 return "Proxy: " + target;
1047 public int hashCode()
1049 return target.hashCode();
1053 public boolean equals(Object obj)
1055 if (!(obj instanceof DriverProxy))
1057 DriverProxy other = (DriverProxy) obj;
1058 return this.target.equals(other.target);