/*
* (C) Copyright 2006-2014 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* bstefanescu, jcarsique
*/
package org.nuxeo.connect.update.standalone;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.attribute.FileTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.nuxeo.common.Environment;
import org.nuxeo.common.xmap.Context;
import org.nuxeo.common.xmap.XMap;
import org.nuxeo.common.xmap.XValueFactory;
import org.nuxeo.connect.update.LocalPackage;
import org.nuxeo.connect.update.PackageDependency;
import org.nuxeo.connect.update.PackageException;
import org.nuxeo.connect.update.PackageState;
import org.nuxeo.connect.update.PackageType;
import org.nuxeo.connect.update.PackageUpdateService;
import org.nuxeo.connect.update.Version;
import org.nuxeo.connect.update.model.PackageDefinition;
import org.nuxeo.connect.update.task.Command;
import org.nuxeo.connect.update.task.standalone.InstallTask;
import org.nuxeo.connect.update.task.standalone.UninstallTask;
import org.nuxeo.connect.update.task.standalone.commands.Append;
import org.nuxeo.connect.update.task.standalone.commands.Config;
import org.nuxeo.connect.update.task.standalone.commands.Copy;
import org.nuxeo.connect.update.task.standalone.commands.Delete;
import org.nuxeo.connect.update.task.standalone.commands.DeployConfigPlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.DeployPlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.FlushCoreCachePlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.FlushJaasCachePlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.FlushPlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.InstallPlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.LoadJarPlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.ParameterizedCopy;
import org.nuxeo.connect.update.task.standalone.commands.ReloadPropertiesPlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.UnAppend;
import org.nuxeo.connect.update.task.standalone.commands.UndeployConfigPlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.UndeployPlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.UninstallPlaceholder;
import org.nuxeo.connect.update.task.standalone.commands.UnloadJarPlaceholder;
import org.nuxeo.connect.update.task.update.Rollback;
import org.nuxeo.connect.update.task.update.Update;
import org.nuxeo.connect.update.xml.FormsDefinition;
import org.nuxeo.connect.update.xml.PackageDefinitionImpl;
/**
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*/
public class StandaloneUpdateService implements PackageUpdateService {
protected static XMap xmap;
protected PackagePersistence persistence;
protected Map<String, Class<? extends Command>> commands;
public static XMap getXmap() {
return xmap;
}
public StandaloneUpdateService(Environment env) throws IOException {
// TODO NXP-9086: Add some checks on the environment
Environment.setDefault(env);
persistence = new PackagePersistence(this);
commands = new HashMap<>();
}
@Override
public File getDataDir() {
return persistence.getRoot();
}
public PackagePersistence getPersistence() {
return persistence;
}
@Override
public LocalPackage addPackage(File file) throws PackageException {
return persistence.addPackage(file);
}
@Override
public void removePackage(String id) throws PackageException {
persistence.removePackage(id);
}
@Override
public LocalPackage getPackage(String id) throws PackageException {
return persistence.getPackage(id);
}
@Override
public List<LocalPackage> getPackages() throws PackageException {
return persistence.getPackages();
}
public static XMap createXmap() {
@SuppressWarnings("hiding")
XMap xmap = new XMap();
xmap.setValueFactory(PackageType.class, new XValueFactory() {
@Override
public String serialize(Context arg0, Object arg1) {
return ((PackageType) arg1).getValue();
}
@Override
public Object deserialize(Context arg0, String arg1) {
return PackageType.getByValue(arg1);
}
});
xmap.setValueFactory(Version.class, new XValueFactory() {
@Override
public String serialize(Context arg0, Object arg1) {
return arg1.toString();
}
@Override
public Object deserialize(Context arg0, String arg1) {
return new Version(arg1);
}
});
xmap.setValueFactory(PackageDependency.class, new XValueFactory() {
@Override
public String serialize(Context arg0, Object arg1) {
return arg1.toString();
}
@Override
public Object deserialize(Context arg0, String arg1) {
return new PackageDependency(arg1);
}
});
xmap.register(PackageDefinitionImpl.class);
xmap.register(FormsDefinition.class);
return xmap;
}
@Override
public void initialize() throws PackageException {
xmap = createXmap();
addCommands();
startInstalledPackages();
}
protected void addCommands() {
addCommand(Copy.ID, Copy.class);
addCommand(Append.ID, Append.class);
addCommand(UnAppend.ID, UnAppend.class);
addCommand(ParameterizedCopy.ID, ParameterizedCopy.class);
addCommand(Delete.ID, Delete.class);
addCommand(InstallPlaceholder.ID, InstallPlaceholder.class);
addCommand(UninstallPlaceholder.ID, UninstallPlaceholder.class);
addCommand(FlushCoreCachePlaceholder.ID, FlushCoreCachePlaceholder.class);
addCommand(FlushJaasCachePlaceholder.ID, FlushJaasCachePlaceholder.class);
addCommand(FlushPlaceholder.ID, FlushPlaceholder.class);
addCommand(ReloadPropertiesPlaceholder.ID, ReloadPropertiesPlaceholder.class);
addCommand(DeployPlaceholder.ID, DeployPlaceholder.class);
addCommand(UndeployPlaceholder.ID, UndeployPlaceholder.class);
addCommand(DeployConfigPlaceholder.ID, DeployConfigPlaceholder.class);
addCommand(UndeployConfigPlaceholder.ID, UndeployConfigPlaceholder.class);
addCommand(LoadJarPlaceholder.ID, LoadJarPlaceholder.class);
addCommand(UnloadJarPlaceholder.ID, UnloadJarPlaceholder.class);
addCommand(Config.ID, Config.class);
addCommand(Update.ID, Update.class);
addCommand(Rollback.ID, Rollback.class);
}
@Deprecated
@Override
public void setPackageState(LocalPackage pkg, int state) throws PackageException {
persistence.updateState(pkg.getId(), state);
pkg.setState(state);
}
@Override
public void setPackageState(LocalPackage pkg, PackageState state) throws PackageException {
persistence.updateState(pkg.getId(), state);
pkg.setState(state);
}
@Override
public void shutdown() throws PackageException {
xmap = null;
}
@Override
public Command getCommand(String id) throws PackageException {
Class<? extends Command> type = commands.get(id);
if (type != null) {
try {
return type.getConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new PackageException("Failed to load command " + id, e);
}
}
return null;
}
@Override
public String getDefaultInstallTaskType() {
return InstallTask.class.getName();
}
@Override
public String getDefaultUninstallTaskType() {
return UninstallTask.class.getName();
}
public void addCommand(String id, Class<? extends Command> cmd) {
commands.put(id, cmd);
}
public void removeCommand(String id) {
commands.remove(id);
}
@Override
public LocalPackage getActivePackage(String name) throws PackageException {
return persistence.getActivePackage(name);
}
@Override
public PackageDefinition loadPackageFromZip(File file) throws PackageException {
ZipFile zip = null;
try {
zip = new ZipFile(file);
ZipEntry mfEntry = zip.getEntry(LocalPackage.MANIFEST);
InputStream mfStream = zip.getInputStream(mfEntry);
return loadPackage(mfStream);
} catch (PackageException e) {
throw e;
} catch (IOException e) {
throw new PackageException("Failed to load package definition from zip file: " + file, e);
} finally {
if (zip != null) {
try {
zip.close();
} catch (IOException e) {
throw new PackageException("Failed to close package zip: " + file, e);
}
}
}
}
@Override
public PackageDefinition loadPackage(File file) throws PackageException {
FileInputStream in = null;
try {
in = new FileInputStream(file);
return loadPackage(in);
} catch (PackageException e) {
throw e;
} catch (IOException e) {
throw new PackageException("Failed to load XML package definition from file: " + file, e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
throw new PackageException("Failed to close input stream for " + file, e);
}
}
}
@Override
public PackageDefinition loadPackage(InputStream in) throws PackageException {
try {
return (PackageDefinition) xmap.load(in);
} catch (IOException e) {
throw new PackageException("Failed to parse XML package definition", e);
}
}
protected void startInstalledPackages() throws PackageException {
for (Entry<String, PackageState> entry : persistence.getStates().entrySet()) {
if (entry.getValue() == PackageState.INSTALLED) {
persistence.updateState(entry.getKey(), PackageState.STARTED);
}
}
}
@Override
public void reset() throws PackageException {
persistence.reset();
}
@Override
public void restart() throws PackageException {
throw new UnsupportedOperationException();
}
@Override
public boolean isStarted(String pkgId) {
return persistence.getState(pkgId) == PackageState.STARTED;
}
@Override
public File getRegistry() {
return new File(getDataDir(), "registry.xml");
}
@Override
public File getBackupDir() {
return new File(getDataDir(), "backup");
}
@Override
public FileTime getInstallDate(String id) {
return getPersistence().getInstallDate(id);
}
}