Skip to content
Permalink
Browse files
FELIX-4491, FELIX-4718, FELIX-4719:
- (large patch due to unexpected downtime of SVN);
- added support for non-processed resources in deployment packages, which
  makes the Felix DP a little more compliant to the OSGi specification. This
  should fix FELIX-4491 (and FELIX-4516 as well?);
- reviewed and fixed the snapshot creation/restore functionality used for
  the data area of bundles that are upgraded. Both pieces of functionality
  were broken and in desparate need of fixing. Added several tests to cover
  this functionality.



git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1643202 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
Jan Willem Janssen committed Dec 5, 2014
1 parent d2cb9ae commit e86c5ab798e682aa12c2fcf3a4e422c58d26ae5e
Show file tree
Hide file tree
Showing 21 changed files with 1,005 additions and 274 deletions.
@@ -27,7 +27,7 @@
*/
public class ResourceInfoImpl extends AbstractInfo {

private String m_resourceProcessor;
private final String m_resourceProcessor;

/**
* Create an instance of this class.
@@ -38,7 +38,21 @@ public class ResourceInfoImpl extends AbstractInfo {
*/
public ResourceInfoImpl(String path, Attributes attributes) throws DeploymentException {
super(path, attributes);
m_resourceProcessor = attributes.getValue(RESOURCE_PROCESSOR);

String rp = attributes.getValue(RESOURCE_PROCESSOR);
if (rp != null && "".equals(rp.trim())) {
rp = null;
}

m_resourceProcessor = rp;
}

/**
* @return <code>true</code> if this resource needs to be processed by a customizer/resource processor,
* <code>false</code> otherwise.
*/
public boolean isProcessedResource() {
return m_resourceProcessor != null;
}

/**
@@ -61,18 +61,21 @@ protected void doExecute(DeploymentSessionImpl session) throws Exception {
ResourceInfoImpl[] orderedTargetResources = target.getOrderedResourceInfos();
for (int i = orderedTargetResources.length - 1; i >= 0; i--) {
ResourceInfoImpl resourceInfo = orderedTargetResources[i];
// FELIX-4491: only resources that need to be processed should be handled...
if (!resourceInfo.isProcessedResource()) {
session.getLog().log(LogService.LOG_INFO, "Ignoring non-processed resource: " + resourceInfo.getPath());
continue;
}

String rpName = resourceInfo.getResourceProcessor();
String path = resourceInfo.getPath();

if (resourceProcessors.contains(rpName)) {
// Keep track of which resource processors we've seen already...
if (!resourceProcessors.add(rpName)) {
// Already seen this RP; continue on the next one...
continue;
}

// Keep track of which resource processors we've seen already...
resourceProcessors.add(rpName);

ServiceReference ref = target.getResourceProcessor(path);
if (ref == null) {
log.log(LogService.LOG_ERROR, "Failed to find resource processor for '" + rpName + "'!");
@@ -56,6 +56,12 @@ protected void doExecute(DeploymentSessionImpl session) throws Exception {
ResourceInfoImpl[] orderedTargetResources = target.getOrderedResourceInfos();
for (int i = orderedTargetResources.length - 1; i >= 0; i--) {
ResourceInfoImpl resourceInfo = orderedTargetResources[i];
// FELIX-4491: only resources that need to be processed should be handled...
if (!resourceInfo.isProcessedResource()) {
session.getLog().log(LogService.LOG_INFO, "Ignoring non-processed resource: " + resourceInfo.getPath());
continue;
}

String path = resourceInfo.getPath();
if (source.getResourceInfoByPath(path) == null) {
ServiceReference ref = target.getResourceProcessor(path);
@@ -30,6 +30,7 @@
import org.osgi.service.deploymentadmin.DeploymentException;
import org.osgi.service.deploymentadmin.spi.ResourceProcessor;
import org.osgi.service.deploymentadmin.spi.ResourceProcessorException;
import org.osgi.service.log.LogService;

/**
* Command that processes all the processed resources in the source deployment
@@ -49,7 +50,7 @@ public class ProcessResourceCommand extends Command {
* committed at a later stage in the deployment session.
*
* @param commitCommand The <code>CommitCommand</code> that will commit all
* resource processors used in this command.
* resource processors used in this command.
*/
public ProcessResourceCommand(CommitResourceCommand commitCommand) {
m_commitCommand = commitCommand;
@@ -84,6 +85,11 @@ protected void doExecute(DeploymentSessionImpl session) throws Exception {
if (resourceInfo == null) {
throw new DeploymentException(CODE_OTHER_ERROR, "Resource '" + name + "' is not described in the manifest.");
}
// FELIX-4491: only resources that need to be processed should be handled...
if (!resourceInfo.isProcessedResource()) {
session.getLog().log(LogService.LOG_INFO, "Ignoring non-processed resource: " + resourceInfo.getPath());
continue;
}

ServiceReference ref = source.getResourceProcessor(name);
if (ref == null) {
@@ -81,48 +81,114 @@ protected void doExecute(DeploymentSessionImpl session) throws Exception {
}
}

private void store(File source, File target) throws IOException {
ZipOutputStream output = null;
protected static void delete(File root, boolean deleteRoot) {
if (root.isDirectory()) {
File[] childs = root.listFiles();
for (int i = 0; i < childs.length; i++) {
delete(childs[i], true);
}
}
if (deleteRoot) {
root.delete();
}
}

protected static void restore(File archiveFile, File targetDir) throws IOException {
ZipInputStream input = null;
try {
File[] children = source.listFiles();
output = new ZipOutputStream(new FileOutputStream(target));
for (int i = 0; i < children.length; i++) {
storeRecursive(source, new File(children[i].getName()), output);
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);
}
}

private void storeRecursive(File current, File path, ZipOutputStream output) throws IOException {
output.putNextEntry(new ZipEntry(path.getPath()));
if (current.isDirectory()) {
output.closeEntry();
File[] childs = current.listFiles();
for (int i = 0; i < childs.length; i++) {
storeRecursive(childs[i], new File(path, childs[i].getName()), 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);
}
}
else {
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(current);
byte[] buffer = new byte[4096];
for (int i = input.read(buffer); i != -1; i = input.read(buffer)) {
output.write(buffer, 0, i);
}
output.closeEntry();
input = new FileInputStream(entry);
copy(input, output);
}
finally {
closeSilently(input);
output.closeEntry();
}
}
else if (entry.isDirectory()) {
String baseDir = "";
if (!"".equals(entryName)) {
baseDir = entryName.concat(File.separator);

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) {
@@ -139,9 +205,7 @@ protected void doRun() {

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) {
@@ -152,8 +216,8 @@ private RestoreSnapshotRunnable(DeploymentSessionImpl session, File snapshot, Fi

protected void doRun() throws Exception {
try {
delete(m_root, false);
unpack(m_snapshot, m_root);
delete(m_root, false /* deleteRoot */);
restore(m_snapshot, m_root);
}
finally {
m_snapshot.delete();
@@ -163,46 +227,5 @@ protected void doRun() throws Exception {
protected void onFailure(Exception e) {
m_session.getLog().log(LogService.LOG_WARNING, "Failed to restore snapshot!", e);
}

private void delete(File root, boolean deleteRoot) {
if (root.isDirectory()) {
File[] childs = root.listFiles();
for (int i = 0; i < childs.length; i++) {
delete(childs[i], true);
}
}
if (deleteRoot) {
root.delete();
}
}

private void unpack(File source, File target) throws IOException {
ZipInputStream input = null;
try {
input = new ZipInputStream(new FileInputStream(source));
for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) {
if (entry.isDirectory()) {
(new File(target, entry.getName())).mkdirs();
}
else {
OutputStream output = null;
try {
output = new FileOutputStream(target);
byte[] buffer = new byte[4096];
for (int i = input.read(buffer); i > -1; i = input.read(buffer)) {
output.write(buffer, 0, i);
}
}
finally {
closeSilently(output);
}
}
input.closeEntry();
}
}
finally {
closeSilently(input);
}
}
}
}

0 comments on commit e86c5ab

Please sign in to comment.