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