001/* 002 * (C) Copyright 2006-2014 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * bstefanescu, jcarsique 016 */ 017package org.nuxeo.connect.update.task.standalone; 018 019import java.io.ByteArrayOutputStream; 020import java.io.File; 021import java.io.FileOutputStream; 022import java.io.IOException; 023import java.io.PrintStream; 024import java.text.SimpleDateFormat; 025import java.util.Date; 026import java.util.HashMap; 027import java.util.Map; 028import java.util.Properties; 029 030import org.apache.commons.collections.MapUtils; 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033 034import org.nuxeo.common.Environment; 035import org.nuxeo.common.utils.FileUtils; 036import org.nuxeo.common.utils.StringUtils; 037import org.nuxeo.connect.update.LocalPackage; 038import org.nuxeo.connect.update.PackageException; 039import org.nuxeo.connect.update.PackageState; 040import org.nuxeo.connect.update.PackageUpdateService; 041import org.nuxeo.connect.update.ValidationStatus; 042import org.nuxeo.connect.update.task.Task; 043import org.nuxeo.connect.update.task.update.UpdateManager; 044 045/** 046 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 047 */ 048public abstract class AbstractTask implements Task { 049 050 static final Log log = LogFactory.getLog(AbstractTask.class); 051 052 public static final String PKG_ID = "package.id"; 053 054 public static final String PKG_NAME = "package.name"; 055 056 public static final String PKG_VERSION = "package.version"; 057 058 public static final String PKG_ROOT = "package.root"; 059 060 public static final String ENV_HOME = "env.home"; 061 062 /** 063 * @since 5.5 064 */ 065 public static final String ENV_SERVER_HOME = "env.server.home"; 066 067 /** 068 * Set only on JBoss - the EAR root directory path 069 */ 070 public static final String ENV_EAR = "env.ear"; 071 072 public static final String ENV_LIB = "env.lib"; 073 074 public static final String ENV_SYSLIB = "env.syslib"; 075 076 public static final String ENV_BUNDLES = "env.bundles"; 077 078 public static final String ENV_CONFIG = "env.config"; 079 080 /** 081 * @since 5.5 082 */ 083 public static final String ENV_TEMPLATES = "env.templates"; 084 085 public static final String ENV_TIMESTAMP = "sys.timestamp"; 086 087 /** 088 * The host application name. 089 * 090 * @see Environment#getHostApplicationName() 091 */ 092 public static final String ENV_HOSTAPP_NAME = "env.hostapp.name"; 093 094 /** 095 * The host application version 096 * 097 * @see Environment#getHostApplicationVersion() 098 */ 099 public static final String ENV_HOSTAPP_VERSION = "env.hostapp.version"; 100 101 protected boolean restart; 102 103 protected LocalPackage pkg; 104 105 protected String serverPathPrefix; 106 107 protected UpdateManager updateMgr; 108 109 protected boolean updateMgrLoaded = false; 110 111 protected PackageUpdateService service; 112 113 /** 114 * A map of environment key/values that can be used in XML install files as variables. 115 */ 116 protected final Map<String, String> env; 117 118 public AbstractTask(PackageUpdateService pus) { 119 service = pus; 120 env = new HashMap<>(); 121 Environment nxenv = Environment.getDefault(); 122 File serverHome = nxenv.getServerHome(); 123 File nxHome = nxenv.getRuntimeHome(); 124 File config = nxenv.getConfig(); 125 serverPathPrefix = serverHome.getAbsolutePath(); 126 if (!serverPathPrefix.endsWith(File.separator)) { 127 serverPathPrefix = serverPathPrefix.concat(File.separator); 128 } 129 env.put(ENV_SERVER_HOME, serverHome.getAbsolutePath()); 130 env.put(ENV_HOME, nxHome.getAbsolutePath()); 131 env.put(ENV_CONFIG, config.getAbsolutePath()); 132 env.put(ENV_HOSTAPP_NAME, nxenv.getHostApplicationName()); 133 env.put(ENV_HOSTAPP_VERSION, nxenv.getHostApplicationVersion()); 134 env.put(ENV_SYSLIB, new File(serverHome, "lib").getAbsolutePath()); 135 if (nxenv.isJBoss()) { 136 File ear = config.getParentFile(); 137 env.put(ENV_EAR, ear.getAbsolutePath()); 138 env.put(ENV_LIB, new File(ear, "lib").getAbsolutePath()); 139 env.put(ENV_BUNDLES, new File(ear, "bundles").getAbsolutePath()); 140 } else { 141 env.put(ENV_LIB, new File(nxHome, "lib").getAbsolutePath()); 142 env.put(ENV_BUNDLES, new File(nxHome, "bundles").getAbsolutePath()); 143 } 144 env.put(ENV_TEMPLATES, new File(serverHome, "templates").getAbsolutePath()); 145 env.put(ENV_TIMESTAMP, new SimpleDateFormat("yyMMddHHmmss").format(new Date())); 146 updateMgr = new UpdateManager(serverHome, service.getRegistry()); 147 } 148 149 public abstract boolean isInstallTask(); 150 151 @Override 152 @SuppressWarnings("hiding") 153 public void initialize(LocalPackage pkg, boolean restart) throws PackageException { 154 this.pkg = pkg; 155 this.restart = restart; 156 env.put(PKG_ID, pkg.getId()); 157 env.put(PKG_NAME, pkg.getName()); 158 env.put(PKG_VERSION, pkg.getVersion().toString()); 159 env.put(PKG_ROOT, pkg.getData().getRoot().getAbsolutePath()); 160 161 if (log.isDebugEnabled()) { 162 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 163 final PrintStream outPrint = new PrintStream(out); 164 MapUtils.debugPrint(outPrint, null, env); 165 log.debug(out.toString()); 166 } 167 } 168 169 /** 170 * Get a file given its key in the environment map. If no key exists then null is returned. 171 * 172 * @param key 173 */ 174 public File getFile(String key) { 175 String val = env.get(key); 176 return val == null ? null : new File(val); 177 } 178 179 @Override 180 public boolean isRestartRequired() { 181 return restart; 182 } 183 184 @Override 185 public LocalPackage getPackage() { 186 return pkg; 187 } 188 189 protected Map<Object, Object> createContextMap(Map<String, String> params) { 190 Map<Object, Object> map = new HashMap<>(System.getProperties()); 191 map.putAll(env); 192 if (params != null && !params.isEmpty()) { 193 map.putAll(params); 194 } 195 return map; 196 } 197 198 protected String loadParametrizedFile(File file, Map<String, String> params) throws IOException { 199 String content = FileUtils.readFile(file); 200 // replace variables. 201 return StringUtils.expandVars(content, createContextMap(params)); 202 } 203 204 protected void saveParams(Map<String, String> params) throws PackageException { 205 if (params == null || params.isEmpty()) { 206 return; 207 } 208 try { 209 Properties props = new Properties(); 210 props.putAll(params); 211 File file = pkg.getData().getEntry(LocalPackage.INSTALL_PROPERTIES); 212 FileOutputStream out = new FileOutputStream(file); 213 try { 214 props.store(out, "user install parameters"); 215 } finally { 216 out.close(); 217 } 218 } catch (IOException e) { 219 throw new PackageException("Failed to save install parameters", e); 220 } 221 } 222 223 @Override 224 public synchronized void run(Map<String, String> params) throws PackageException { 225 if (isInstallTask()) { 226 LocalPackage oldpkg = service.getActivePackage(pkg.getName()); 227 if (oldpkg != null) { 228 if (oldpkg.getPackageState() == PackageState.INSTALLING) { 229 throw new PackageException("Another package with the same name is installing: " + oldpkg.getName()); 230 } else { 231 // uninstall it. 232 Task utask = oldpkg.getUninstallTask(); 233 try { 234 utask.run(new HashMap<String, String>()); 235 } catch (PackageException e) { 236 utask.rollback(); 237 throw new PackageException("Failed to uninstall: " + oldpkg.getId() 238 + ". Cannot continue installation of " + pkg.getId(), e); 239 } 240 } 241 } 242 } 243 service.setPackageState(pkg, PackageState.INSTALLING); 244 saveParams(params); 245 doRun(params); 246 taskDone(); 247 if (updateMgrLoaded) { 248 updateMgr.store(); 249 } 250 } 251 252 public synchronized UpdateManager getUpdateManager() throws PackageException { 253 if (!updateMgrLoaded) { 254 updateMgr.load(); 255 updateMgrLoaded = true; 256 } 257 return updateMgr; 258 } 259 260 protected abstract void rollbackDone() throws PackageException; 261 262 protected abstract void taskDone() throws PackageException; 263 264 @Override 265 public void rollback() throws PackageException { 266 try { 267 doRollback(); 268 } finally { 269 rollbackDone(); 270 } 271 } 272 273 @Override 274 public void setRestartRequired(boolean isRestartRequired) { 275 this.restart = isRestartRequired; 276 } 277 278 protected abstract void doRun(Map<String, String> params) throws PackageException; 279 280 protected abstract void doRollback() throws PackageException; 281 282 @Override 283 public ValidationStatus validate() throws PackageException { 284 ValidationStatus status = new ValidationStatus(); 285 if (isInstallTask()) { 286 validateInstall(status); 287 } 288 doValidate(status); 289 return status; 290 } 291 292 public abstract void doValidate(ValidationStatus status) throws PackageException; 293 294 protected LocalPackage validateInstall(ValidationStatus status) throws PackageException { 295 LocalPackage oldpkg = service.getActivePackage(pkg.getName()); 296 if (oldpkg != null) { 297 if (oldpkg.getPackageState() == PackageState.INSTALLING) { 298 status.addWarning("A package with the same name: " + oldpkg.getId() 299 + " is being installing. Try again later."); 300 } else { 301 status.addWarning("The package " + oldpkg.getId() + " will be uninstalled!"); 302 } 303 return oldpkg; 304 } 305 return null; 306 } 307 308 @Override 309 public String getRelativeFilePath(File file) { 310 String path = file.getAbsolutePath(); 311 if (path.startsWith(serverPathPrefix)) { 312 return path.substring(serverPathPrefix.length()); 313 } 314 return path; 315 } 316 317}