001/* 002 * Copyright 2020 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.core.migration.action.impl; 017 018import java.io.IOException; 019import java.io.InputStream; 020import java.net.MalformedURLException; 021import java.util.Map; 022 023import javax.script.ScriptException; 024 025import org.apache.avalon.framework.configuration.Configuration; 026import org.apache.avalon.framework.configuration.ConfigurationException; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.commons.io.IOUtils; 031import org.apache.commons.lang3.StringUtils; 032import org.apache.excalibur.source.Source; 033import org.apache.excalibur.source.SourceNotFoundException; 034import org.apache.excalibur.source.SourceResolver; 035import org.slf4j.LoggerFactory; 036 037import org.ametys.core.migration.MigrationException; 038import org.ametys.core.migration.action.Action; 039import org.ametys.core.migration.action.data.ActionData; 040import org.ametys.core.migration.action.data.impl.ScriptActionData; 041import org.ametys.core.migration.version.Version; 042import org.ametys.plugins.core.ui.script.ScriptHandler; 043import org.ametys.runtime.plugin.component.AbstractLogEnabled; 044 045/** 046 * SQL action : A script will be executed 047 */ 048public class ScriptAction extends AbstractLogEnabled implements Action, Serviceable 049{ 050 /** Source resolver */ 051 protected SourceResolver _sourceResolver; 052 053 /** Script Handler */ 054 protected ScriptHandler _scriptHandler; 055 056 public void service(ServiceManager manager) throws ServiceException 057 { 058 _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 059 _scriptHandler = (ScriptHandler) manager.lookup(ScriptHandler.ROLE); 060 } 061 062 public void doAction(ActionData actionData) throws MigrationException 063 { 064 getLogger().debug("Start initialization for : {}", actionData.toString()); 065 066 if (!(actionData instanceof ScriptActionData)) 067 { 068 throw new MigrationException("Script Upgrade can only be created for a Script upgrade, this is not the case for upgrade : " + actionData.toString()); 069 } 070 071 ScriptActionData scriptActionData = (ScriptActionData) actionData; 072 try 073 { 074 String script = getScript(scriptActionData); 075 076 Version version = actionData.getVersion(); 077 Map<String, Object> variables = Map.of( 078 "version", version, 079 "actionData", actionData, 080 "logger", LoggerFactory.getLogger(getLogger().getName() + "." + version.getComponentId()) 081 ); 082 083 // Execute the script in the admin workspace 084 Map<String, Object> scriptResult = _scriptHandler.executeScript(script, variables, "admin"); 085 if (!StringUtils.isAllBlank((String) scriptResult.get("error"), (String) scriptResult.get("message"), (String) scriptResult.get("stacktrace"))) 086 { 087 throw new MigrationException("Error while executing script to upgrade component '" + actionData.getVersion().getComponentId() + "' to version '" + actionData.getVersionNumber() + "'. Error : '" + scriptResult.get("error") + "', message : '" + scriptResult.get("message") + "', stacktrace : '" + scriptResult.get("stacktrace") + "'"); 088 } 089 } 090 catch (ScriptException e) 091 { 092 throw new MigrationException("Error while executing script to upgrade : '" + actionData.toString() + "'", e); 093 } 094 095 getLogger().debug("End upgrade for : {}", actionData.toString()); 096 } 097 098 /** 099 * Get the content of the script from the actionData 100 * @param scriptActionData actionData containing info about the upgrade 101 * @return The script as a String (either from the config or from a file to parse) 102 * @throws MigrationException Something went wrong 103 */ 104 protected String getScript(ScriptActionData scriptActionData) throws MigrationException 105 { 106 String script; 107 if (StringUtils.isNotBlank(scriptActionData.getScript())) 108 { 109 script = scriptActionData.getScript(); 110 } 111 else 112 { 113 String uri = "plugin:" + scriptActionData.getPlugin() + "://" + scriptActionData.getFile(); 114 Source source = null; 115 try 116 { 117 source = _sourceResolver.resolveURI(uri); 118 119 if (!source.exists()) 120 { 121 throw new SourceNotFoundException("URI '" + uri + "' does not exist."); 122 } 123 try (InputStream is = source.getInputStream()) 124 { 125 script = IOUtils.toString(is, "UTF-8"); 126 } 127 } 128 catch (MalformedURLException e) 129 { 130 throw new MigrationException("Impossible to find the script for the upgrade : " + scriptActionData.toString(), e); 131 } 132 catch (IOException e) 133 { 134 throw new MigrationException("Impossible to run the upgrade : " + scriptActionData.toString(), e); 135 } 136 finally 137 { 138 if (source != null) 139 { 140 _sourceResolver.release(source); 141 } 142 } 143 } 144 return "function main() { \n " + script + " \n }"; 145 } 146 147 public ActionData generateActionData(String id, Version version, String comment, String from, String type, String pluginName, Configuration configuration, boolean restartRequired) throws MigrationException, ConfigurationException 148 { 149 return new ScriptActionData(id, version, comment, from, type, pluginName, configuration, restartRequired); 150 } 151}