001package ca.uhn.fhir.jpa.migrate.tasks; 002 003/*- 004 * #%L 005 * HAPI FHIR Server - SQL Migration 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.context.ConfigurationException; 024import ca.uhn.fhir.i18n.Msg; 025import ca.uhn.fhir.jpa.migrate.DriverTypeEnum; 026import ca.uhn.fhir.jpa.migrate.tasks.api.ISchemaInitializationProvider; 027import com.google.common.base.Charsets; 028import org.apache.commons.io.IOUtils; 029import org.apache.commons.lang3.builder.HashCodeBuilder; 030 031import javax.annotation.Nonnull; 032import java.io.IOException; 033import java.io.InputStream; 034import java.util.ArrayList; 035import java.util.Collections; 036import java.util.List; 037 038import static org.apache.commons.lang3.StringUtils.isBlank; 039 040public class SchemaInitializationProvider implements ISchemaInitializationProvider { 041 042 private final String mySchemaExistsIndicatorTable; 043 private final boolean myCanInitializeSchema; 044 private String mySchemaFileClassPath; 045 private String mySchemaDescription; 046 047 /** 048 * @param theSchemaFileClassPath pathname to script used to initialize schema 049 * @param theSchemaExistsIndicatorTable a table name we can use to determine if this schema has already been initialized 050 * @param theCanInitializeSchema this is a "root" schema initializer that creates the primary tables used by this app 051 */ 052 public SchemaInitializationProvider(String theSchemaDescription, String theSchemaFileClassPath, String theSchemaExistsIndicatorTable, boolean theCanInitializeSchema) { 053 mySchemaDescription = theSchemaDescription; 054 mySchemaFileClassPath = theSchemaFileClassPath; 055 mySchemaExistsIndicatorTable = theSchemaExistsIndicatorTable; 056 myCanInitializeSchema = theCanInitializeSchema; 057 } 058 059 @Override 060 public List<String> getSqlStatements(DriverTypeEnum theDriverType) { 061 if (!isEnabled()) { 062 return Collections.emptyList(); 063 } 064 065 List<String> retval = new ArrayList<>(); 066 067 String initScript = mySchemaFileClassPath + "/" + getInitScript(theDriverType); 068 try { 069 InputStream sqlFileInputStream = SchemaInitializationProvider.class.getResourceAsStream(initScript); 070 if (sqlFileInputStream == null) { 071 throw new ConfigurationException(Msg.code(49) + "Schema initialization script " + initScript + " not found on classpath"); 072 } 073 // Assumes no escaped semicolons... 074 String sqlString = IOUtils.toString(sqlFileInputStream, Charsets.UTF_8); 075 String sqlStringNoComments = preProcessSqlString(theDriverType, sqlString); 076 String[] statements = sqlStringNoComments.split("\\;"); 077 for (String statement : statements) { 078 String cleanedStatement = preProcessSqlStatement(theDriverType, statement); 079 if (!isBlank(cleanedStatement)) { 080 retval.add(cleanedStatement); 081 } 082 } 083 } catch (IOException e) { 084 throw new ConfigurationException(Msg.code(50) + "Error reading schema initialization script " + initScript, e); 085 } 086 return retval; 087 } 088 089 protected String preProcessSqlString(DriverTypeEnum theDriverType, String sqlString) { 090 return sqlString; 091 } 092 093 protected String preProcessSqlStatement(DriverTypeEnum theDriverType, String sqlStatement) { 094 return sqlStatement; 095 } 096 097 @Nonnull 098 protected String getInitScript(DriverTypeEnum theDriverType) { 099 return theDriverType.getSchemaFilename(); 100 } 101 102 @Override 103 public boolean equals(Object theO) { 104 if (this == theO) return true; 105 106 if (theO == null || getClass() != theO.getClass()) return false; 107 108 SchemaInitializationProvider that = (SchemaInitializationProvider) theO; 109 110 return this.getClass().getSimpleName() == that.getClass().getSimpleName(); 111 } 112 113 @Override 114 public int hashCode() { 115 return new HashCodeBuilder(17, 37) 116 .append(this.getClass().getSimpleName()) 117 .toHashCode(); 118 } 119 120 @Override 121 public String getSchemaExistsIndicatorTable() { 122 return mySchemaExistsIndicatorTable; 123 } 124 125 public SchemaInitializationProvider setSchemaFileClassPath(String theSchemaFileClassPath) { 126 mySchemaFileClassPath = theSchemaFileClassPath; 127 return this; 128 } 129 130 @Override 131 public String getSchemaDescription() { 132 return mySchemaDescription; 133 } 134 135 @Override 136 public SchemaInitializationProvider setSchemaDescription(String theSchemaDescription) { 137 mySchemaDescription = theSchemaDescription; 138 return this; 139 } 140 141 @Override 142 public boolean canInitializeSchema() { 143 return myCanInitializeSchema; 144 } 145} 146