private void enlarge(final int size) {
        int length1 = 2 * data.length;
        int length2 = length + size;
        byte[] newData = new byte[length1 > length2 ? length1 : length2];
        System.arraycopy(data, 0, newData, 0, length);
        data = newData;
    }

private void enlarge ( final int size ) { int length1 = 2 * data . length ; int length2 = length + size ; byte [ ] newData = new byte [ length1 > length2 ? length1 : length2 ] ; System . arraycopy ( data , 0 , newData , 0 , length ) ; data = newData ; }

Enlarge this byte vector so that it can receive n more bytes.

@param size
number of additional bytes that this byte vector should be
able to receive.

Enlarge this byte vector so that it can receive n more bytes .


@Override
   public String getColumnName(int col) {
      return (col < header.length) ? columnMapping.get(header[col].toUpperCase()) : null;
   }

@ Override public String getColumnName ( int col ) { return ( col < header . length ) ? columnMapping . get ( header [ col ] . toUpperCase ( ) ) : null ; }

Retrieves the column name for a given column position

@param col - column position.
@return - The column name.


public void setColumnMapping(Map<String, String> columnMapping) {
      this.columnMapping.clear();
      for (Map.Entry<String, String> entry : columnMapping.entrySet()) {
         this.columnMapping.put(entry.getKey().toUpperCase(), entry.getValue());
      }
   }

public void setColumnMapping ( Map < String , String > columnMapping ) { this . columnMapping . clear ( ) ; for ( Map . Entry < String , String > entry : columnMapping . entrySet ( ) ) { this . columnMapping . put ( entry . getKey ( ) . toUpperCase ( ) , entry . getValue ( ) ) ; } }

Sets the column mapping to those passed in.
@param columnMapping - source column mapping.

Sets the column mapping to those passed in .


@Override
    public <T> T getValue(String propertyName, Class<T> returnType) {
        return getContainer().getValue(propertyName, returnType);
    }

@ Override public < T > T getValue ( String propertyName , Class < T > returnType ) { return getContainer ( ) . getValue ( propertyName , returnType ) ; }

Returns the value for the given property cast to the passed returnType.
If the type of the property and the given return type are not compatible an exception will be thrown.
If the passed propertyName is not a defined property, an exception is thrown.

Returns the value for the given property cast to the passed returnType . If the type of the property and the given return type are not compatible an exception will be thrown . If the passed propertyName is not a defined property an exception is thrown .


@Override
    public void init(ConfigurationValueProvider... configurationValueProviders) {
        if (configurationValueProviders != null) {
            for (ConfigurationProperty property : getContainer().properties.values()) {
                property.init(configurationValueProviders);
            }
        }
    }

@ Override public void init ( ConfigurationValueProvider ... configurationValueProviders ) { if ( configurationValueProviders != null ) { for ( ConfigurationProperty property : getContainer ( ) . properties . values ( ) ) { property . init ( configurationValueProviders ) ; } } }

Override default values for properties with the given ConfigurationProviders.

Override default values for properties with the given ConfigurationProviders .


public static IOCase forName(String name) {
        if (IOCase.SENSITIVE.name.equals(name)){
            return IOCase.SENSITIVE;
        }
        if (IOCase.INSENSITIVE.name.equals(name)){
            return IOCase.INSENSITIVE;
        }
        if (IOCase.SYSTEM.name.equals(name)){
            return IOCase.SYSTEM;
        }
        throw new IllegalArgumentException("Invalid IOCase name: " + name);
    }

public
static
IOCase
forName
(
String
name
)
{
if
(
IOCase
.
SENSITIVE
.
name
.
equals
(
name
)
)
{
return
IOCase
.
SENSITIVE
;
}
if
(
IOCase
.
INSENSITIVE
.
name
.
equals
(
name
)
)
{
return
IOCase
.
INSENSITIVE
;
}
if
(
IOCase
.
SYSTEM
.
name
.
equals
(
name
)
)
{
return
IOCase
.
SYSTEM
;
}
throw
new
IllegalArgumentException
(
"Invalid IOCase name: "
+
name
)
;
}

Factory method to create an IOCase from a name.

@param name  the name to find
@return the IOCase object
@throws IllegalArgumentException if the name is invalid

Factory method to create an IOCase from a name .


String convertCase(String str) {
        if (str == null) {
            return null;
        }
        return isSensitive ? str : str.toLowerCase();
    }

String convertCase ( String str ) { if ( str == null ) { return null ; } return isSensitive ? str : str . toLowerCase ( ) ; }

Converts the case of the input String to a standard format.
Subsequent operations can then use standard String methods.

@param str  the string to convert, null returns null
@return the lower-case version if case-insensitive

Converts the case of the input String to a standard format . Subsequent operations can then use standard String methods .


public Object getCurrentValue(Change change) {
        try {
            for (PropertyDescriptor descriptor : PropertyUtils.getInstance().getDescriptors(change.getClass())) {
                if (descriptor.getDisplayName().equals(this.parameterName)) {
                    Method readMethod = descriptor.getReadMethod();
                    if (readMethod == null) {
                        readMethod = change.getClass().getMethod(
                            "is" + StringUtil.upperCaseFirst(descriptor.getName())
                        );
                    }
                    return readMethod.invoke(change);
                }
            }
            throw new RuntimeException("Could not find readMethod for " + this.parameterName);
        } catch (Exception e) {
            throw new UnexpectedLiquibaseException(e);
        }
    }

public
Object
getCurrentValue
(
Change
change
)
{
try
{
for
(
PropertyDescriptor
descriptor
:
PropertyUtils
.
getInstance
(
)
.
getDescriptors
(
change
.
getClass
(
)
)
)
{
if
(
descriptor
.
getDisplayName
(
)
.
equals
(
this
.
parameterName
)
)
{
Method
readMethod
=
descriptor
.
getReadMethod
(
)
;
if
(
readMethod
==
)
{
readMethod
=
change
.
getClass
(
)
.
getMethod
(
"is"
+
StringUtil
.
upperCaseFirst
(
descriptor
.
getName
(
)
)
)
;
}
return
readMethod
.
invoke
(
change
)
;
}
}
throw
new
RuntimeException
(
"Could not find readMethod for "
+
this
.
parameterName
)
;
}
catch
(
Exception
e
)
{
throw
new
UnexpectedLiquibaseException
(
e
)
;
}
}

Returns the current value of this parameter for the given Change.

Returns the current value of this parameter for the given Change .


public void setValue(Change change, Object value) {
        if ((value instanceof String) && (!"string".equals(dataType))) {
            try {
                switch (dataType) {
                    case "bigInteger":
                        value = new BigInteger((String) value);
                        break;
                    case "databaseFunction":
                        value = new DatabaseFunction((String) value);
                        break;
                    default:
                        throw new UnexpectedLiquibaseException("Unknown data type: " + dataType);
                }
            } catch (Exception e) {
                throw new UnexpectedLiquibaseException("Cannot convert string value '" + value + "' to " +
                    dataType + ": " + e.getMessage());
            }
        }

        try {
            for (PropertyDescriptor descriptor : PropertyUtils.getInstance().getDescriptors(change.getClass())) {
                if (descriptor.getDisplayName().equals(this.parameterName)) {
                    Method writeMethod = descriptor.getWriteMethod();
                    if (writeMethod == null) {
                        throw new UnexpectedLiquibaseException("Could not find writeMethod for " + this.parameterName);
                    }
                    Class<?> expectedWriteType = writeMethod.getParameterTypes()[0];
                    if ((value != null) && !expectedWriteType.isAssignableFrom(value.getClass())) {
                        if (expectedWriteType.equals(String.class)) {
                            value = value.toString();
                        } else {
                            throw new UnexpectedLiquibaseException(
                                "Could not convert " + value.getClass().getName() +
                                " to " +
                                expectedWriteType.getName()
                            );
                        }
                    }
                    writeMethod.invoke(change, value);
                }
            }
        } catch (Exception e) {
            throw new UnexpectedLiquibaseException("Error setting " + this.parameterName + " to " + value, e);
        }
    }

public
void
setValue
(
Change
change
,
Object
value
)
{
if
(
(
value
instanceof
String
)
&&
(
!
"string"
.
equals
(
dataType
)
)
)
{
try
{
switch
(
dataType
)
{
case
"bigInteger"
:
value
=
new
BigInteger
(
(
String
)
value
)
;
break
;
case
"databaseFunction"
:
value
=
new
DatabaseFunction
(
(
String
)
value
)
;
break
;
default
:
throw
new
UnexpectedLiquibaseException
(
"Unknown data type: "
+
dataType
)
;
}
}
catch
(
Exception
e
)
{
throw
new
UnexpectedLiquibaseException
(
"Cannot convert string value '"
+
value
+
"' to "
+
dataType
+
": "
+
e
.
getMessage
(
)
)
;
}
}
try
{
for
(
PropertyDescriptor
descriptor
:
PropertyUtils
.
getInstance
(
)
.
getDescriptors
(
change
.
getClass
(
)
)
)
{
if
(
descriptor
.
getDisplayName
(
)
.
equals
(
this
.
parameterName
)
)
{
Method
writeMethod
=
descriptor
.
getWriteMethod
(
)
;
if
(
writeMethod
==
)
{
throw
new
UnexpectedLiquibaseException
(
"Could not find writeMethod for "
+
this
.
parameterName
)
;
}
Class
<
>
expectedWriteType
=
writeMethod
.
getParameterTypes
(
)
[
0
]
;
if
(
(
value
!=
)
&&
!
expectedWriteType
.
isAssignableFrom
(
value
.
getClass
(
)
)
)
{
if
(
expectedWriteType
.
equals
(
String
.
class
)
)
{
value
=
value
.
toString
(
)
;
}
else
{
throw
new
UnexpectedLiquibaseException
(
"Could not convert "
+
value
.
getClass
(
)
.
getName
(
)
+
" to "
+
expectedWriteType
.
getName
(
)
)
;
}
}
writeMethod
.
invoke
(
change
,
value
)
;
}
}
}
catch
(
Exception
e
)
{
throw
new
UnexpectedLiquibaseException
(
"Error setting "
+
this
.
parameterName
+
" to "
+
value
,
e
)
;
}
}

Sets the value of this parameter on the given change.

Sets the value of this parameter on the given change .


public static <T> T[] createIfNull(T[] arguments) {
        if (arguments == null) {
            return (T[]) new Object[0];
        } else {
            return arguments;
        }
    }

public static < T > T [ ] createIfNull ( T [ ] arguments ) { if ( arguments == null ) { return ( T [ ] ) new Object [ 0 ] ; } else { return arguments ; } }

Returns a new empty array if the passed array is null.

Returns a new empty array if the passed array is null .


public static <T> Set<T> createIfNull(Set<T> currentValue) {
        if (currentValue == null) {
            return new HashSet<>();
        } else {
            return currentValue;
        }
    }

public static < T > Set < T > createIfNull ( Set < T > currentValue ) { if ( currentValue == null ) { return new HashSet <> ( ) ; } else { return currentValue ; } }

Returns a new empty set if the passed array is null.

Returns a new empty set if the passed array is null .


private Boolean getGlobalParam(Map property) {
		Boolean global = null;
		Object globalObj = property.get("global");
		if (globalObj == null) {
			// default behaviour before liquibase 3.4
			global = true;
		} else {
			global = (Boolean) globalObj;
		}
		return global;
	}

Extract the global parameter from the properties.

@param property the map of props
@return the global param

Extract the global parameter from the properties .


protected void attachParams(List<ColumnConfig> cols, PreparedStatement stmt)
            throws SQLException, DatabaseException {
        int i = 1;  // index starts from 1
        for (ColumnConfig col : cols) {
            LOG.fine(LogType.LOG, "Applying column parameter = " + i + " for column " + col.getName());
            applyColumnParameter(stmt, i, col);
            i++;
        }
    }

protected
void
attachParams
(
List
<
ColumnConfig
>
cols
,
PreparedStatement
stmt
)
throws
SQLException
,
DatabaseException
{
int
i
=
1
;
// index starts from 1
for
(
ColumnConfig
col
:
cols
)
{
LOG
.
fine
(
LogType
.
LOG
,
"Applying column parameter = "
+
i
+
" for column "
+
col
.
getName
(
)
)
;
applyColumnParameter
(
stmt
,
i
,
col
)
;
i
++
;
}
}

Sets the list of bind variables for the execution of a DML statement
@param cols a list of columns with their designated values
@param stmt the PreparedStatement to which the values are to be attached
@throws SQLException if JDBC objects to a setting (non-existent bind number, wrong column type etc.)
@throws DatabaseException if an I/O error occurs during the read of LOB values


public String getAbsolutePath(String path) {
        String p = path;
        File f = new File(p);
        if (!f.isAbsolute()) {
            String basePath = FilenameUtils.getFullPath(changeSet.getChangeLog().getPhysicalFilePath());
            p = FilenameUtils.normalize(basePath + p);
        }
        return p;
    }

public String getAbsolutePath ( String path ) { String p = path ; File f = new File ( p ) ; if ( ! f . isAbsolute ( ) ) { String basePath = FilenameUtils . getFullPath ( changeSet . getChangeLog ( ) . getPhysicalFilePath ( ) ) ; p = FilenameUtils . normalize ( basePath + p ) ; } return p ; }

Gets absolute and normalized path for path.
If path is relative, absolute path is calculated relative to change log file.

@param path Absolute or relative path.
@return Absolute and normalized path.

Gets absolute and normalized path for path . If path is relative absolute path is calculated relative to change log file .


public static CheckSum parse(String checksumValue) {
        if (checksumValue == null) {
            return null;
        }
        // The general layout of a checksum is:
        // <1 digit: algorithm version number>:<1..n characters alphanumeric checksum>
        // Example: 7:2cdf9876e74347162401315d34b83746
        Matcher matcher = CHECKSUM_PATTERN.matcher(checksumValue);
        if (matcher.find()) {
            return new CheckSum(matcher.group(2), Integer.parseInt(matcher.group(1)));
        } else {
            // No version information found
            return new CheckSum(checksumValue, 1);
        }
    }

Parse the given storedCheckSum string value and return a new CheckSum object.

Parse the given storedCheckSum string value and return a new CheckSum object .


public static CheckSum compute(String valueToChecksum) {
        return new CheckSum(MD5Util.computeMD5(
                //remove "Unknown" unicode char 65533
                Normalizer.normalize(
                    StringUtil.standardizeLineEndings(valueToChecksum)
                            .replace("\uFFFD", "")
                        , Normalizer.Form.NFC)
        ), getCurrentVersion());
    }

public
static
CheckSum
compute
(
String
valueToChecksum
)
{
return
new
CheckSum
(
MD5Util
.
computeMD5
(
//remove "Unknown" unicode char 65533
Normalizer
.
normalize
(
StringUtil
.
standardizeLineEndings
(
valueToChecksum
)
.
replace
(
"\uFFFD"
,
""
)
,
Normalizer
.
Form
.
NFC
)
)
,
getCurrentVersion
(
)
)
;
}

Compute a storedCheckSum of the given string.

Compute a storedCheckSum of the given string .


protected ClassLoader getClassLoaderIncludingProjectClasspath() throws MojoExecutionException {
        try {
            List classpathElements = project.getCompileClasspathElements();
            classpathElements.add(project.getBuild().getOutputDirectory());
            URL urls[] = new URL[classpathElements.size()];
            for (int i = 0; i < classpathElements.size(); ++i) {
                urls[i] = new File((String) classpathElements.get(i)).toURI().toURL();
            }
            return new URLClassLoader(urls, getMavenArtifactClassLoader());
        } catch (Exception e) {
            throw new MojoExecutionException("Failed to create project classloader", e);
        }
    }

protected
ClassLoader
getClassLoaderIncludingProjectClasspath
(
)
throws
MojoExecutionException
{
try
{
List
classpathElements
=
project
.
getCompileClasspathElements
(
)
;
classpathElements
.
add
(
project
.
getBuild
(
)
.
getOutputDirectory
(
)
)
;
URL
urls
[
]
=
new
URL
[
classpathElements
.
size
(
)
]
;
for
(
int
i
=
0
;
i
<
classpathElements
.
size
(
)
;
++
i
)
{
urls
[
i
]
=
new
File
(
(
String
)
classpathElements
.
get
(
i
)
)
.
toURI
(
)
.
toURL
(
)
;
}
return
new
URLClassLoader
(
urls
,
getMavenArtifactClassLoader
(
)
)
;
}
catch
(
Exception
e
)
{
throw
new
MojoExecutionException
(
"Failed to create project classloader"
,
e
)
;
}
}

Returns an isolated classloader.

@return ClassLoader
@noinspection unchecked


protected void printSettings(String indent) {
        if (indent == null) {
            indent = "";
        }
        getLog().info(indent + "driver: " + driver);
        getLog().info(indent + "url: " + url);
        getLog().info(indent + "username: " + username);
        getLog().info(indent + "password: " + "*****");
        getLog().info(indent + "use empty password: " + emptyPassword);
        getLog().info(indent + "properties file: " + propertyFile);
        getLog().info(indent + "properties file will override? " + propertyFileWillOverride);
        getLog().info(indent + "prompt on non-local database? " + promptOnNonLocalDatabase);
        getLog().info(indent + "clear checksums? " + clearCheckSums);
    }

protected
void
printSettings
(
String
indent
)
{
if
(
indent
==
)
{
indent
=
""
;
}
getLog
(
)
.
info
(
indent
+
"driver: "
+
driver
)
;
getLog
(
)
.
info
(
indent
+
"url: "
+
url
)
;
getLog
(
)
.
info
(
indent
+
"username: "
+
username
)
;
getLog
(
)
.
info
(
indent
+
"password: "
+
"*****"
)
;
getLog
(
)
.
info
(
indent
+
"use empty password: "
+
emptyPassword
)
;
getLog
(
)
.
info
(
indent
+
"properties file: "
+
propertyFile
)
;
getLog
(
)
.
info
(
indent
+
"properties file will override? "
+
propertyFileWillOverride
)
;
getLog
(
)
.
info
(
indent
+
"prompt on non-local database? "
+
promptOnNonLocalDatabase
)
;
getLog
(
)
.
info
(
indent
+
"clear checksums? "
+
clearCheckSums
)
;
}

Prints the settings that have been set of defaulted for the plugin. These will only
be shown in verbose mode.

@param indent The indent string to use when printing the settings.

Prints the settings that have been set of defaulted for the plugin . These will only be shown in verbose mode .


protected void parsePropertiesFile(InputStream propertiesInputStream)
            throws MojoExecutionException {
        if (propertiesInputStream == null) {
            throw new MojoExecutionException("Properties file InputStream is null.");
        }
        Properties props = new Properties();
        try {
            props.load(propertiesInputStream);
        } catch (IOException e) {
            throw new MojoExecutionException("Could not load the properties Liquibase file", e);
        }

        for (Iterator it = props.keySet().iterator(); it.hasNext(); ) {
            String key = null;
            try {
                key = (String) it.next();
                Field field = MavenUtils.getDeclaredField(this.getClass(), key);

                if (propertyFileWillOverride) {
                    getLog().debug("  properties file setting value: " + field.getName());
                    setFieldValue(field, props.get(key).toString());
                } else {
                    if (!isCurrentFieldValueSpecified(field)) {
                        getLog().debug("  properties file setting value: " + field.getName());
                        setFieldValue(field, props.get(key).toString());
                    }
                }
            } catch (Exception e) {
                getLog().info("  '" + key + "' in properties file is not being used by this "
                        + "task.");
            }
        }
    }

Parses a properties file and sets the associated fields in the plugin.

@param propertiesInputStream The input stream which is the Liquibase properties that
needs to be parsed.
@throws org.apache.maven.plugin.MojoExecutionException If there is a problem parsing
the file.

Parses a properties file and sets the associated fields in the plugin .


private boolean isCurrentFieldValueSpecified(Field f) throws IllegalAccessException {
        Object currentValue = f.get(this);
        if (currentValue == null) {
            return false;
        }

        Object defaultValue = getDefaultValue(f);
        if (defaultValue == null) {
            return currentValue != null;
        } else {
            // There is a default value, check to see if the user has selected something other
            // than the default
            return !defaultValue.equals(f.get(this));
        }
    }

This method will check to see if the user has specified a value different to that of
the default value. This is not an ideal solution, but should cover most situations in
the use of the plugin.

@param f The Field to check if a user has specified a value for.
@return true if the user has specified a value.

This method will check to see if the user has specified a value different to that of the default value . This is not an ideal solution but should cover most situations in the use of the plugin .


public void writeNext(String[] nextLine, boolean applyQuotesToAll) {

      if (nextLine == null) {
         return;
      }

      StringBuilder sb = new StringBuilder(nextLine.length * 2); // This is for the worse case where all elements have to be escaped.
      for (int i = 0; i < nextLine.length; i++) {

         if (i != 0) {
            sb.append(separator);
         }

         String nextElement = nextLine[i];

         if (nextElement == null) {
            continue;
         }

         Boolean stringContainsSpecialCharacters = stringContainsSpecialCharacters(nextElement);

         if ((applyQuotesToAll || stringContainsSpecialCharacters) && (quotechar != NO_QUOTE_CHARACTER)) {
            sb.append(quotechar);
         }

         if (stringContainsSpecialCharacters) {
            sb.append(processLine(nextElement));
         } else {
            sb.append(nextElement);
         }

         if ((applyQuotesToAll || stringContainsSpecialCharacters) && (quotechar != NO_QUOTE_CHARACTER)) {
            sb.append(quotechar);
         }
      }

      sb.append(lineEnd);
      pw.write(sb.toString());
   }

Writes the next line to the file.

@param nextLine         a string array with each comma-separated element as a separate
entry.
@param applyQuotesToAll true if all values are to be quoted.  false applies quotes only
to values which contain the separator, escape, quote or new line characters.


protected boolean stringContainsSpecialCharacters(String line) {
      return (line.indexOf(quotechar) != -1) || (line.indexOf(escapechar) != -1) || (line.indexOf(separator) != -1)
          || line.contains(DEFAULT_LINE_END) || line.contains("\r");
   }

protected boolean stringContainsSpecialCharacters ( String line ) { return ( line . indexOf ( quotechar ) != - 1 ) || ( line . indexOf ( escapechar ) != - 1 ) || ( line . indexOf ( separator ) != - 1 ) || line . contains ( DEFAULT_LINE_END ) || line . contains ( "\r" ) ; }

checks to see if the line contains special characters.
@param line - element of data to check for special characters.
@return true if the line contains the quote, escape, separator, newline or return.

checks to see if the line contains special characters .


protected StringBuilder processLine(String nextElement) {
      StringBuilder sb = new StringBuilder(nextElement.length() * 2); // this is for the worse case where all elements have to be escaped.
      for (int j = 0; j < nextElement.length(); j++) {
         char nextChar = nextElement.charAt(j);
         processCharacter(sb, nextChar);
      }

      return sb;
   }

Processes all the characters in a line.
@param nextElement - element to process.
@return a StringBuilder with the elements data.

Processes all the characters in a line .


private void processCharacter(StringBuilder sb, char nextChar) {
      if ((escapechar != NO_ESCAPE_CHARACTER) && checkCharactersToEscape(nextChar)) {
         sb.append(escapechar).append(nextChar);
      } else {
         sb.append(nextChar);
      }
   }

private void processCharacter ( StringBuilder sb , char nextChar ) { if ( ( escapechar != NO_ESCAPE_CHARACTER ) && checkCharactersToEscape ( nextChar ) ) { sb . append ( escapechar ) . append ( nextChar ) ; } else { sb . append ( nextChar ) ; } }

Appends the character to the StringBuilder adding the escape character if needed.
@param sb - StringBuffer holding the processed character.
@param nextChar - character to process

Appends the character to the StringBuilder adding the escape character if needed .


private void executeUpdate(ServletContext servletContext, InitialContext ic) throws NamingException, SQLException, LiquibaseException {
        setDataSource((String) servletValueContainer.getValue(LIQUIBASE_DATASOURCE));
        if (getDataSource() == null) {
            throw new RuntimeException("Cannot run Liquibase, " + LIQUIBASE_DATASOURCE + " is not set");
        }

        setChangeLogFile((String) servletValueContainer.getValue(LIQUIBASE_CHANGELOG));
        if (getChangeLogFile() == null) {
            throw new RuntimeException("Cannot run Liquibase, " + LIQUIBASE_CHANGELOG + " is not set");
        }

        setContexts((String) servletValueContainer.getValue(LIQUIBASE_CONTEXTS));
        setLabels((String) servletValueContainer.getValue(LIQUIBASE_LABELS));
        this.defaultSchema = StringUtil.trimToNull((String) servletValueContainer.getValue(LIQUIBASE_SCHEMA_DEFAULT));

        Connection connection = null;
        Database database = null;
        try {
            DataSource dataSource = (DataSource) ic.lookup(this.dataSourceName);

            connection = dataSource.getConnection();

            Thread currentThread = Thread.currentThread();
            ClassLoader contextClassLoader = currentThread.getContextClassLoader();
            ResourceAccessor threadClFO = new ClassLoaderResourceAccessor(contextClassLoader);

            ResourceAccessor clFO = new ClassLoaderResourceAccessor();
            ResourceAccessor fsFO = new FileSystemResourceAccessor();

            database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
            database.setDefaultSchemaName(getDefaultSchema());
            Liquibase liquibase = new Liquibase(getChangeLogFile(), new CompositeResourceAccessor(clFO, fsFO, threadClFO), database);

            @SuppressWarnings("unchecked")
            Enumeration<String> initParameters = servletContext.getInitParameterNames();
            while (initParameters.hasMoreElements()) {
                String name = initParameters.nextElement().trim();
                if (name.startsWith(LIQUIBASE_PARAMETER + ".")) {
                    liquibase.setChangeLogParameter(name.substring(LIQUIBASE_PARAMETER.length() + 1), servletValueContainer.getValue(name));
                }
            }

            liquibase.update(new Contexts(getContexts()), new LabelExpression(getLabels()));
        }
        finally {
            if (database != null) {
                database.close();
            } else if (connection != null) {
                connection.close();
            }
        }
    }

private
void
executeUpdate
(
ServletContext
servletContext
,
InitialContext
ic
)
throws
NamingException
,
SQLException
,
LiquibaseException
{
setDataSource
(
(
String
)
servletValueContainer
.
getValue
(
LIQUIBASE_DATASOURCE
)
)
;
if
(
getDataSource
(
)
==
)
{
throw
new
RuntimeException
(
"Cannot run Liquibase, "
+
LIQUIBASE_DATASOURCE
+
" is not set"
)
;
}
setChangeLogFile
(
(
String
)
servletValueContainer
.
getValue
(
LIQUIBASE_CHANGELOG
)
)
;
if
(
getChangeLogFile
(
)
==
)
{
throw
new
RuntimeException
(
"Cannot run Liquibase, "
+
LIQUIBASE_CHANGELOG
+
" is not set"
)
;
}
setContexts
(
(
String
)
servletValueContainer
.
getValue
(
LIQUIBASE_CONTEXTS
)
)
;
setLabels
(
(
String
)
servletValueContainer
.
getValue
(
LIQUIBASE_LABELS
)
)
;
this
.
defaultSchema
=
StringUtil
.
trimToNull
(
(
String
)
servletValueContainer
.
getValue
(
LIQUIBASE_SCHEMA_DEFAULT
)
)
;
Connection
connection
=
;
Database
database
=
;
try
{
DataSource
dataSource
=
(
DataSource
)
ic
.
lookup
(
this
.
dataSourceName
)
;
connection
=
dataSource
.
getConnection
(
)
;
Thread
currentThread
=
Thread
.
currentThread
(
)
;
ClassLoader
contextClassLoader
=
currentThread
.
getContextClassLoader
(
)
;
ResourceAccessor
threadClFO
=
new
ClassLoaderResourceAccessor
(
contextClassLoader
)
;
ResourceAccessor
clFO
=
new
ClassLoaderResourceAccessor
(
)
;
ResourceAccessor
fsFO
=
new
FileSystemResourceAccessor
(
)
;
database
=
DatabaseFactory
.
getInstance
(
)
.
findCorrectDatabaseImplementation
(
new
JdbcConnection
(
connection
)
)
;
database
.
setDefaultSchemaName
(
getDefaultSchema
(
)
)
;
Liquibase
liquibase
=
new
Liquibase
(
getChangeLogFile
(
)
,
new
CompositeResourceAccessor
(
clFO
,
fsFO
,
threadClFO
)
,
database
)
;
@
SuppressWarnings
(
"unchecked"
)
Enumeration
<
String
>
initParameters
=
servletContext
.
getInitParameterNames
(
)
;
while
(
initParameters
.
hasMoreElements
(
)
)
{
String
name
=
initParameters
.
nextElement
(
)
.
trim
(
)
;
if
(
name
.
startsWith
(
LIQUIBASE_PARAMETER
+
"."
)
)
{
liquibase
.
setChangeLogParameter
(
name
.
substring
(
LIQUIBASE_PARAMETER
.
length
(
)
+
1
)
,
servletValueContainer
.
getValue
(
name
)
)
;
}
}
liquibase
.
update
(
new
Contexts
(
getContexts
(
)
)
,
new
LabelExpression
(
getLabels
(
)
)
)
;
}
finally
{
if
(
database
!=
)
{
database
.
close
(
)
;
}
else
if
(
connection
!=
)
{
connection
.
close
(
)
;
}
}
}


protected Object valueOf(Object value) {
        if (value == null) {
            return value;
        } else if (type.isAssignableFrom(value.getClass())) {
            return value;
        } else if (value instanceof String) {
            if (type.equals(Boolean.class)) {
                return Boolean.valueOf((String) value);
            } else if (type.equals(Integer.class)) {
                return Integer.valueOf((String) value);
            } else if (type.equals(BigDecimal.class)) {
                return new BigDecimal((String) value);
            } else if (type.equals(Long.class)) {
            	return Long.valueOf((String) value);
            } else if (type.equals(List.class)) {
                return StringUtil.splitAndTrim((String) value, ",");
            } else {
                throw new UnexpectedLiquibaseException("Cannot parse property "+value.getClass().getSimpleName()+" to a "+type.getSimpleName());
            }
        } else {
            throw new UnexpectedLiquibaseException("Could not convert "+value.getClass().getSimpleName()+" to a "+type.getSimpleName());
        }
    }

protected
Object
valueOf
(
Object
value
)
{
if
(
value
==
)
{
return
value
;
}
else
if
(
type
.
isAssignableFrom
(
value
.
getClass
(
)
)
)
{
return
value
;
}
else
if
(
value
instanceof
String
)
{
if
(
type
.
equals
(
Boolean
.
class
)
)
{
return
Boolean
.
valueOf
(
(
String
)
value
)
;
}
else
if
(
type
.
equals
(
Integer
.
class
)
)
{
return
Integer
.
valueOf
(
(
String
)
value
)
;
}
else
if
(
type
.
equals
(
BigDecimal
.
class
)
)
{
return
new
BigDecimal
(
(
String
)
value
)
;
}
else
if
(
type
.
equals
(
Long
.
class
)
)
{
return
Long
.
valueOf
(
(
String
)
value
)
;
}
else
if
(
type
.
equals
(
List
.
class
)
)
{
return
StringUtil
.
splitAndTrim
(
(
String
)
value
,
","
)
;
}
else
{
throw
new
UnexpectedLiquibaseException
(
"Cannot parse property "
+
value
.
getClass
(
)
.
getSimpleName
(
)
+
" to a "
+
type
.
getSimpleName
(
)
)
;
}
}
else
{
throw
new
UnexpectedLiquibaseException
(
"Could not convert "
+
value
.
getClass
(
)
.
getSimpleName
(
)
+
" to a "
+
type
.
getSimpleName
(
)
)
;
}
}

Converts an object of a different type to the type used by this property. If types are not convertible, an exception is thrown.

Converts an object of a different type to the type used by this property . If types are not convertible an exception is thrown .


public <T> T getValue(Class<T> type) {
        if (!this.type.isAssignableFrom(type)) {
            throw new UnexpectedLiquibaseException("Property "+name+" on is of type "+this.type.getSimpleName()+", not "+type.getSimpleName());
        }

        return (T) value;
    }

public
<
T
>
T
getValue
(
Class
<
T
>
type
)
{
if
(
!
this
.
type
.
isAssignableFrom
(
type
)
)
{
throw
new
UnexpectedLiquibaseException
(
"Property "
+
name
+
" on is of type "
+
this
.
type
.
getSimpleName
(
)
+
", not "
+
type
.
getSimpleName
(
)
)
;
}
return
(
T
)
value
;
}

Returns the value currently stored in this property cast to the given type.

Returns the value currently stored in this property cast to the given type .


public void setValue(Object value) {
        if ((value != null) && !type.isAssignableFrom(value.getClass())) {
            throw new UnexpectedLiquibaseException("Property "+name+" on is of type "+type.getSimpleName()+", not "+value.getClass().getSimpleName());
        }

        this.value = value;
        wasOverridden = true;
    }

public
void
setValue
(
Object
value
)
{
if
(
(
value
!=
)
&&
!
type
.
isAssignableFrom
(
value
.
getClass
(
)
)
)
{
throw
new
UnexpectedLiquibaseException
(
"Property "
+
name
+
" on is of type "
+
type
.
getSimpleName
(
)
+
", not "
+
value
.
getClass
(
)
.
getSimpleName
(
)
)
;
}
this
.
value
=
value
;
wasOverridden
=
true
;
}

Overwrites the value currently stored in this property. It he passed type is not compatible with the defined type, an exception is thrown.

Overwrites the value currently stored in this property . It he passed type is not compatible with the defined type an exception is thrown .


public ConfigurationProperty addAlias(String... aliases) {
        if (aliases != null) {
            this.aliases.addAll(Arrays.asList(aliases));
        }

        return this;
    }

public ConfigurationProperty addAlias ( String ... aliases ) { if ( aliases != null ) { this . aliases . addAll ( Arrays . asList ( aliases ) ) ; } return this ; }

Adds an alias for this property. An alias is an alternate to the "name" field that can be used by the ConfigurationProvers to look up starting values.

Adds an alias for this property . An alias is an alternate to the name field that can be used by the ConfigurationProvers to look up starting values .


public ConfigurationProperty setDefaultValue(Object defaultValue) {
        if ((defaultValue != null) && !type.isAssignableFrom(defaultValue.getClass())) {
            if ((type == Long.class) && (defaultValue instanceof Integer)) {
                return setDefaultValue(((Integer) defaultValue).longValue());
            }
            throw new UnexpectedLiquibaseException("Property "+name+" on is of type "+type.getSimpleName()+", not "+defaultValue.getClass().getSimpleName());
        }

        this.defaultValue = defaultValue;

        return this;
    }

public
ConfigurationProperty
setDefaultValue
(
Object
defaultValue
)
{
if
(
(
defaultValue
!=
)
&&
!
type
.
isAssignableFrom
(
defaultValue
.
getClass
(
)
)
)
{
if
(
(
type
==
Long
.
class
)
&&
(
defaultValue
instanceof
Integer
)
)
{
return
setDefaultValue
(
(
(
Integer
)
defaultValue
)
.
longValue
(
)
)
;
}
throw
new
UnexpectedLiquibaseException
(
"Property "
+
name
+
" on is of type "
+
type
.
getSimpleName
(
)
+
", not "
+
defaultValue
.
getClass
(
)
.
getSimpleName
(
)
)
;
}
this
.
defaultValue
=
defaultValue
;
return
this
;
}

Sets the default value to use if no ConfigurationProviders override it. Throws an exception if the given object is not compatible with the defined type.

Sets the default value to use if no ConfigurationProviders override it . Throws an exception if the given object is not compatible with the defined type .


@Override
    public Sql[] generateSql(CreateIndexStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain)  {
        /*
         * According to https://firebirdsql.org/refdocs/langrefupd20-create-table.html#langrefupd20-ct-using-index ,
         * Firebird automatically creates indexes for PRIMARY KEY, UNIQUE KEY and FOREIGN KEY constraints,
         * so we should not duplicate that functionality (=we should not issue CREATE INDEX statements for them)
         */
        List<String> associatedWith = StringUtil.splitAndTrim(statement.getAssociatedWith(), ",");
        if ((associatedWith != null) && (associatedWith.contains(Index.MARK_PRIMARY_KEY) || associatedWith.contains
            (Index.MARK_UNIQUE_CONSTRAINT) || associatedWith.contains(Index.MARK_FOREIGN_KEY))) {
            return new Sql[0];
        }

        StringBuffer buffer = new StringBuffer();

        buffer.append("CREATE ");

        // If the statement wants a UNIQUE index, issue a CREATE UNIQUE ... INDEX statement.
        if ((statement.isUnique() != null) && statement.isUnique()) {
            buffer.append("UNIQUE ");
        }

        /*
         * Examine the direction (ASCending or DESCending) of all columns of the planned index. If _all_ of them
         * are DESC, issue a CREATE DESCENDING INDEX statement. If all of them are ASC, we do not need to do anything
         * special (ASCENDING is the default). However, since Firebird does not seem to support mixed ASC/DESC
         * columns within a single index, we must error out.
         *
         * The syntax we want to create is this:
         * CREATE [UNIQUE] [ASC[ENDING] | DESC[ENDING]] INDEX index_name ON table_name
          * {(col [, col …]) | COMPUTED BY (<expression>)};
         */
        ColumnAnalysisResult result = analyseColumns(statement, database);

        if (result.isFoundDescColumns())
            buffer.append("DESCENDING ");

        buffer.append("INDEX ");

        if (statement.getIndexName() != null) {
            String indexSchema = statement.getTableSchemaName();
            buffer.append(database.escapeIndexName(statement.getTableCatalogName(), indexSchema,
                    statement.getIndexName())).append(" ");
        }

        buffer.append("ON ");
        // append table name
        buffer.append(database.escapeTableName(statement.getTableCatalogName(), statement.getTableSchemaName(),
                statement.getTableName()));

        if (result.getNumComputedCols() > 0)
            buffer.append("COMPUTED BY ");

        buffer.append(String.format("(%s)", result.getColumnExpression()));

        return new Sql[]{new UnparsedSql(buffer.toString(), getAffectedIndex(statement))};
    }

Generate a CREATE INDEX SQL statement for Firebird databases.
@param statement A CreateIndexStatement with the desired properties of the SQL to be generated
@param database A database object (must be of FirebirdDatabase type, or we will error out)
@param sqlGeneratorChain The other generators in the current chain (ignored by this implementation)
@return An array with one entry containing the generated CREATE INDEX statement for Firebird.

Generate a CREATE INDEX SQL statement for Firebird databases .


private boolean applyIsComputedExpressionHeuristic(ColumnConfig column, Database database) {
        String expr = column.getName();

        /*
         * https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-structure-identifiers.html
         * says the following about what makes a valid identifier in Firebird:
         * - At most 31 chars
         * - Starts with a 7-bit character
         * - After that, letters, digits, underscores or dollar signs are valid characters
         */
        String regex = "^(?i)[ABCDEFGHIJKLMNOPQRSTUVWXYZ]" // Starting character
                + "[ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$]{0,30}$"; // following characters
        if (!expr.matches(regex))
            return true;

        /* At this point, we know that expr at least has the form of an identifier. If it is a function, it must
         * be in the list of database functions.
         */
        if (database.isFunction(expr))
            return true;
        else
            return false;
    }

An imperfect heuristic to determine if an expression is more likely a column name or a computed expression.
@return true if it is more likely an expression, false if it is more likely a column name (identifier).

An imperfect heuristic to determine if an expression is more likely a column name or a computed expression .


public void tag(String tagString) throws LiquibaseException {
        LockService lockService = LockServiceFactory.getInstance().getLockService(database);
        lockService.waitForLock();

        try {
            ChangeLogHistoryServiceFactory.getInstance().getChangeLogService(database).generateDeploymentId();

            checkLiquibaseTables(false, null, new Contexts(),
                new LabelExpression());
            getDatabase().tag(tagString);
        } finally {
            try {
                lockService.releaseLock();
            } catch (LockException e) {
                LOG.severe(LogType.LOG, MSG_COULD_NOT_RELEASE_LOCK, e);
            }
        }
    }

public void tag ( String tagString ) throws LiquibaseException { LockService lockService = LockServiceFactory . getInstance ( ) . getLockService ( database ) ; lockService . waitForLock ( ) ; try { ChangeLogHistoryServiceFactory . getInstance ( ) . getChangeLogService ( database ) . generateDeploymentId ( ) ; checkLiquibaseTables ( false , null , new Contexts ( ) , new LabelExpression ( ) ) ; getDatabase ( ) . tag ( tagString ) ; } finally { try { lockService . releaseLock ( ) ; } catch ( LockException e ) { LOG . severe ( LogType . LOG , MSG_COULD_NOT_RELEASE_LOCK , e ) ; } } }


public DatabaseChangeLogLock[] listLocks() throws LiquibaseException {
        checkLiquibaseTables(false, null, new Contexts(), new LabelExpression());

        return LockServiceFactory.getInstance().getLockService(database).listLocks();
    }

public DatabaseChangeLogLock [ ] listLocks ( ) throws LiquibaseException { checkLiquibaseTables ( false , null , new Contexts ( ) , new LabelExpression ( ) ) ; return LockServiceFactory . getInstance ( ) . getLockService ( database ) . listLocks ( ) ; }


public List<ChangeSetStatus> getChangeSetStatuses(Contexts contexts, LabelExpression labelExpression,
                                                      boolean checkLiquibaseTables) throws LiquibaseException {
        changeLogParameters.setContexts(contexts);
        changeLogParameters.setLabels(labelExpression);

        DatabaseChangeLog changeLog = getDatabaseChangeLog();

        if (checkLiquibaseTables) {
            checkLiquibaseTables(true, changeLog, contexts, labelExpression);
        }

        changeLog.validate(database, contexts, labelExpression);

        ChangeLogIterator logIterator = getStandardChangelogIterator(contexts, labelExpression, changeLog);

        StatusVisitor visitor = new StatusVisitor(database);
        logIterator.run(visitor, new RuntimeEnvironment(database, contexts, labelExpression));
        return visitor.getStatuses();
    }

public List < ChangeSetStatus > getChangeSetStatuses ( Contexts contexts , LabelExpression labelExpression , boolean checkLiquibaseTables ) throws LiquibaseException { changeLogParameters . setContexts ( contexts ) ; changeLogParameters . setLabels ( labelExpression ) ; DatabaseChangeLog changeLog = getDatabaseChangeLog ( ) ; if ( checkLiquibaseTables ) { checkLiquibaseTables ( true , changeLog , contexts , labelExpression ) ; } changeLog . validate ( database , contexts , labelExpression ) ; ChangeLogIterator logIterator = getStandardChangelogIterator ( contexts , labelExpression , changeLog ) ; StatusVisitor visitor = new StatusVisitor ( database ) ; logIterator . run ( visitor , new RuntimeEnvironment ( database , contexts , labelExpression ) ) ; return visitor . getStatuses ( ) ; }

Returns the ChangeSetStatuses of all changesets in the change log file and history in the order they
would be ran.

Returns the ChangeSetStatuses of all changesets in the change log file and history in the order they would be ran .


public void clearCheckSums() throws LiquibaseException {
        LOG.info(LogType.LOG, "Clearing database change log checksums");
        LockService lockService = LockServiceFactory.getInstance().getLockService(database);
        lockService.waitForLock();

        try {
            checkLiquibaseTables(false, null, new Contexts(), new LabelExpression());

            UpdateStatement updateStatement = new UpdateStatement(
                getDatabase().getLiquibaseCatalogName(),
                getDatabase().getLiquibaseSchemaName(),
                getDatabase().getDatabaseChangeLogTableName()
            );
            updateStatement.addNewColumnValue("MD5SUM", null);
            ExecutorService.getInstance().getExecutor(database).execute(updateStatement);
            getDatabase().commit();
        } finally {
            try {
                lockService.releaseLock();
            } catch (LockException e) {
                LOG.severe(LogType.LOG, MSG_COULD_NOT_RELEASE_LOCK, e);
            }
        }
        resetServices();
    }

Sets checksums to null so they will be repopulated next run


public List<T> parse(MappingStrategy<T> mapper, Reader reader) {
      return parse(mapper, new CSVReader(reader));
   }

public List < T > parse ( MappingStrategy < T > mapper , Reader reader ) { return parse ( mapper , new CSVReader ( reader ) ) ; }

parse the values from a csvReader constructed from the passed in Reader.
@param mapper - mapping strategy for the bean.
@param reader - Reader used to construct a CSVReader
@return List of Objects.

parse the values from a csvReader constructed from the passed in Reader .


protected T processLine(MappingStrategy<T> mapper, String[] line) throws ReflectiveOperationException, IntrospectionException {
      T bean = mapper.createBean();
      for (int col = 0; col < line.length; col++) {
         if (mapper.isAnnotationDriven()) {
            processField(mapper, line, bean, col);
         } else {
            processProperty(mapper, line, bean, col);
         }
      }
      return bean;
   }

protected T processLine ( MappingStrategy < T > mapper , String [ ] line ) throws ReflectiveOperationException , IntrospectionException { T bean = mapper . createBean ( ) ; for ( int col = 0 ; col < line . length ; col ++ ) { if ( mapper . isAnnotationDriven ( ) ) { processField ( mapper , line , bean , col ) ; } else { processProperty ( mapper , line , bean , col ) ; } } return bean ; }

Creates a single object from a line from the csv file.
@param mapper - MappingStrategy
@param line  - array of Strings from the csv file.
@return - object containing the values.
@throws ReflectiveOperationException - thrown on error accessing bean.
@throws IntrospectionException - thrown on error getting the PropertyDescriptor.

Creates a single object from a line from the csv file .


protected PropertyEditor getPropertyEditor(PropertyDescriptor desc) throws ReflectiveOperationException {
      Class<?> cls = desc.getPropertyEditorClass();
      if (null != cls) {
         return (PropertyEditor) cls.getConstructor().newInstance();
      }
      return getPropertyEditorValue(desc.getPropertyType());
   }

protected PropertyEditor getPropertyEditor ( PropertyDescriptor desc ) throws ReflectiveOperationException { Class < ? > cls = desc . getPropertyEditorClass ( ) ; if ( null != cls ) { return ( PropertyEditor ) cls . getConstructor ( ) . newInstance ( ) ; } return getPropertyEditorValue ( desc . getPropertyType ( ) ) ; }

Attempt to find custom property editor on descriptor first, else try the propery editor manager.

@param desc - PropertyDescriptor.
@return - the PropertyEditor for the given PropertyDescriptor.
@throws ReflectiveOperationException - thrown when getting the PropertyEditor for the class.

Attempt to find custom property editor on descriptor first else try the propery editor manager .


protected void loadImplementationsInJar(
            String parentPackage,
            InputStream parentFileStream,
            ClassLoader loader,
            String parentFileName,
            String grandparentFileName) throws IOException {
        Set<String> classFiles = classFilesByLocation.get(parentFileName);

        if (classFiles == null) {
            classFiles = new HashSet<String>();
            classFilesByLocation.put(parentFileName, classFiles);

            Set<String> grandparentClassFiles = classFilesByLocation.get(grandparentFileName);
            if (grandparentClassFiles == null) {
                grandparentClassFiles = new HashSet<String>();
                classFilesByLocation.put(grandparentFileName, grandparentClassFiles);
            }
            JarInputStream jarStream;
            if (parentFileStream instanceof JarInputStream) {
                jarStream = (JarInputStream) parentFileStream;
            } else {
                jarStream = new JarInputStream(parentFileStream);
            }

            JarEntry entry;
            while ((entry = jarStream.getNextJarEntry()) != null) {
                String name = entry.getName();
                if (name != null) {
                    if (name.endsWith(".jar")) { //in a nested jar
                        log.fine(LogType.LOG, "Found nested jar " + name);

                        // To avoid needing to unzip 'parentFile' in its entirety, as that
                        // may take a very long time (see CORE-2115) or not even be possible
                        // (see CORE-2595), we load the nested JAR from the classloader and
                        // read it as a zip.
                        //
                        // It is safe to assume that the nested JAR is readable by the classloader
                        // as a resource stream, because we have reached this point by scanning
                        // through packages located from `classloader` by using `getResource`.
                        // If loading this nested JAR as a resource fails, then certainly loading
                        // classes from inside it with `classloader` would fail and we are safe
                        // to exclude it form the PackageScan.
                        InputStream nestedJarResourceStream = loader.getResourceAsStream(name);
                        if (nestedJarResourceStream != null) {
                            JarInputStream nestedJarStream = new JarInputStream(nestedJarResourceStream);
                            try {
                                loadImplementationsInJar(
                                        parentPackage,
                                        nestedJarStream,
                                        loader,
                                        parentFileName + "!" + name,
                                        parentFileName);
                            } finally {
                                nestedJarStream.close();
                            }
                        }
                    } else if (!entry.isDirectory() && name.endsWith(".class")) {
                        classFiles.add(name.trim());
                        grandparentClassFiles.add(name.trim());
                    }
                }
            }
        }

        for (String name : classFiles) {
            if (name.contains(parentPackage)) {
                loadClass(name, loader);
            }
        }
    }

Finds matching classes within a jar files that contains a folder
structure matching the package structure. If the File is not a JarFile or
does not exist a warning will be logged, but no error will be raised.

Any nested JAR files found inside this JAR will be assumed to also be
on the classpath and will be recursively examined for classes in `parentPackage`.
@param parentPackage  the parent package under which classes must be in order to
be considered
@param parentFileStream  the inputstream of the jar file to be examined for classes
@param loader a classloader which can load classes contained within the JAR file
@param parentFileName a unique name for the parentFileStream, to be used for caching.
This is the URL of the parentFileStream, if it comes from a URL,
or a composite ID if we are currently examining a nested JAR.

Finds matching classes within a jar files that contains a folder structure matching the package structure . If the File is not a JarFile or does not exist a warning will be logged but no error will be raised .


protected void addIfMatching(PackageScanFilter test, String fqn, Set<Class<?>> classes) {
        try {
            String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
            Set<ClassLoader> set = getClassLoaders();
            boolean found = false;
            for (ClassLoader classLoader : set) {
                log.fine(LogType.LOG, "Testing that class " + externalName + " matches criteria [" + test + "] using classloader:" + classLoader);
                try {
                    Class<?> type = classLoader.loadClass(externalName);
                    log.fine(LogType.LOG, "Loaded the class: " + type + " in classloader: " + classLoader);
                    if (test.matches(type)) {
                        log.fine(LogType.LOG, "Found class: " + type + " which matches the filter in classloader: " + classLoader);
                        classes.add(type);
                    }
                    found = true;
                    break;
                } catch (ClassNotFoundException e) {
                    log.fine(LogType.LOG, "Cannot find class '" + fqn + "' in classloader: " + classLoader
                            + ". Reason: " + e, e);
                } catch (LinkageError e) {
                    log.fine(LogType.LOG, "Cannot find the class definition '" + fqn + "' in classloader: " + classLoader
                            + ". Reason: " + e, e);
                } catch (Exception e) {
                    log.severe(LogType.LOG, "Cannot load class '"+fqn+"' in classloader: "+classLoader+".  Reason: "+e, e);
                }
            }
            if (!found) {
                // use debug to avoid being noisy in logs
                log.fine(LogType.LOG, "Cannot find class '" + fqn + "' in any classloaders: " + set);
            }
        } catch (Exception e) {
            log.warning(LogType.LOG, "Cannot examine class '" + fqn + "' due to a " + e.getClass().getName()
                    + " with message: " + e.getMessage(), e);
        }
    }

Add the class designated by the fully qualified class name provided to
the set of resolved classes if and only if it is approved by the Test
supplied.

@param test the test used to determine if the class matches
@param fqn  the fully qualified name of a class

Add the class designated by the fully qualified class name provided to the set of resolved classes if and only if it is approved by the Test supplied .


public static Class getPropertyType(Object object, String propertyName) {
        Method readMethod = getReadMethod(object, propertyName);
        if (readMethod == null) {
            return null;
        }
        return readMethod.getReturnType();
    }

public static Class getPropertyType ( Object object , String propertyName ) { Method readMethod = getReadMethod ( object , propertyName ) ; if ( readMethod == null ) { return null ; } return readMethod . getReturnType ( ) ; }

Tried to determine the appropriate reader method for a given propertyName of a given object and, if found,
returns the class of its return type.
@param object the object to examine
@param propertyName the property name whose reading method should be searched
@return the class name of the return type if the reading method is found, null if it is not found.

Tried to determine the appropriate reader method for a given propertyName of a given object and if found returns the class of its return type .


public static boolean hasProperty(Object object, String propertyName) {
        return hasReadProperty(object, propertyName) && hasWriteProperty(object, propertyName);
    }

public static boolean hasProperty ( Object object , String propertyName ) { return hasReadProperty ( object , propertyName ) && hasWriteProperty ( object , propertyName ) ; }

Examines the given object's class and returns true if reader and writer methods both exist for the
given property name.
@param object the object for which the class should be examined
@param propertyName the property name to search
@return true if both reader and writer methods exist

Examines the given object s class and returns true if reader and writer methods both exist for the given property name .


public static void setProperty(Object object, String propertyName, String propertyValue)  {
        Method method = getWriteMethod(object, propertyName);
        if (method == null) {
            throw new UnexpectedLiquibaseException (
                String.format("Property [%s] was not found for object type [%s]", propertyName,
                    object.getClass().getName()
                ));
        }

        Class<?> parameterType = method.getParameterTypes()[0];
        Object finalValue = propertyValue;
        if (parameterType.equals(Boolean.class) || parameterType.equals(boolean.class)) {
            finalValue = Boolean.valueOf(propertyValue);
        } else if (parameterType.equals(Integer.class)) {
            finalValue = Integer.valueOf(propertyValue);
        } else if (parameterType.equals(Long.class)) {
            finalValue = Long.valueOf(propertyValue);
        } else if (parameterType.equals(BigInteger.class)) {
            finalValue = new BigInteger(propertyValue);
        } else if (parameterType.equals(BigDecimal.class)) {
            finalValue = new BigDecimal(propertyValue);
        } else if (parameterType.equals(DatabaseFunction.class)) {
            finalValue = new DatabaseFunction(propertyValue);
        } else if (parameterType.equals(SequenceNextValueFunction.class)) {
            finalValue = new SequenceNextValueFunction(propertyValue);
        } else if (parameterType.equals(SequenceCurrentValueFunction.class)) {
            finalValue = new SequenceCurrentValueFunction(propertyValue);
        } else if (Enum.class.isAssignableFrom(parameterType)) {
            finalValue = Enum.valueOf((Class<Enum>) parameterType, propertyValue);
        }
        try {
            method.invoke(object, finalValue);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new UnexpectedLiquibaseException(e);
        } catch (IllegalArgumentException e) {
            throw new UnexpectedLiquibaseException("Cannot call " + method.toString()
                + " with value of type " + finalValue.getClass().getName());
        }
    }

Tries to guess the "real" data type of propertyValue by the given propertyName, then sets the
selected property of the given object to that value.
@param object                        the object whose property should be set
@param propertyName                  name of the property to set
@param propertyValue                 new value of the property, as String

Tries to guess the real data type of propertyValue by the given propertyName then sets the selected property of the given object to that value .


private static Method getReadMethod(Object object, String propertyName) {
        String getMethodName = "get" + propertyName.substring(0, 1).toUpperCase(Locale.ENGLISH)
            + propertyName.substring(1);
        String isMethodName = "is" + propertyName.substring(0, 1).toUpperCase(Locale.ENGLISH)
            + propertyName.substring(1);

        Method[] methods = getMethods(object);

        for (Method method : methods) {
            if ((method.getName().equals(getMethodName) || method.getName().equals(isMethodName)) && (method
                .getParameterTypes().length == 0)) {
                return method;
            }
        }
        return null;
    }

private static Method getReadMethod ( Object object , String propertyName ) { String getMethodName = "get" + propertyName . substring ( 0 , 1 ) . toUpperCase ( Locale . ENGLISH ) + propertyName . substring ( 1 ) ; String isMethodName = "is" + propertyName . substring ( 0 , 1 ) . toUpperCase ( Locale . ENGLISH ) + propertyName . substring ( 1 ) ; Method [ ] methods = getMethods ( object ) ; for ( Method method : methods ) { if ( ( method . getName ( ) . equals ( getMethodName ) || method . getName ( ) . equals ( isMethodName ) ) && ( method . getParameterTypes ( ) . length == 0 ) ) { return method ; } } return null ; }

Tries to find the Java method to read a given propertyName for the given object.
@param object the object whose class will be examined
@param propertyName the property name for which the read method should be searched
@return the {@link Method} if found, null in all other cases.

Tries to find the Java method to read a given propertyName for the given object .


private static Method getWriteMethod(Object object, String propertyName) {
        String methodName = "set"
            + propertyName.substring(0, 1).toUpperCase(Locale.ENGLISH) + propertyName.substring(1);
        Method[] methods = getMethods(object);

        for (Method method : methods) {
            if (method.getName().equals(methodName) && (method.getParameterTypes().length == 1)) {
                return method;
            }
        }
        return null;
    }

private static Method getWriteMethod ( Object object , String propertyName ) { String methodName = "set" + propertyName . substring ( 0 , 1 ) . toUpperCase ( Locale . ENGLISH ) + propertyName . substring ( 1 ) ; Method [ ] methods = getMethods ( object ) ; for ( Method method : methods ) { if ( method . getName ( ) . equals ( methodName ) && ( method . getParameterTypes ( ) . length == 1 ) ) { return method ; } } return null ; }

Tries to find the Java method to write a new value for a given propertyName to the given object.
@param object the object whose class will be examined
@param propertyName the property name for which the write method is to be searched
@return the {@link Method} if found, null in all other cases.

Tries to find the Java method to write a new value for a given propertyName to the given object .


private static Method[] getMethods(Object object) {
        Method[] methods = methodCache.get(object.getClass());

        if (methods == null) {
            methods = object.getClass().getMethods();
            methodCache.put(object.getClass(), methods);
        }
        return methods;
    }

private static Method [ ] getMethods ( Object object ) { Method [ ] methods = methodCache . get ( object . getClass ( ) ) ; if ( methods == null ) { methods = object . getClass ( ) . getMethods ( ) ; methodCache . put ( object . getClass ( ) , methods ) ; } return methods ; }

Determines the class of a given object and returns an array of that class's methods. The information might come
from a cache.
@param object the object to examine
@return a list of methods belonging to the class of the object

Determines the class of a given object and returns an array of that class s methods . The information might come from a cache .


protected Object undoCollection(Object potentialCollection, Object otherObject) {
        if ((potentialCollection != null) && (otherObject != null) && (potentialCollection instanceof Collection) &&
            !(otherObject instanceof Collection)) {
            if ((((Collection) potentialCollection).size() == 1) && ((Collection) potentialCollection).iterator()
                .next().getClass().equals(otherObject.getClass())) {
                potentialCollection = ((Collection) potentialCollection).iterator().next();
            }
        }
        return potentialCollection;
    }

protected Object undoCollection ( Object potentialCollection , Object otherObject ) { if ( ( potentialCollection != null ) && ( otherObject != null ) && ( potentialCollection instanceof Collection ) && ! ( otherObject instanceof Collection ) ) { if ( ( ( ( Collection ) potentialCollection ) . size ( ) == 1 ) && ( ( Collection ) potentialCollection ) . iterator ( ) . next ( ) . getClass ( ) . equals ( otherObject . getClass ( ) ) ) { potentialCollection = ( ( Collection ) potentialCollection ) . iterator ( ) . next ( ) ; } } return potentialCollection ; }

Sometimes an attribute in one object is a single-entity collection and on the other it is just the object.
Check the passed potentialCollection and if it is a single-entry collection of the same type as the otherObject, return just the collection element.
Otherwise, return the original collection.

Sometimes an attribute in one object is a single - entity collection and on the other it is just the object . Check the passed potentialCollection and if it is a single - entry collection of the same type as the otherObject return just the collection element . Otherwise return the original collection .


public List<ForeignKey> getOutgoingForeignKeys() {
        List<ForeignKey> fkList = getAttribute("outgoingForeignKeys", List.class);
        return ((fkList == null) ? new ArrayList<ForeignKey>(0) : fkList);
    }

public List < ForeignKey > getOutgoingForeignKeys ( ) { List < ForeignKey > fkList = getAttribute ( "outgoingForeignKeys" , List . class ) ; return ( ( fkList == null ) ? new ArrayList < ForeignKey > ( 0 ) : fkList ) ; }

Returns the list of all outgoing FOREIGN KEYS from this table


public CDILiquibaseConfig createCDILiquibaseConfig() {
        final String id = UUID.randomUUID().toString();
        log.fine(LogType.LOG, String.format("[id = %s] createConfig(). Date: '%s'", id, new Date()));

        final InputStream is = SchemesCDIConfigBuilder.class.getResourceAsStream(SCHEMA_NAME);
        try {
            return jvmLocked(id, new Callable<CDILiquibaseConfig>() {
                public CDILiquibaseConfig call() throws Exception {
                    return createCDILiquibaseConfig(id, is);
                }
            });
        } catch (Exception ex) {
            log.warning(LogType.LOG, String.format("[id = %s] Unable to initialize liquibase where '%s'.", id, ex.getMessage()), ex);
            return null;
        } finally {
            try {
                is.close();
            } catch (IOException ioe) {
                log.warning(LogType.LOG, String.format("[id = %s] IOException during closing an input stream '%s'.", id, ioe.getMessage()), ioe);
            }
        }
    }


CDILiquibaseConfig fileLocked(final String id, Callable<CDILiquibaseConfig> action) throws Exception {
        log.info(LogType.LOG, String.format("[id = %s] JVM lock acquired, acquiring file lock", id));
        String lockPath = String.format("%s/schema.liquibase.lock", ROOT_PATH);

        File lockFile = new File(lockPath);
        if (!lockFile.exists() && lockFile.createNewFile()) {
            log.info(LogType.LOG, String.format("[id = %s] Created lock file [path='%s'].", id, lockPath));
        }

        log.info(LogType.LOG, String.format("[id = %s] Trying to acquire the file lock [file='%s']...", id, lockPath));

        CDILiquibaseConfig actionResult = null;
        FileLock lock = null;
        try (
            FileOutputStream fileStream = new FileOutputStream(lockPath);
            FileChannel fileChannel = fileStream.getChannel();
        )
        {
            while (null == lock) {
                try {
                    lock = fileChannel.tryLock();
                } catch (OverlappingFileLockException e) {
                    log.fine(LogType.LOG, String.format("[id = %s] Lock already acquired, waiting for the lock...", id));
                }
                if (null == lock) {
                    log.fine(LogType.LOG, String.format("[id = %s] Waiting for the lock...", id));
                    Thread.sleep(FILE_LOCK_TIMEOUT);
                }
            }
            log.info(LogType.LOG, String.format("[id = %s] File lock acquired, running liquibase...", id));
            actionResult = action.call();
            lock.release();
        } catch (Exception e) {
            log.warning(LogType.LOG, e.getMessage(), e);
        }
        return actionResult;
    }


public static String getSimplePathForResources(String entryName, String path) {
        String[] components = path.split("!");
        if (components.length == 3) {
            if (components[1].endsWith(".jar")) {
                return components[2].substring(1);
            } else {
                return entryName.replaceFirst(components[1], "").substring(1);
            }
        }
        return entryName;
    }

public static String getSimplePathForResources ( String entryName , String path ) { String [ ] components = path . split ( "!" ) ; if ( components . length == 3 ) { if ( components [ 1 ] . endsWith ( ".jar" ) ) { return components [ 2 ] . substring ( 1 ) ; } else { return entryName . replaceFirst ( components [ 1 ] , "" ) . substring ( 1 ) ; } } return entryName ; }

Method used to simplify an entryName

Ex: with path jar:/some/jar.jar!/BOOT-INF/classes!/db/changelog and entryName /BOOT-INF/classes/db/changelog
The simple entry name for Spring is db/changelog
(/BOOT-INF/classes/ is not needed and break the liquibase alphabetical sort order)

@param entryName the entryName to simplify
@param path file path
@return the simple path


public boolean isFilteredBy(Class<? extends ChangeSetFilter> filterType) {
        if (!willRun) {
            return false;
        }

        if (filterResults == null) {
            return false;
        }

        for (ChangeSetFilterResult result : filterResults) {
            if (result.getFilter().equals(filterType)) {
                return true;
            }
        }
        return false;
    }

public boolean isFilteredBy ( Class < ? extends ChangeSetFilter > filterType ) { if ( ! willRun ) { return false ; } if ( filterResults == null ) { return false ; } for ( ChangeSetFilterResult result : filterResults ) { if ( result . getFilter ( ) . equals ( filterType ) ) { return true ; } } return false ; }

Convenience method to check wither a given ChangeSetFilter type is a reason for running the change set or not.

Convenience method to check wither a given ChangeSetFilter type is a reason for running the change set or not .


public static String getValueForColumn(ResultSet rs, String columnNameToCheck, Database database) throws SQLException {
        ResultSetMetaData metadata = rs.getMetaData();
        int numberOfColumns = metadata.getColumnCount();
        String correctedColumnName = database.correctObjectName(columnNameToCheck, Column.class);
        // get the column names; column indexes start from 1
        for (int i = 1; i < (numberOfColumns + 1); i++) {
            String columnName = metadata.getColumnLabel(i);
            // Get the name of the column's table name
            if (correctedColumnName.equalsIgnoreCase(columnName)) {
                return rs.getString(columnName);
            }
        }
        return null;
    }

Checks whether a result set has a column matching the specified column name.
The column name is first changed to match the database format.
E.g. an unquoted columnName in h2 will be converted to uppercase so the column name that is
being checked for is really the uppercase version of the column name,

@param rs result set to check
@param columnNameToCheck column name to check
@return The value if found, null if not found

Checks whether a result set has a column matching the specified column name . The column name is first changed to match the database format . E . g . an unquoted columnName in h2 will be converted to uppercase so the column name that is being checked for is really the uppercase version of the column name


public void init(ConfigurationValueProvider... configurationValueProviders) {
        if (configurationValueProviders == null) {
            configurationValueProviders = new ConfigurationValueProvider[0];
        }
        this.configurationValueProviders = configurationValueProviders;

        this.reset();
    }

public void init ( ConfigurationValueProvider ... configurationValueProviders ) { if ( configurationValueProviders == null ) { configurationValueProviders = new ConfigurationValueProvider [ 0 ] ; } this . configurationValueProviders = configurationValueProviders ; this . reset ( ) ; }

Re-initialize the configuration with the given ConfigurationProviders. Any existing
AbstractConfigurationContainer instances are reset to defaults.

Re - initialize the configuration with the given ConfigurationProviders . Any existing AbstractConfigurationContainer instances are reset to defaults .


public static void initializeDatabase(String username, String defaultCatalogName, String defaultSchemaName,
                                          Database database) throws DatabaseException {
        if (((defaultCatalogName != null) || (defaultSchemaName != null)) && !(database.getConnection() instanceof
            OfflineConnection)) {
            if (database instanceof OracleDatabase) {
                String schema = defaultCatalogName;
                if (schema == null) {
                    schema = defaultSchemaName;
                }
                ExecutorService.getInstance().getExecutor(database).execute(
                    new RawSqlStatement("ALTER SESSION SET CURRENT_SCHEMA=" +
                        database.escapeObjectName(schema, Schema.class)));
            } else if (database instanceof PostgresDatabase && defaultSchemaName != null) {
                    ExecutorService.getInstance().getExecutor(database).execute(new RawSqlStatement("SET SEARCH_PATH TO " + database.escapeObjectName(defaultSchemaName, Schema.class)));
            } else if (database instanceof AbstractDb2Database) {
                String schema = defaultCatalogName;
                if (schema == null) {
                    schema = defaultSchemaName;
                }
                ExecutorService.getInstance().getExecutor(database).execute(new RawSqlStatement("SET CURRENT SCHEMA "
                        + schema));
            } else if (database instanceof MySQLDatabase) {
                String schema = defaultCatalogName;
                if (schema == null) {
                    schema = defaultSchemaName;
                }
                ExecutorService.getInstance().getExecutor(database).execute(new RawSqlStatement("USE " + schema));
            }

        }
    }

public
static
void
initializeDatabase
(
String
username
,
String
defaultCatalogName
,
String
defaultSchemaName
,
Database
database
)
throws
DatabaseException
{
if
(
(
(
defaultCatalogName
!=
)
||
(
defaultSchemaName
!=
)
)
&&
!
(
database
.
getConnection
(
)
instanceof
OfflineConnection
)
)
{
if
(
database
instanceof
OracleDatabase
)
{
String
schema
=
defaultCatalogName
;
if
(
schema
==
)
{
schema
=
defaultSchemaName
;
}
ExecutorService
.
getInstance
(
)
.
getExecutor
(
database
)
.
execute
(
new
RawSqlStatement
(
"ALTER SESSION SET CURRENT_SCHEMA="
+
database
.
escapeObjectName
(
schema
,
Schema
.
class
)
)
)
;
}
else
if
(
database
instanceof
PostgresDatabase
&&
defaultSchemaName
!=
)
{
ExecutorService
.
getInstance
(
)
.
getExecutor
(
database
)
.
execute
(
new
RawSqlStatement
(
"SET SEARCH_PATH TO "
+
database
.
escapeObjectName
(
defaultSchemaName
,
Schema
.
class
)
)
)
;
}
else
if
(
database
instanceof
AbstractDb2Database
)
{
String
schema
=
defaultCatalogName
;
if
(
schema
==
)
{
schema
=
defaultSchemaName
;
}
ExecutorService
.
getInstance
(
)
.
getExecutor
(
database
)
.
execute
(
new
RawSqlStatement
(
"SET CURRENT SCHEMA "
+
schema
)
)
;
}
else
if
(
database
instanceof
MySQLDatabase
)
{
String
schema
=
defaultCatalogName
;
if
(
schema
==
)
{
schema
=
defaultSchemaName
;
}
ExecutorService
.
getInstance
(
)
.
getExecutor
(
database
)
.
execute
(
new
RawSqlStatement
(
"USE "
+
schema
)
)
;
}
}
}

Executes RawSqlStatements particular to each database engine to set the default schema for the given Database

@param username           The username used for the connection. Used with MSSQL databases
@param defaultCatalogName Catalog name and schema name are similar concepts.
Used if defaultCatalogName is null.
@param defaultSchemaName  Catalog name and schema name are similar concepts.
Catalog is used with Oracle, DB2 and MySQL, and takes
precedence over the schema name.
@param database           Which Database object is affected by the initialization.
@throws DatabaseException


public static boolean nameMatches(DatabaseObject databaseObject1, DatabaseObject databaseObject2, Database accordingTo) {
        String object1Name = accordingTo.correctObjectName(databaseObject1.getName(), databaseObject1.getClass());
        String object2Name = accordingTo.correctObjectName(databaseObject2.getName(), databaseObject2.getClass());

        if ((object1Name == null) && (object2Name == null)) {
            return true;
        }
        if ((object1Name == null) || (object2Name == null)) {
            return false;
        }
        if (accordingTo.isCaseSensitive()) {
            return object1Name.equals(object2Name);
        } else {
            return object1Name.equalsIgnoreCase(object2Name);
        }
    }

public static boolean nameMatches ( DatabaseObject databaseObject1 , DatabaseObject databaseObject2 , Database accordingTo ) { String object1Name = accordingTo . correctObjectName ( databaseObject1 . getName ( ) , databaseObject1 . getClass ( ) ) ; String object2Name = accordingTo . correctObjectName ( databaseObject2 . getName ( ) , databaseObject2 . getClass ( ) ) ; if ( ( object1Name == null ) && ( object2Name == null ) ) { return true ; } if ( ( object1Name == null ) || ( object2Name == null ) ) { return false ; } if ( accordingTo . isCaseSensitive ( ) ) { return object1Name . equals ( object2Name ) ; } else { return object1Name . equalsIgnoreCase ( object2Name ) ; } }

Static so it can be used in other comparators if needed


private void setValidateOptionIfAvailable(Database database, ForeignKey foreignKey, CachedRow cachedRow) {
        if (!(database instanceof OracleDatabase)) {
            return;
        }
        final String constraintValidate = cachedRow.getString("FK_VALIDATE");
        final String VALIDATE = "VALIDATED";
        if (constraintValidate!=null && !constraintValidate.isEmpty()) {
            foreignKey.setShouldValidate(VALIDATE.equals(cleanNameFromDatabase(constraintValidate.trim(), database)));
        }
    }

private void setValidateOptionIfAvailable ( Database database , ForeignKey foreignKey , CachedRow cachedRow ) { if ( ! ( database instanceof OracleDatabase ) ) { return ; } final String constraintValidate = cachedRow . getString ( "FK_VALIDATE" ) ; final String VALIDATE = "VALIDATED" ; if ( constraintValidate != null && ! constraintValidate . isEmpty ( ) ) { foreignKey . setShouldValidate ( VALIDATE . equals ( cleanNameFromDatabase ( constraintValidate . trim ( ) , database ) ) ) ; } }

Method to map 'validate' option for FK. This thing works only for ORACLE

@param database - DB where FK will be created
@param foreignKey - FK object to persist validate option
@param cachedRow - it's a cache-map to get metadata about FK

Method to map validate option for FK . This thing works only for ORACLE


public boolean addType(Class<? extends DatabaseObject> type, Database database) {
        boolean added = this.types.add(type);
        if (added) {
            for (Class<? extends DatabaseObject> container : SnapshotGeneratorFactory.getInstance().getContainerTypes(type, database)) {
                addType(container, database);
            }
        }
        return added;
    }

public boolean addType ( Class < ? extends DatabaseObject > type , Database database ) { boolean added = this . types . add ( type ) ; if ( added ) { for ( Class < ? extends DatabaseObject > container : SnapshotGeneratorFactory . getInstance ( ) . getContainerTypes ( type , database ) ) { addType ( container , database ) ; } } return added ; }

Adds a new DatabaseObject type to the list of object types to be included in snapshots.
@param type The type to be added
@param database The database to check for any dependent types that need to be included as well
@return true if the type was added to the list, false if it was already present.

Adds a new DatabaseObject type to the list of object types to be included in snapshots .


@Override
    public void afterPropertiesSet() throws LiquibaseException {
        ConfigurationProperty shouldRunProperty = LiquibaseConfiguration.getInstance()
            .getProperty(GlobalConfiguration.class, GlobalConfiguration.SHOULD_RUN);

		if (!shouldRunProperty.getValue(Boolean.class)) {
            Scope.getCurrentScope().getLog(getClass()).info(LogType.LOG, "Liquibase did not run because " + LiquibaseConfiguration
                .getInstance().describeValueLookupLogic(shouldRunProperty) + " was set to false");
            return;
		}
		if (!shouldRun) {
            Scope.getCurrentScope().getLog(getClass()).info(LogType.LOG, "Liquibase did not run because 'shouldRun' " + "property was set " +
                "to false on " + getBeanName() + " Liquibase Spring bean.");
            return;
		}

		Connection c = null;
		Liquibase liquibase = null;
		try {
			c = getDataSource().getConnection();
            liquibase = createLiquibase(c);
			generateRollbackFile(liquibase);
			performUpdate(liquibase);
		} catch (SQLException e) {
			throw new DatabaseException(e);
		} finally {
			Database database = null;
			if (liquibase != null) {
				database = liquibase.getDatabase();
			}
			if (database != null) {
                database.close();
            }
        }

	}

Executed automatically when the bean is initialized.

Executed automatically when the bean is initialized .


protected String checkForTrim(String s, PropertyDescriptor prop) {
        return trimmableProperty(prop) ? s.trim() : s;
    }

protected String checkForTrim ( String s , PropertyDescriptor prop ) { return trimmableProperty ( prop ) ? s . trim ( ) : s ; }

Returns the trimmed value of the string only if the property the string is describing should be trimmed
to be converted to that type.

@param s    - String describing the value.
@param prop - property descriptor of the value.
@return the string passed in if the property is a string otherwise it will return the string with the
beginning and end whitespace removed.

Returns the trimmed value of the string only if the property the string is describing should be trimmed to be converted to that type .


protected Object convertValue(String value, PropertyDescriptor prop) throws ReflectiveOperationException {
        PropertyEditor editor = getPropertyEditor(prop);
        Object obj = value;
        if (null != editor) {
            editor.setAsText(value);
            obj = editor.getValue();
        }
        return obj;
    }

protected Object convertValue ( String value , PropertyDescriptor prop ) throws ReflectiveOperationException { PropertyEditor editor = getPropertyEditor ( prop ) ; Object obj = value ; if ( null != editor ) { editor . setAsText ( value ) ; obj = editor . getValue ( ) ; } return obj ; }

Convert a string value to its Object value.

@param value - String value
@param prop  - PropertyDescriptor
@return The object set to value (i.e. Integer).  Will return String if no PropertyEditor is found.
@throws ReflectiveOperationException - Thrown on error getting the property editor from the property descriptor.

Convert a string value to its Object value .


public static void main(String[] args) {
        int errorLevel = 0;
        try {
            errorLevel = run(args);
        } catch (Throwable e) {
            System.exit(-1);
        }
        System.exit(errorLevel);
    }

public static void main ( String [ ] args ) { int errorLevel = 0 ; try { errorLevel = run ( args ) ; } catch ( Throwable e ) { System . exit ( - 1 ) ; } System . exit ( errorLevel ) ; }

Entry point. This is what gets executes when starting this program from the command line. This is actually
a simple wrapper so that an errorlevel of != 0 is guaranteed in case of an uncaught exception.

@param args the command line arguments

Entry point . This is what gets executes when starting this program from the command line . This is actually a simple wrapper so that an errorlevel of ! = 0 is guaranteed in case of an uncaught exception .


@SuppressWarnings("squid:S109")
    private static String[] splitArg(String arg) throws CommandLineParsingException {
        String[] splitArg = arg.split("=", 2);
        if (splitArg.length < 2) {
            throw new CommandLineParsingException(
                    String.format(coreBundle.getString("could.not.parse.expression"), arg)
            );
        }

        splitArg[0] = splitArg[0].replaceFirst("--", "");
        return splitArg;
    }

@ SuppressWarnings ( "squid:S109" ) private static String [ ] splitArg ( String arg ) throws CommandLineParsingException { String [ ] splitArg = arg . split ( "=" , 2 ) ; if ( splitArg . length < 2 ) { throw new CommandLineParsingException ( String . format ( coreBundle . getString ( "could.not.parse.expression" ) , arg ) ) ; } splitArg [ 0 ] = splitArg [ 0 ] . replaceFirst ( "--" , "" ) ; return splitArg ; }

What the number 2 stands for is obvious from the context


private static boolean isCommand(String arg) {
        return COMMANDS.MIGRATE.equals(arg)
                || COMMANDS.MIGRATE_SQL.equalsIgnoreCase(arg)
                || COMMANDS.UPDATE.equalsIgnoreCase(arg)
                || COMMANDS.UPDATE_SQL.equalsIgnoreCase(arg)
                || COMMANDS.UPDATE_COUNT.equalsIgnoreCase(arg)
                || COMMANDS.UPDATE_COUNT_SQL.equalsIgnoreCase(arg)
                || COMMANDS.UPDATE_TO_TAG.equalsIgnoreCase(arg)
                || COMMANDS.UPDATE_TO_TAG_SQL.equalsIgnoreCase(arg)
                || COMMANDS.ROLLBACK.equalsIgnoreCase(arg)
                || COMMANDS.ROLLBACK_TO_DATE.equalsIgnoreCase(arg)
                || COMMANDS.ROLLBACK_COUNT.equalsIgnoreCase(arg)
                || COMMANDS.ROLLBACK_SQL.equalsIgnoreCase(arg)
                || COMMANDS.ROLLBACK_TO_DATE_SQL.equalsIgnoreCase(arg)
                || COMMANDS.ROLLBACK_COUNT_SQL.equalsIgnoreCase(arg)
                || COMMANDS.FUTURE_ROLLBACK_SQL.equalsIgnoreCase(arg)
                || COMMANDS.FUTURE_ROLLBACK_COUNT_SQL.equalsIgnoreCase(arg)
                || COMMANDS.FUTURE_ROLLBACK_TO_TAG_SQL.equalsIgnoreCase(arg)
                || COMMANDS.UPDATE_TESTING_ROLLBACK.equalsIgnoreCase(arg)
                || COMMANDS.TAG.equalsIgnoreCase(arg)
                || COMMANDS.TAG_EXISTS.equalsIgnoreCase(arg)
                || COMMANDS.LIST_LOCKS.equalsIgnoreCase(arg)
                || COMMANDS.DROP_ALL.equalsIgnoreCase(arg)
                || COMMANDS.RELEASE_LOCKS.equalsIgnoreCase(arg)
                || COMMANDS.STATUS.equalsIgnoreCase(arg)
                || COMMANDS.UNEXPECTED_CHANGESETS.equalsIgnoreCase(arg)
                || COMMANDS.VALIDATE.equalsIgnoreCase(arg)
                || COMMANDS.HELP.equalsIgnoreCase(arg)
                || COMMANDS.DIFF.equalsIgnoreCase(arg)
                || COMMANDS.DIFF_CHANGELOG.equalsIgnoreCase(arg)
                || COMMANDS.GENERATE_CHANGELOG.equalsIgnoreCase(arg)
                || COMMANDS.SNAPSHOT.equalsIgnoreCase(arg)
                || COMMANDS.SNAPSHOT_REFERENCE.equalsIgnoreCase(arg)
                || COMMANDS.EXECUTE_SQL.equalsIgnoreCase(arg)
                || COMMANDS.CALCULATE_CHECKSUM.equalsIgnoreCase(arg)
                || COMMANDS.CLEAR_CHECKSUMS.equalsIgnoreCase(arg)
                || COMMANDS.DB_DOC.equalsIgnoreCase(arg)
                || COMMANDS.CHANGELOG_SYNC.equalsIgnoreCase(arg)
                || COMMANDS.CHANGELOG_SYNC_SQL.equalsIgnoreCase(arg)
                || COMMANDS.MARK_NEXT_CHANGESET_RAN.equalsIgnoreCase(arg)
                || COMMANDS.MARK_NEXT_CHANGESET_RAN_SQL.equalsIgnoreCase(arg);
    }

private static boolean isCommand ( String arg ) { return COMMANDS . MIGRATE . equals ( arg ) || COMMANDS . MIGRATE_SQL . equalsIgnoreCase ( arg ) || COMMANDS . UPDATE . equalsIgnoreCase ( arg ) || COMMANDS . UPDATE_SQL . equalsIgnoreCase ( arg ) || COMMANDS . UPDATE_COUNT . equalsIgnoreCase ( arg ) || COMMANDS . UPDATE_COUNT_SQL . equalsIgnoreCase ( arg ) || COMMANDS . UPDATE_TO_TAG . equalsIgnoreCase ( arg ) || COMMANDS . UPDATE_TO_TAG_SQL . equalsIgnoreCase ( arg ) || COMMANDS . ROLLBACK . equalsIgnoreCase ( arg ) || COMMANDS . ROLLBACK_TO_DATE . equalsIgnoreCase ( arg ) || COMMANDS . ROLLBACK_COUNT . equalsIgnoreCase ( arg ) || COMMANDS . ROLLBACK_SQL . equalsIgnoreCase ( arg ) || COMMANDS . ROLLBACK_TO_DATE_SQL . equalsIgnoreCase ( arg ) || COMMANDS . ROLLBACK_COUNT_SQL . equalsIgnoreCase ( arg ) || COMMANDS . FUTURE_ROLLBACK_SQL . equalsIgnoreCase ( arg ) || COMMANDS . FUTURE_ROLLBACK_COUNT_SQL . equalsIgnoreCase ( arg ) || COMMANDS . FUTURE_ROLLBACK_TO_TAG_SQL . equalsIgnoreCase ( arg ) || COMMANDS . UPDATE_TESTING_ROLLBACK . equalsIgnoreCase ( arg ) || COMMANDS . TAG . equalsIgnoreCase ( arg ) || COMMANDS . TAG_EXISTS . equalsIgnoreCase ( arg ) || COMMANDS . LIST_LOCKS . equalsIgnoreCase ( arg ) || COMMANDS . DROP_ALL . equalsIgnoreCase ( arg ) || COMMANDS . RELEASE_LOCKS . equalsIgnoreCase ( arg ) || COMMANDS . STATUS . equalsIgnoreCase ( arg ) || COMMANDS . UNEXPECTED_CHANGESETS . equalsIgnoreCase ( arg ) || COMMANDS . VALIDATE . equalsIgnoreCase ( arg ) || COMMANDS . HELP . equalsIgnoreCase ( arg ) || COMMANDS . DIFF . equalsIgnoreCase ( arg ) || COMMANDS . DIFF_CHANGELOG . equalsIgnoreCase ( arg ) || COMMANDS . GENERATE_CHANGELOG . equalsIgnoreCase ( arg ) || COMMANDS . SNAPSHOT . equalsIgnoreCase ( arg ) || COMMANDS . SNAPSHOT_REFERENCE . equalsIgnoreCase ( arg ) || COMMANDS . EXECUTE_SQL . equalsIgnoreCase ( arg ) || COMMANDS . CALCULATE_CHECKSUM . equalsIgnoreCase ( arg ) || COMMANDS . CLEAR_CHECKSUMS . equalsIgnoreCase ( arg ) || COMMANDS . DB_DOC . equalsIgnoreCase ( arg ) || COMMANDS . CHANGELOG_SYNC . equalsIgnoreCase ( arg ) || COMMANDS . CHANGELOG_SYNC_SQL . equalsIgnoreCase ( arg ) || COMMANDS . MARK_NEXT_CHANGESET_RAN . equalsIgnoreCase ( arg ) || COMMANDS . MARK_NEXT_CHANGESET_RAN_SQL . equalsIgnoreCase ( arg ) ; }

Returns true if the given arg is a valid main command of Liquibase.

@param arg the String to test
@return true if it is a valid main command, false if not

Returns true if the given arg is a valid main command of Liquibase .


private static boolean isNoArgCommand(String arg) {
        return COMMANDS.MIGRATE.equals(arg)
                || COMMANDS.MIGRATE_SQL.equalsIgnoreCase(arg)
                || COMMANDS.UPDATE.equalsIgnoreCase(arg)
                || COMMANDS.UPDATE_SQL.equalsIgnoreCase(arg)
                || COMMANDS.FUTURE_ROLLBACK_SQL.equalsIgnoreCase(arg)
                || COMMANDS.UPDATE_TESTING_ROLLBACK.equalsIgnoreCase(arg)
                || COMMANDS.LIST_LOCKS.equalsIgnoreCase(arg)
                || COMMANDS.DROP_ALL.equalsIgnoreCase(arg)
                || COMMANDS.RELEASE_LOCKS.equalsIgnoreCase(arg)
                || COMMANDS.VALIDATE.equalsIgnoreCase(arg)
                || COMMANDS.HELP.equalsIgnoreCase(arg)
                || COMMANDS.CLEAR_CHECKSUMS.equalsIgnoreCase(arg)
                || COMMANDS.CHANGELOG_SYNC.equalsIgnoreCase(arg)
                || COMMANDS.CHANGELOG_SYNC_SQL.equalsIgnoreCase(arg)
                || COMMANDS.MARK_NEXT_CHANGESET_RAN.equalsIgnoreCase(arg)
                || COMMANDS.MARK_NEXT_CHANGESET_RAN_SQL.equalsIgnoreCase(arg);
    }

private static boolean isNoArgCommand ( String arg ) { return COMMANDS . MIGRATE . equals ( arg ) || COMMANDS . MIGRATE_SQL . equalsIgnoreCase ( arg ) || COMMANDS . UPDATE . equalsIgnoreCase ( arg ) || COMMANDS . UPDATE_SQL . equalsIgnoreCase ( arg ) || COMMANDS . FUTURE_ROLLBACK_SQL . equalsIgnoreCase ( arg ) || COMMANDS . UPDATE_TESTING_ROLLBACK . equalsIgnoreCase ( arg ) || COMMANDS . LIST_LOCKS . equalsIgnoreCase ( arg ) || COMMANDS . DROP_ALL . equalsIgnoreCase ( arg ) || COMMANDS . RELEASE_LOCKS . equalsIgnoreCase ( arg ) || COMMANDS . VALIDATE . equalsIgnoreCase ( arg ) || COMMANDS . HELP . equalsIgnoreCase ( arg ) || COMMANDS . CLEAR_CHECKSUMS . equalsIgnoreCase ( arg ) || COMMANDS . CHANGELOG_SYNC . equalsIgnoreCase ( arg ) || COMMANDS . CHANGELOG_SYNC_SQL . equalsIgnoreCase ( arg ) || COMMANDS . MARK_NEXT_CHANGESET_RAN . equalsIgnoreCase ( arg ) || COMMANDS . MARK_NEXT_CHANGESET_RAN_SQL . equalsIgnoreCase ( arg ) ; }

Returns true if the given main command arg needs no special parameters.

@param arg the main command to test
@return true if arg is a valid main command and needs no special parameters, false in all other cases

Returns true if the given main command arg needs no special parameters .


private static File extract(JarFile jar, JarEntry entry) throws IOException {
        // expand to temp dir and add to list
        File tempFile = File.createTempFile("liquibase.tmp", null);
        // read from jar and write to the tempJar file
        try (
                BufferedInputStream inStream = new BufferedInputStream(jar.getInputStream(entry));
                BufferedOutputStream outStream = new BufferedOutputStream(new FileOutputStream(tempFile))
        ) {
            int status;
            while ((status = inStream.read()) != -1) {
                outStream.write(status);
            }
        }

        return tempFile;
    }

Extract a single object from a JAR file into a temporary file.

@param jar   the JAR file from which we will extract
@param entry the object inside the JAR file that to be extracted
@return a File object with the temporary file containing the extracted object
@throws IOException if an I/O problem occurs

Extract a single object from a JAR file into a temporary file .


private void parseDefaultPropertyFileFromResource(File potentialPropertyFile) throws IOException,
            CommandLineParsingException {
        try (InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream
                (potentialPropertyFile.getAbsolutePath())) {
            if (resourceAsStream != null) {
                parsePropertiesFile(resourceAsStream);
            }
        }
    }

private void parseDefaultPropertyFileFromResource ( File potentialPropertyFile ) throws IOException , CommandLineParsingException { try ( InputStream resourceAsStream = getClass ( ) . getClassLoader ( ) . getResourceAsStream ( potentialPropertyFile . getAbsolutePath ( ) ) ) { if ( resourceAsStream != null ) { parsePropertiesFile ( resourceAsStream ) ; } } }

Open a property file that is embedded as a Java resource and parse it.

@param potentialPropertyFile location and file name of the property file
@throws IOException                 if the file cannot be opened
@throws CommandLineParsingException if an error occurs during parsing

Open a property file that is embedded as a Java resource and parse it .


protected String[] fixupArgs(String[] args) {
        List<String> fixedArgs = new ArrayList<>();

        for (int i = 0; i < args.length; i++) {
            String arg = args[i];
            if ((arg.startsWith("--") || arg.startsWith("-D")) && !arg.contains("=")) {
                String nextArg = null;
                if ((i + 1) < args.length) {
                    nextArg = args[i + 1];
                }
                if ((nextArg != null) && !nextArg.startsWith("--") && !isCommand(nextArg)) {
                    arg = arg + "=" + nextArg;
                    i++;
                }
            }

            // Sometimes, commas are still escaped as \, at this point, fix it:
            arg = arg.replace("\\,", ",");
            fixedArgs.add(arg);
        }

        return fixedArgs.toArray(new String[fixedArgs.size()]);
    }

On windows machines, it splits args on '=' signs.  Put it back like it was.

On windows machines it splits args on = signs . Put it back like it was .


protected List<String> checkSetup() {
        List<String> messages = new ArrayList<>();
        if (command == null) {
            messages.add(coreBundle.getString("command.not.passed"));
        } else if (!isCommand(command)) {
            messages.add(String.format(coreBundle.getString("command.unknown"), command));
        } else {
            if (StringUtil.trimToNull(url) == null) {
                messages.add(String.format(coreBundle.getString("option.required"), "--" + OPTIONS.URL));
            }

            if (isChangeLogRequired(command) && (StringUtil.trimToNull(changeLogFile) == null)) {
                messages.add(String.format(coreBundle.getString("option.required"), "--" + OPTIONS.CHANGELOG_FILE));
            }

            if (isNoArgCommand(command) && !commandParams.isEmpty()) {
                messages.add(coreBundle.getString(ERRORMSG_UNEXPECTED_PARAMETERS) + commandParams);
            } else {
                validateCommandParameters(messages);
            }
        }
        return messages;
    }

protected List < String > checkSetup ( ) { List < String > messages = new ArrayList <> ( ) ; if ( command == null ) { messages . add ( coreBundle . getString ( "command.not.passed" ) ) ; } else if ( ! isCommand ( command ) ) { messages . add ( String . format ( coreBundle . getString ( "command.unknown" ) , command ) ) ; } else { if ( StringUtil . trimToNull ( url ) == null ) { messages . add ( String . format ( coreBundle . getString ( "option.required" ) , "--" + OPTIONS . URL ) ) ; } if ( isChangeLogRequired ( command ) && ( StringUtil . trimToNull ( changeLogFile ) == null ) ) { messages . add ( String . format ( coreBundle . getString ( "option.required" ) , "--" + OPTIONS . CHANGELOG_FILE ) ) ; } if ( isNoArgCommand ( command ) && ! commandParams . isEmpty ( ) ) { messages . add ( coreBundle . getString ( ERRORMSG_UNEXPECTED_PARAMETERS ) + commandParams ) ; } else { validateCommandParameters ( messages ) ; } } return messages ; }

After parsing, checks if the given combination of main command and can be executed.

@return an empty List if successful, or a list of error messages

After parsing checks if the given combination of main command and can be executed .


private void checkForMissingCommandParameters(final List<String> messages) {
        if ((commandParams.isEmpty() || commandParams.iterator().next().startsWith("-"))
                && (COMMANDS.CALCULATE_CHECKSUM.equalsIgnoreCase(command))) {
            messages.add(coreBundle.getString("changeset.identifier.missing"));
        }
    }

private void checkForMissingCommandParameters ( final List < String > messages ) { if ( ( commandParams . isEmpty ( ) || commandParams . iterator ( ) . next ( ) . startsWith ( "-" ) ) && ( COMMANDS . CALCULATE_CHECKSUM . equalsIgnoreCase ( command ) ) ) { messages . add ( coreBundle . getString ( "changeset.identifier.missing" ) ) ; } }

Checks for missing command line parameters and, if any problems are found,
returns the list of issues in String form.

@param messages an array of Strings to which messages for issues found will be added

Checks for missing command line parameters and if any problems are found returns the list of issues in String form .