blob: 29c2c2c2b3d9ec53ffc9189de3f0601bed21de5c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.felix.deploymentadmin.spi;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.felix.deploymentadmin.AbstractDeploymentPackage;
import org.apache.felix.deploymentadmin.Utils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.deploymentadmin.BundleInfo;
import org.osgi.service.deploymentadmin.DeploymentException;
import org.osgi.service.log.LogService;
public class SnapshotCommand extends Command {
/** The ZIP specification mandates that directory-entries end with a forward slash (on all platforms). */
static final String FORWARD_SLASH = "/";
private final GetStorageAreaCommand m_getStorageAreaCommand;
public SnapshotCommand(GetStorageAreaCommand getStorageAreaCommand) {
m_getStorageAreaCommand = getStorageAreaCommand;
}
protected void doExecute(DeploymentSessionImpl session) throws Exception {
AbstractDeploymentPackage target = session.getTargetAbstractDeploymentPackage();
BundleContext context = session.getBundleContext();
BundleInfo[] infos = target.getBundleInfos();
Map storageAreas = m_getStorageAreaCommand.getStorageAreas();
for (int i = 0; i < infos.length; i++) {
if (isCancelled()) {
throw new DeploymentException(CODE_CANCELLED);
}
String symbolicName = infos[i].getSymbolicName();
Bundle bundle = target.getBundle(symbolicName);
if (bundle != null) {
File root = (File) storageAreas.get(symbolicName);
if (root != null) {
File snapshot = context.getDataFile("snapshots");
snapshot.mkdirs();
snapshot = new File(snapshot, infos[i].getSymbolicName());
try {
snapshot.createNewFile();
store(root, snapshot);
addRollback(new RestoreSnapshotRunnable(session, snapshot, root));
addCommit(new DeleteSnapshotRunnable(session, snapshot));
}
catch (Exception e) {
session.getLog().log(LogService.LOG_WARNING, "Could not access storage area of bundle '" + symbolicName + "'!", e);
snapshot.delete();
}
}
else {
session.getLog().log(LogService.LOG_WARNING, "Could not retrieve storage area of bundle '" + symbolicName + "', skipping it.");
}
}
}
}
protected static void restore(File archiveFile, File targetDir) throws IOException {
ZipInputStream input = null;
try {
input = new ZipInputStream(new FileInputStream(archiveFile));
ZipEntry entry;
while ((entry = input.getNextEntry()) != null) {
File targetEntry = new File(targetDir, entry.getName());
if (entry.isDirectory()) {
if (!targetEntry.mkdirs()) {
throw new IOException("Failed to create one or more sub-directories!");
}
}
else {
OutputStream output = null;
try {
output = new FileOutputStream(targetEntry);
copy(input, output);
}
finally {
closeSilently(output);
}
}
input.closeEntry();
}
}
finally {
closeSilently(input);
}
}
protected static void store(File sourceDir, File archiveFile) throws IOException {
ZipOutputStream output = null;
try {
output = new ZipOutputStream(new FileOutputStream(archiveFile));
// Traverse source directory recursively, and store all entries...
store(output, sourceDir, "");
}
finally {
closeSilently(output);
}
}
protected static void copy(InputStream is, OutputStream os) throws IOException {
byte[] buffer = new byte[8192];
int read;
try {
while ((read = is.read(buffer)) != -1) {
os.write(buffer, 0, read);
}
}
finally {
os.flush();
}
}
private static void store(ZipOutputStream output, File sourceDir, String entryName) throws IOException {
File entry = new File(sourceDir, entryName);
if (entry.isFile()) {
ZipEntry zipEntry = new ZipEntry(entryName);
zipEntry.setSize(entry.length());
zipEntry.setTime(entry.lastModified());
output.putNextEntry(zipEntry);
InputStream input = null;
try {
input = new FileInputStream(entry);
copy(input, output);
}
finally {
closeSilently(input);
output.closeEntry();
}
}
else if (entry.isDirectory()) {
String baseDir = "";
if (!"".equals(entryName)) {
baseDir = entryName;
// Directories *must* use forward slashes...
if (!baseDir.endsWith(FORWARD_SLASH)) {
baseDir = baseDir.concat(FORWARD_SLASH);
}
output.putNextEntry(new ZipEntry(baseDir));
output.closeEntry();
}
String[] entries = entry.list();
for (int i = 0; i < entries.length; i++) {
store(output, sourceDir, baseDir.concat(entries[i]));
}
}
}
private static class DeleteSnapshotRunnable extends AbstractAction {
private final DeploymentSessionImpl m_session;
private final File m_snapshot;
private DeleteSnapshotRunnable(DeploymentSessionImpl session, File snapshot) {
m_session = session;
m_snapshot = snapshot;
}
protected void doRun() {
if (!m_snapshot.delete()) {
m_session.getLog().log(LogService.LOG_WARNING, "Failed to delete snapshot in " + m_snapshot + "!");
}
}
}
private static class RestoreSnapshotRunnable extends AbstractAction {
private final DeploymentSessionImpl m_session;
private final File m_snapshot;
private final File m_root;
private RestoreSnapshotRunnable(DeploymentSessionImpl session, File snapshot, File root) {
m_session = session;
m_snapshot = snapshot;
m_root = root;
}
protected void doRun() throws Exception {
try {
Utils.delete(m_root, false /* deleteRoot */);
restore(m_snapshot, m_root);
}
finally {
m_snapshot.delete();
}
}
protected void onFailure(Exception e) {
m_session.getLog().log(LogService.LOG_WARNING, "Failed to restore snapshot!", e);
}
}
}