org.jclouds.virtualbox.functions.CreateMediumIfNotAlreadyExists.java Source code

Java tutorial

Introduction

Here is the source code for org.jclouds.virtualbox.functions.CreateMediumIfNotAlreadyExists.java

Source

/*
 * 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.jclouds.virtualbox.functions;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.inject.Inject;
import javax.inject.Singleton;

import org.jclouds.virtualbox.domain.HardDisk;
import org.jclouds.virtualbox.util.MachineUtils;
import org.virtualbox_4_2.AccessMode;
import org.virtualbox_4_2.DeviceType;
import org.virtualbox_4_2.IMachine;
import org.virtualbox_4_2.IMedium;
import org.virtualbox_4_2.IMediumAttachment;
import org.virtualbox_4_2.IProgress;
import org.virtualbox_4_2.IVirtualBox;
import org.virtualbox_4_2.VBoxException;
import org.virtualbox_4_2.VirtualBoxManager;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;

/**
 * @author Mattias Holmqvist
 */
@Singleton
public class CreateMediumIfNotAlreadyExists implements Function<HardDisk, IMedium> {

    private final Supplier<VirtualBoxManager> manager;
    private final MachineUtils machineUtils;
    private final boolean overwriteIfExists;

    @Inject
    public CreateMediumIfNotAlreadyExists(Supplier<VirtualBoxManager> manager, MachineUtils machineUtils,
            boolean overwriteIfExists) {
        this.manager = manager;
        this.machineUtils = machineUtils;
        this.overwriteIfExists = overwriteIfExists;
    }

    public static final Pattern ATTACHED_PATTERN = Pattern.compile(".*is still attached.*: ([-0-9a-f]+) .*");

    @Override
    public IMedium apply(HardDisk hardDisk) {
        IVirtualBox vBox = manager.get().getVBox();
        try {
            String diskPath = hardDisk.getDiskPath();
            final IMedium medium = vBox.openMedium(diskPath, DeviceType.HardDisk, AccessMode.ReadWrite, false);
            if (overwriteIfExists) {
                try {
                    deleteMediumAndBlockUntilComplete(medium);
                } catch (VBoxException e) {
                    onAlreadyAttachedExceptionDetachOrPropagate(vBox, medium, e);
                }
                return createNewMedium(vBox, hardDisk);
            } else {
                throw new IllegalStateException("Medium for path " + diskPath + " already exists.");
            }
        } catch (VBoxException e) {
            if (notFoundException(e))
                return createNewMedium(vBox, hardDisk);
            throw e;
        }
    }

    private void onAlreadyAttachedExceptionDetachOrPropagate(IVirtualBox vBox, final IMedium medium,
            VBoxException e) {
        Matcher matcher = ATTACHED_PATTERN.matcher(e.getMessage());
        if (matcher.find()) {
            String machineId = matcher.group(1);
            IMachine immutableMachine = vBox.findMachine(machineId);
            IMediumAttachment mediumAttachment = Iterables.find(immutableMachine.getMediumAttachments(),
                    new Predicate<IMediumAttachment>() {
                        public boolean apply(IMediumAttachment in) {
                            return in.getMedium().getId().equals(medium.getId());
                        }
                    });
            machineUtils.writeLockMachineAndApply(immutableMachine.getName(), new DetachDistroMediumFromMachine(
                    mediumAttachment.getController(), mediumAttachment.getPort(), mediumAttachment.getDevice()));
            deleteMediumAndBlockUntilComplete(medium);
        } else {
            throw e;
        }
    }

    void deleteMediumAndBlockUntilComplete(IMedium medium) {
        final IProgress progress = medium.deleteStorage();
        progress.waitForCompletion(-1);
    }

    private IMedium createNewMedium(IVirtualBox vBox, HardDisk hardDisk) {
        IMedium medium = vBox.createHardDisk(hardDisk.getDiskFormat(), hardDisk.getDiskPath());
        createBaseStorage(medium);
        return medium;
    }

    private boolean notFoundException(VBoxException e) {
        return e.getMessage().contains("VirtualBox error: Could not find file for the medium ");
    }

    private void createBaseStorage(IMedium hardDisk) {
        try {
            long size = 4L * 1024L * 1024L * 1024L - 4L;
            IProgress storageCreation = hardDisk.createBaseStorage(size,
                    (long) org.virtualbox_4_2.jaxws.MediumVariant.STANDARD.ordinal());
            storageCreation.waitForCompletion(-1);
        } catch (VBoxException e) {
            if (fileNotFoundException(e)) {
                // File for medium could not be found. Something wrong with
                // creation.
                hardDisk.deleteStorage();
            }
            if (!storageAlreadyExists(e)) {
                // Hard disk file was created but the storage had been created
                // before that.
                throw e;
            }
        }
    }

    private boolean fileNotFoundException(VBoxException e) {
        return e.getMessage().contains("VERR_FILE_NOT_FOUND");
    }

    private boolean storageAlreadyExists(VBoxException e) {
        return e.getMessage().contains("VirtualBox error: Storage for the medium ")
                && e.getMessage().contains("is already created");
    }

}