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