/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the License at the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apereo.portal.version;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import javax.annotation.Resource;
import org.apereo.portal.shell.PortalShellBuildHelper;
import org.apereo.portal.version.dao.VersionDao;
import org.apereo.portal.version.om.Version;
import org.apereo.portal.version.om.Version.Field;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContextException;
import org.springframework.stereotype.Component;
/**
* Bean that verifies the product version numbers in the configuration versus the database on
* startup
*
*/
@Component
public class VersionVerifier implements InitializingBean {
protected final Logger logger = LoggerFactory.getLogger(getClass());
private Map<String, Version> requiredProductVersions;
private VersionDao versionDao;
private Version.Field updatePolicy = Version.Field.LOCAL;
private PortalShellBuildHelper portalShellBuildHelper;
@Resource(name = "productVersions")
public void setRequiredProductVersions(Map<String, Version> requiredProductVersions) {
this.requiredProductVersions = ImmutableMap.copyOf(requiredProductVersions);
}
@Autowired
public void setVersionDao(VersionDao versionDao) {
this.versionDao = versionDao;
}
@Autowired
public void setPortalShellBuildHelper(PortalShellBuildHelper portalShellBuildHelper) {
this.portalShellBuildHelper = portalShellBuildHelper;
}
@Value("${org.apereo.portal.version.autoUpdatePolicy:LOCAL}")
public void setUpdatePolicy(Version.Field updatePolicy) {
if (updatePolicy != null
&& updatePolicy != Version.Field.LOCAL
&& updatePolicy != Version.Field.PATCH) {
throw new IllegalArgumentException("Only null, LOCAL, and PATCH updates are allowed");
}
this.updatePolicy = updatePolicy;
}
@Override
public void afterPropertiesSet() throws Exception {
for (final Map.Entry<String, Version> productVersionEntry :
this.requiredProductVersions.entrySet()) {
final String product = productVersionEntry.getKey();
final Version dbVersion = this.versionDao.getVersion(product);
if (dbVersion == null) {
throw new ApplicationContextException(
"No Version exists for "
+ product
+ " in the database. Please check the upgrade instructions for this release.");
}
final Version codeVersion = productVersionEntry.getValue();
final Field mostSpecificMatchingField =
VersionUtils.getMostSpecificMatchingField(dbVersion, codeVersion);
switch (mostSpecificMatchingField) {
//Versions completely match
case LOCAL:
{
logger.info(
"Software and Database versions are both {} for {}",
dbVersion,
product);
continue;
}
//Versions match except for local part
case PATCH:
//Versions match except for patch.local part
case MINOR:
{
//If db is before code and auto-update is enabled run hibernate-update
final Field upgradeField = mostSpecificMatchingField.getLessImportant();
if (dbVersion.isBefore(codeVersion)
&& this.updatePolicy != null
&& (upgradeField.equals(this.updatePolicy)
|| upgradeField.isLessImportantThan(this.updatePolicy))) {
logger.info(
"Automatically updating database from {} to {} for {}",
dbVersion,
codeVersion,
product);
this.portalShellBuildHelper.hibernateUpdate(
"automated-hibernate-update", product, true, null);
continue;
} else if (codeVersion.isBefore(dbVersion)) {
//It is ok to run older code on a newer DB within the local/patch range
continue;
}
}
//Versions match except for minor.patch.local part
case MAJOR:
//Versions do not match at all
default:
{
if (dbVersion.isBefore(codeVersion)) {
throw new ApplicationContextException(
"Database Version for "
+ product
+ " is "
+ dbVersion
+ " but the code version is "
+ codeVersion
+ ". Please check the upgrade instructions for this release");
} else {
throw new ApplicationContextException(
"Database Version for "
+ product
+ " is "
+ dbVersion
+ " but the code version is "
+ codeVersion
+ ". It is not possible to run ");
}
}
}
}
}
}