View Javadoc

1   // Version: $Id: $
2   // Copyright: Copyright(c) 2007 Trace Financial Limited
3   package org.liquibase.maven.plugins;
4   
5   import java.io.File;
6   import java.net.*;
7   import java.sql.*;
8   import java.util.*;
9   import java.lang.reflect.Field;
10  import liquibase.exception.LiquibaseException;
11  import org.apache.maven.artifact.Artifact;
12  import org.apache.maven.plugin.logging.Log;
13  import org.apache.maven.project.MavenProject;
14  
15  /**
16   * A Utilities class for Maven plugins.
17   * 
18   * @author Peter Murray
19   */
20  public class MavenUtils {
21  
22      public static final String LOG_SEPARATOR = "------------------------------------------------------------------------";
23  
24      /**
25       * Obtains a {@link ClassLoader} that can load from the Maven project dependencies. If the dependencies have not be
26       * resolved (or there are none) then this will just end up delegating to the parent {@link ClassLoader} of this
27       * class.
28       * 
29       * @return The ClassLoader that can load the resolved dependencies for the Maven project.
30       * @throws java.net.MalformedURLException
31       *             If any of the dependencies cannot be resolved into a URL.
32       */
33      public static ClassLoader getArtifactClassloader(MavenProject project, boolean includeArtifact,
34              boolean includeTestOutputDirectory, Class clazz, Log log, boolean verbose) throws MalformedURLException {
35          if (verbose) {
36              log.info("Loading artfacts into URLClassLoader");
37          }
38          Set<URL> urls = new HashSet<URL>();
39  
40          Set dependencies = project.getDependencyArtifacts();
41          if (dependencies != null && !dependencies.isEmpty()) {
42              for (Iterator it = dependencies.iterator(); it.hasNext();) {
43                  addArtifact(urls, (Artifact) it.next(), log, verbose);
44              }
45          } else {
46              log.info("there are no resolved artifacts for the Maven project.");
47          }
48  
49          // Include the artifact for the actual maven project if requested
50          if (includeArtifact) {
51              // If the actual artifact can be resolved, then use that, otherwise use the build
52              // directory as that should contain the files for this project that we will need to
53              // run against. It is possible that the build directy could be empty, but we cannot
54              // directly include the source and resources as the resources may require filtering
55              // to replace any placeholders in the resource files.
56              Artifact a = project.getArtifact();
57              if (a.getFile() != null) {
58                  addArtifact(urls, a, log, verbose);
59              } else {
60                  addFile(urls, new File(project.getBuild().getOutputDirectory()), log, verbose);
61              }
62          }
63          if (includeTestOutputDirectory) {
64              addFile(urls, new File(project.getBuild().getTestOutputDirectory()), log, verbose);
65          }
66          if (verbose) {
67              log.info(LOG_SEPARATOR);
68          }
69  
70          URL[] urlArray = urls.toArray(new URL[urls.size()]);
71          return new URLClassLoader(urlArray, clazz.getClassLoader());
72      }
73  
74      /**
75       * Adds the artifact file into the set of URLs so it can be used in a URLClassLoader.
76       * 
77       * @param urls
78       *            The set to add the artifact file URL to.
79       * @param artifact
80       *            The Artifiact to resolve the file for.
81       * @throws MalformedURLException
82       *             If there is a problem creating the URL for the file.
83       */
84      private static void addArtifact(Set<URL> urls, Artifact artifact, Log log, boolean verbose)
85              throws MalformedURLException {
86          File f = artifact.getFile();
87          if (f == null) {
88              log.warn("Artifact with no actual file, '" + artifact.getGroupId() + ":" + artifact.getArtifactId() + "'");
89          } else {
90              addFile(urls, f, log, verbose);
91          }
92          // if (f != null) {
93          // URL fileURL = f.toURI().toURL();
94          // if (verbose) {
95          // log.info("  artifact: " + fileURL);
96          // }
97          // urls.add(fileURL);
98          // } else {
99          // log.warn("Artifact with no actual file, '" + artifact.getGroupId()
100         // + ":" + artifact.getArtifactId() + "'");
101         // }
102     }
103 
104     private static void addFile(Set<URL> urls, File f, Log log, boolean verbose) throws MalformedURLException {
105         if (f != null) {
106             URL fileURL = f.toURI().toURL();
107             if (verbose) {
108                 log.info("  artifact: " + fileURL);
109             }
110             urls.add(fileURL);
111         }
112     }
113 
114     public static Connection getDatabaseConnection(ClassLoader classLoader, String driver, String url, String username,
115             String password) throws LiquibaseException {
116         Driver dbDriver = null;
117         try {
118             dbDriver = (Driver) Class.forName(driver, true, classLoader).newInstance();
119         } catch (InstantiationException e) {
120             throw new LiquibaseException("Failed to load JDBC driver, " + driver, e);
121         } catch (IllegalAccessException e) {
122             throw new LiquibaseException("Failed to load JDBC driver, " + driver, e);
123         } catch (ClassNotFoundException e) {
124             throw new LiquibaseException("Missing Class '" + e.getMessage() + "'. Database "
125                     + "driver may not be included in the project " + "dependencies or with wrong scope.");
126         }
127 
128         Properties info = new Properties();
129         info.put("user", username);
130         info.put("password", password);
131         try {
132             Connection connection = dbDriver.connect(url, info);
133             if (connection == null) {
134                 throw new LiquibaseException("Connection could not be created to " + url + " with driver "
135                         + dbDriver.getClass().getName() + ".  Possibly the wrong driver for the given "
136                         + "database URL");
137             }
138             return connection;
139         } catch (SQLException e) {
140             throw new LiquibaseException(e);
141         }
142     }
143 
144     /**
145      * Recursively searches for the field specified by the fieldName in the class and all the super classes until it
146      * either finds it, or runs out of parents.
147      * 
148      * @param clazz
149      *            The Class to start searching from.
150      * @param fieldName
151      *            The name of the field to retrieve.
152      * @return The {@link Field} identified by the field name.
153      * @throws NoSuchFieldException
154      *             If the field was not found in the class or any of its super classes.
155      */
156     public static Field getDeclaredField(Class clazz, String fieldName) throws NoSuchFieldException {
157         Field f = getField(clazz, fieldName);
158         if (f == null) {
159             // Try the parent class
160             Class parent = clazz.getSuperclass();
161             if (parent != null) {
162                 return getDeclaredField(parent, fieldName);
163             } else {
164                 throw new NoSuchFieldException("The field '" + fieldName + "' could not be "
165                         + "found in the class of any of its parent " + "classes.");
166             }
167         } else {
168             return f;
169         }
170     }
171 
172     private static Field getField(Class clazz, String fieldName) {
173         Field[] fields = clazz.getDeclaredFields();
174         for (int i = 0; i < fields.length; i++) {
175             if (fields[i].getName().equals(fieldName)) {
176                 return fields[i];
177             }
178         }
179         return null;
180     }
181 }