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.standalone; 018 019import java.io.File; 020import java.io.FileInputStream; 021import java.io.IOException; 022import java.io.InputStream; 023import java.nio.file.attribute.FileTime; 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027import java.util.Map.Entry; 028import java.util.zip.ZipEntry; 029import java.util.zip.ZipFile; 030 031import org.nuxeo.common.Environment; 032import org.nuxeo.common.xmap.Context; 033import org.nuxeo.common.xmap.XMap; 034import org.nuxeo.common.xmap.XValueFactory; 035import org.nuxeo.connect.update.LocalPackage; 036import org.nuxeo.connect.update.PackageDependency; 037import org.nuxeo.connect.update.PackageException; 038import org.nuxeo.connect.update.PackageState; 039import org.nuxeo.connect.update.PackageType; 040import org.nuxeo.connect.update.PackageUpdateService; 041import org.nuxeo.connect.update.Version; 042import org.nuxeo.connect.update.model.PackageDefinition; 043import org.nuxeo.connect.update.task.Command; 044import org.nuxeo.connect.update.task.standalone.InstallTask; 045import org.nuxeo.connect.update.task.standalone.UninstallTask; 046import org.nuxeo.connect.update.task.standalone.commands.Append; 047import org.nuxeo.connect.update.task.standalone.commands.Config; 048import org.nuxeo.connect.update.task.standalone.commands.Copy; 049import org.nuxeo.connect.update.task.standalone.commands.Delete; 050import org.nuxeo.connect.update.task.standalone.commands.DeployConfigPlaceholder; 051import org.nuxeo.connect.update.task.standalone.commands.DeployPlaceholder; 052import org.nuxeo.connect.update.task.standalone.commands.FlushCoreCachePlaceholder; 053import org.nuxeo.connect.update.task.standalone.commands.FlushJaasCachePlaceholder; 054import org.nuxeo.connect.update.task.standalone.commands.FlushPlaceholder; 055import org.nuxeo.connect.update.task.standalone.commands.InstallPlaceholder; 056import org.nuxeo.connect.update.task.standalone.commands.LoadJarPlaceholder; 057import org.nuxeo.connect.update.task.standalone.commands.ParameterizedCopy; 058import org.nuxeo.connect.update.task.standalone.commands.ReloadPropertiesPlaceholder; 059import org.nuxeo.connect.update.task.standalone.commands.UnAppend; 060import org.nuxeo.connect.update.task.standalone.commands.UndeployConfigPlaceholder; 061import org.nuxeo.connect.update.task.standalone.commands.UndeployPlaceholder; 062import org.nuxeo.connect.update.task.standalone.commands.UninstallPlaceholder; 063import org.nuxeo.connect.update.task.standalone.commands.UnloadJarPlaceholder; 064import org.nuxeo.connect.update.task.update.Rollback; 065import org.nuxeo.connect.update.task.update.Update; 066import org.nuxeo.connect.update.xml.FormsDefinition; 067import org.nuxeo.connect.update.xml.PackageDefinitionImpl; 068 069/** 070 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 071 */ 072public class StandaloneUpdateService implements PackageUpdateService { 073 074 protected static XMap xmap; 075 076 protected PackagePersistence persistence; 077 078 protected Map<String, Class<? extends Command>> commands; 079 080 public static XMap getXmap() { 081 return xmap; 082 } 083 084 public StandaloneUpdateService(Environment env) throws IOException { 085 // TODO NXP-9086: Add some checks on the environment 086 Environment.setDefault(env); 087 persistence = new PackagePersistence(this); 088 commands = new HashMap<>(); 089 } 090 091 @Override 092 public File getDataDir() { 093 return persistence.getRoot(); 094 } 095 096 public PackagePersistence getPersistence() { 097 return persistence; 098 } 099 100 @Override 101 public LocalPackage addPackage(File file) throws PackageException { 102 return persistence.addPackage(file); 103 } 104 105 @Override 106 public void removePackage(String id) throws PackageException { 107 persistence.removePackage(id); 108 } 109 110 @Override 111 public LocalPackage getPackage(String id) throws PackageException { 112 return persistence.getPackage(id); 113 } 114 115 @Override 116 public List<LocalPackage> getPackages() throws PackageException { 117 return persistence.getPackages(); 118 } 119 120 public static XMap createXmap() { 121 @SuppressWarnings("hiding") 122 XMap xmap = new XMap(); 123 xmap.setValueFactory(PackageType.class, new XValueFactory() { 124 @Override 125 public String serialize(Context arg0, Object arg1) { 126 return ((PackageType) arg1).getValue(); 127 } 128 129 @Override 130 public Object deserialize(Context arg0, String arg1) { 131 return PackageType.getByValue(arg1); 132 } 133 }); 134 xmap.setValueFactory(Version.class, new XValueFactory() { 135 @Override 136 public String serialize(Context arg0, Object arg1) { 137 return arg1.toString(); 138 } 139 140 @Override 141 public Object deserialize(Context arg0, String arg1) { 142 return new Version(arg1); 143 } 144 }); 145 xmap.setValueFactory(PackageDependency.class, new XValueFactory() { 146 147 @Override 148 public String serialize(Context arg0, Object arg1) { 149 return arg1.toString(); 150 } 151 152 @Override 153 public Object deserialize(Context arg0, String arg1) { 154 return new PackageDependency(arg1); 155 } 156 }); 157 xmap.register(PackageDefinitionImpl.class); 158 xmap.register(FormsDefinition.class); 159 return xmap; 160 } 161 162 @Override 163 public void initialize() throws PackageException { 164 xmap = createXmap(); 165 addCommands(); 166 startInstalledPackages(); 167 } 168 169 protected void addCommands() { 170 addCommand(Copy.ID, Copy.class); 171 addCommand(Append.ID, Append.class); 172 addCommand(UnAppend.ID, UnAppend.class); 173 addCommand(ParameterizedCopy.ID, ParameterizedCopy.class); 174 addCommand(Delete.ID, Delete.class); 175 addCommand(InstallPlaceholder.ID, InstallPlaceholder.class); 176 addCommand(UninstallPlaceholder.ID, UninstallPlaceholder.class); 177 addCommand(FlushCoreCachePlaceholder.ID, FlushCoreCachePlaceholder.class); 178 addCommand(FlushJaasCachePlaceholder.ID, FlushJaasCachePlaceholder.class); 179 addCommand(FlushPlaceholder.ID, FlushPlaceholder.class); 180 addCommand(ReloadPropertiesPlaceholder.ID, ReloadPropertiesPlaceholder.class); 181 addCommand(DeployPlaceholder.ID, DeployPlaceholder.class); 182 addCommand(UndeployPlaceholder.ID, UndeployPlaceholder.class); 183 addCommand(DeployConfigPlaceholder.ID, DeployConfigPlaceholder.class); 184 addCommand(UndeployConfigPlaceholder.ID, UndeployConfigPlaceholder.class); 185 addCommand(LoadJarPlaceholder.ID, LoadJarPlaceholder.class); 186 addCommand(UnloadJarPlaceholder.ID, UnloadJarPlaceholder.class); 187 addCommand(Config.ID, Config.class); 188 addCommand(Update.ID, Update.class); 189 addCommand(Rollback.ID, Rollback.class); 190 } 191 192 @Deprecated 193 @Override 194 public void setPackageState(LocalPackage pkg, int state) throws PackageException { 195 persistence.updateState(pkg.getId(), state); 196 pkg.setState(state); 197 } 198 199 @Override 200 public void setPackageState(LocalPackage pkg, PackageState state) throws PackageException { 201 persistence.updateState(pkg.getId(), state); 202 pkg.setState(state); 203 } 204 205 @Override 206 public void shutdown() throws PackageException { 207 xmap = null; 208 } 209 210 @Override 211 public Command getCommand(String id) throws PackageException { 212 Class<? extends Command> type = commands.get(id); 213 if (type != null) { 214 try { 215 return type.getConstructor().newInstance(); 216 } catch (ReflectiveOperationException e) { 217 throw new PackageException("Failed to load command " + id, e); 218 } 219 } 220 return null; 221 } 222 223 @Override 224 public String getDefaultInstallTaskType() { 225 return InstallTask.class.getName(); 226 } 227 228 @Override 229 public String getDefaultUninstallTaskType() { 230 return UninstallTask.class.getName(); 231 } 232 233 public void addCommand(String id, Class<? extends Command> cmd) { 234 commands.put(id, cmd); 235 } 236 237 public void removeCommand(String id) { 238 commands.remove(id); 239 } 240 241 @Override 242 public LocalPackage getActivePackage(String name) throws PackageException { 243 return persistence.getActivePackage(name); 244 } 245 246 @Override 247 public PackageDefinition loadPackageFromZip(File file) throws PackageException { 248 ZipFile zip = null; 249 try { 250 zip = new ZipFile(file); 251 ZipEntry mfEntry = zip.getEntry(LocalPackage.MANIFEST); 252 InputStream mfStream = zip.getInputStream(mfEntry); 253 return loadPackage(mfStream); 254 } catch (PackageException e) { 255 throw e; 256 } catch (IOException e) { 257 throw new PackageException("Failed to load package definition from zip file: " + file, e); 258 } finally { 259 if (zip != null) { 260 try { 261 zip.close(); 262 } catch (IOException e) { 263 throw new PackageException("Failed to close package zip: " + file, e); 264 } 265 } 266 } 267 } 268 269 @Override 270 public PackageDefinition loadPackage(File file) throws PackageException { 271 FileInputStream in = null; 272 try { 273 in = new FileInputStream(file); 274 return loadPackage(in); 275 } catch (PackageException e) { 276 throw e; 277 } catch (IOException e) { 278 throw new PackageException("Failed to load XML package definition from file: " + file, e); 279 } finally { 280 try { 281 if (in != null) { 282 in.close(); 283 } 284 } catch (IOException e) { 285 throw new PackageException("Failed to close input stream for " + file, e); 286 } 287 } 288 } 289 290 @Override 291 public PackageDefinition loadPackage(InputStream in) throws PackageException { 292 try { 293 return (PackageDefinition) xmap.load(in); 294 } catch (IOException e) { 295 throw new PackageException("Failed to parse XML package definition", e); 296 } 297 } 298 299 protected void startInstalledPackages() throws PackageException { 300 for (Entry<String, PackageState> entry : persistence.getStates().entrySet()) { 301 if (entry.getValue() == PackageState.INSTALLED) { 302 persistence.updateState(entry.getKey(), PackageState.STARTED); 303 } 304 } 305 } 306 307 @Override 308 public void reset() throws PackageException { 309 persistence.reset(); 310 } 311 312 @Override 313 public void restart() throws PackageException { 314 throw new UnsupportedOperationException(); 315 } 316 317 @Override 318 public boolean isStarted(String pkgId) { 319 return persistence.getState(pkgId) == PackageState.STARTED; 320 } 321 322 @Override 323 public File getRegistry() { 324 return new File(getDataDir(), "registry.xml"); 325 } 326 327 @Override 328 public File getBackupDir() { 329 return new File(getDataDir(), "backup"); 330 } 331 332 @Override 333 public FileTime getInstallDate(String id) { 334 return getPersistence().getInstallDate(id); 335 } 336 337}