package net.rrm.ehour.ui.admin.backup.restore;
import net.rrm.ehour.backup.domain.ImportException;
import net.rrm.ehour.backup.domain.ParseSession;
import net.rrm.ehour.backup.service.restore.BackupFileUtil;
import net.rrm.ehour.backup.service.restore.RestoreService;
import net.rrm.ehour.ui.admin.backup.BackupAjaxEventType;
import net.rrm.ehour.ui.common.border.GreyBlueRoundedBorder;
import net.rrm.ehour.ui.common.border.GreyRoundedBorder;
import net.rrm.ehour.ui.common.component.JavaScriptConfirmation;
import net.rrm.ehour.ui.common.decorator.DemoDecorator;
import net.rrm.ehour.ui.common.decorator.LoadingSpinnerDecorator;
import net.rrm.ehour.ui.common.event.AjaxEvent;
import net.rrm.ehour.ui.common.event.PayloadAjaxEvent;
import net.rrm.ehour.ui.common.panel.AbstractAjaxPanel;
import net.rrm.ehour.ui.common.session.EhourWebSession;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.ajax.attributes.IAjaxCallListener;
import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.upload.FileUpload;
import org.apache.wicket.markup.html.form.upload.FileUploadField;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.util.time.Duration;
import org.wicketstuff.async.components.IRunnableFactory;
import org.wicketstuff.async.components.InteractionState;
import org.wicketstuff.async.components.ProgressBar;
import org.wicketstuff.async.components.ProgressButton;
import org.wicketstuff.async.task.AbstractTaskContainer;
import org.wicketstuff.async.task.DefaultTaskManager;
import org.wicketstuff.async.task.IProgressObservableRunnable;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class RestoreDbFormPanel extends AbstractAjaxPanel<Void> {
private static final Logger LOGGER = Logger.getLogger(RestoreDbFormPanel.class);
private static final String ID_FEEDBACK = "feedback";
private static final String ID_RESTORE_BORDER = "restoreBorder";
private Form<Void> form;
@SpringBean
private RestoreService restoreService;
private FeedbackPanel feedback;
public RestoreDbFormPanel(String id) {
super(id);
}
@Override
protected void onInitialize() {
super.onInitialize();
GreyRoundedBorder frame = new GreyRoundedBorder("frame", new ResourceModel("admin.export.restore.title"));
addOrReplace(frame);
GreyBlueRoundedBorder restoreBorder = new GreyBlueRoundedBorder(ID_RESTORE_BORDER);
frame.add(restoreBorder);
form = addUploadForm("form");
restoreBorder.add(form);
feedback = new FeedbackPanel(ID_FEEDBACK);
feedback.setOutputMarkupId(true);
form.add(feedback);
}
private Form<Void> addUploadForm(String id) {
final boolean inDemoMode = EhourWebSession.getEhourConfig().isInDemoMode();
Form<Void> form = new Form<>(id);
form.setMultiPart(true);
final FileUploadField file = new FileUploadField("file");
form.add(file);
AbstractTaskContainer taskContainer = DefaultTaskManager.getInstance().makeContainer(1000l, TimeUnit.MINUTES);
final ParseSession session = new ParseSession();
ProgressButton progressButton = new ProgressButton("submit", form, Model.of(taskContainer), getRunnableFactory(session), Duration.milliseconds(500l)) {
@Override
protected void onTaskError(AjaxRequestTarget ajaxRequestTarget) {
ajaxRequestTarget.add(feedback);
}
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
if (isValidUpload(file)) {
byte[] bytes = file.getFileUpload().getBytes();
try {
String tempFilename = BackupFileUtil.writeToTempFile(bytes);
session.setFilename(tempFilename);
super.onSubmit(target, form);
} catch (IOException e) {
LOGGER.error("While restoring", e);
error("Failed to write to temp file");
}
this.setEnabled(false);
} else {
target.add(feedback);
}
}
@Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
super.updateAjaxAttributes(attributes);
List<IAjaxCallListener> callListeners = attributes.getAjaxCallListeners();
if (inDemoMode) {
callListeners.add(new DemoDecorator());
} else {
callListeners.add(new JavaScriptConfirmation(new ResourceModel("admin.import.restore.confirm")));
callListeners.add(new LoadingSpinnerDecorator());
}
}
};
progressButton.registerMessageModel(Model.of("Start"), InteractionState.STARTABLE);
progressButton.registerMessageModel(Model.of("Running..."), InteractionState.NON_INTERACTIVE);
form.add(progressButton);
form.add(new ProgressBar("bar", progressButton));
return form;
}
private IRunnableFactory getRunnableFactory(final ParseSession session) {
return new IRunnableFactory() {
@Override
public Runnable getRunnable() {
return new IProgressObservableRunnable() {
@Override
public double getProgress() {
return session.getProgress();
}
@Override
public String getProgressMessage() {
return "Restoring";
}
@Override
public void run() {
try {
restoreService.importDatabase(session);
} catch (ImportException e) {
LOGGER.error(e);
throw new IllegalArgumentException(e);
}
}
};
}
};
}
private boolean isValidUpload(FileUploadField field) {
if (field.getFileUpload() != null) {
FileUpload upload = field.getFileUpload();
if (upload.getContentType() == null || !upload.getContentType().toLowerCase().contains("text")) {
error("Invalid content type");
} else if (StringUtils.isBlank(upload.getClientFileName())) {
error("Empty file");
} else if (upload.getBytes() == null || upload.getBytes().length == 0 || upload.getSize() == 0) {
error("Empty file");
}
} else {
error("Empty file");
}
return !hasErrorMessage();
}
@SuppressWarnings("unchecked")
public Boolean ajaxEventReceived(AjaxEvent ajaxEvent) {
boolean continueWithPropagating = true;
if (ajaxEvent.getEventType() == BackupAjaxEventType.VALIDATED) {
PayloadAjaxEvent<ParseSession> event = (PayloadAjaxEvent<ParseSession>) ajaxEvent;
final ParseSession session = event.getPayload();
Component replacement = new AjaxLazyLoadPanel(ID_FEEDBACK) {
@Override
public Component getLazyLoadComponent(String markupId) {
AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
target.appendJavaScript("showHideSpinner(false);");
return new RestoreDbPanel(markupId, session);
}
@Override
public Component getLoadingComponent(String markupId) {
AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
target.appendJavaScript("showHideSpinner(true);");
return new Label(markupId, new ResourceModel("admin.import.label.restoring"));
}
};
AjaxRequestTarget target = event.getTarget();
replaceStatusPanel(replacement, target);
continueWithPropagating = false;
}
return continueWithPropagating;
}
private void replaceStatusPanel(Component replacement, AjaxRequestTarget target) {
replacement.setOutputMarkupId(true);
form.addOrReplace(replacement);
target.add(replacement);
}
}