org.dcm4chee.wizard.panel.BasicConfigurationPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.dcm4chee.wizard.panel.BasicConfigurationPanel.java

Source

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in
 * Java(TM), hosted at http://sourceforge.net/projects/dcm4che.
 *
 * The Initial Developer of the Original Code is
 * Agfa-Gevaert AG.
 * Portions created by the Initial Developer are Copyright (C) 2008
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * See listed authors below.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

package org.dcm4chee.wizard.panel;

import org.apache.catalina.connector.ClientAbortException;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.PageCreator;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.WindowClosedCallback;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.tree.TableTree;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.IRequestCycle;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.http.WebResponse;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.util.time.Duration;
import org.dcm4che3.conf.api.ConfigurationException;
import org.dcm4che3.conf.api.DicomConfiguration;
import org.dcm4che3.conf.prefs.PreferencesDicomConfiguration;
import org.dcm4che3.net.ApplicationEntity;
import org.dcm4che3.net.Connection;
import org.dcm4che3.net.Device;
import org.dcm4che3.net.DeviceExtension;
import org.dcm4che3.net.TransferCapability;
import org.dcm4che3.net.audit.AuditLogger;
import org.dcm4che3.net.hl7.HL7Application;
import org.dcm4che3.net.hl7.HL7DeviceExtension;
import org.dcm4chee.proxy.conf.ProxyAEExtension;
import org.dcm4chee.storage.conf.StorageConfiguration;
import org.dcm4chee.wizard.WizardApplication;
import org.dcm4chee.wizard.common.behavior.TooltipBehavior;
import org.dcm4chee.wizard.common.component.ExtendedForm;
import org.dcm4chee.wizard.common.component.ModalWindowRuntimeException;
import org.dcm4chee.wizard.common.component.secure.ConfirmationWindow;
import org.dcm4chee.wizard.common.component.secure.MessageWindow;
import org.dcm4chee.wizard.edit.*;
import org.dcm4chee.wizard.edit.proxy.CreateOrEditForwardOptionPage;
import org.dcm4chee.wizard.edit.proxy.CreateOrEditForwardRulePage;
import org.dcm4chee.wizard.edit.proxy.CreateOrEditRetryPage;
import org.dcm4chee.wizard.edit.xds.*;
import org.dcm4chee.wizard.icons.ImageManager;
import org.dcm4chee.wizard.icons.behaviour.ImageSizeBehaviour;
import org.dcm4chee.wizard.model.*;
import org.dcm4chee.wizard.model.hl7.HL7ApplicationModel;
import org.dcm4chee.wizard.model.proxy.ForwardOptionModel;
import org.dcm4chee.wizard.model.proxy.ForwardRuleModel;
import org.dcm4chee.wizard.model.proxy.RetryModel;
import org.dcm4chee.wizard.model.xds.*;
import org.dcm4chee.wizard.page.ApplyTransferCapabilityProfilePage;
import org.dcm4chee.wizard.page.AutoDetectTransferCapabilities;
import org.dcm4chee.wizard.page.DicomEchoPage;
import org.dcm4chee.wizard.tree.ConfigTableTree;
import org.dcm4chee.wizard.tree.ConfigTreeNode;
import org.dcm4chee.wizard.tree.ConfigTreeNode.TreeNodeType;
import org.dcm4chee.wizard.tree.ConfigTreeProvider;
import org.dcm4chee.wizard.tree.ConfigTreeProvider.ConfigurationType;
import org.dcm4chee.wizard.tree.CustomTreeColumn;
import org.dcm4chee.xds2.common.deactivatable.Deactivateable;
import org.dcm4chee.xds2.conf.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipOutputStream;

/**
 * @author Robert David <robert.david@agfa.com>
 * @author Michael Backhaus <michael.backhaus@agfa.com>
 */
public class BasicConfigurationPanel extends DicomConfigurationPanel {

    private static final long serialVersionUID = 1L;

    private static final String MODULE_NAME = "dicom";

    private static Logger log = LoggerFactory.getLogger(BasicConfigurationPanel.class);

    private ExtendedForm form;

    private ModalWindow editWindow;
    private ModalWindow echoWindow;
    private ConfirmationWindow<ConfigTreeNode> removeConfirmation;
    private MessageWindow refreshMessage;
    private MessageWindow reloadMessage;
    public WindowClosedCallback windowClosedCallback;

    List<IColumn<ConfigTreeNode, String>> deviceColumns = new ArrayList<IColumn<ConfigTreeNode, String>>();
    TableTree<ConfigTreeNode, String> configTree;

    public static final Map<TreeNodeType, Class<? extends DeviceExtension>> XDS_EXTENSIONS = new HashMap<>();
    public static final Map<TreeNodeType, String> XDS_REST_PATH = new HashMap<>();

    static {

        XDS_EXTENSIONS.put(TreeNodeType.XDSRegistry, XdsRegistry.class);
        XDS_EXTENSIONS.put(TreeNodeType.XDSRepository, XdsRepository.class);
        XDS_EXTENSIONS.put(TreeNodeType.XCAiInitiatingGateway, XCAiInitiatingGWCfg.class);
        XDS_EXTENSIONS.put(TreeNodeType.XCAiRespondingGateway, XCAiRespondingGWCfg.class);
        XDS_EXTENSIONS.put(TreeNodeType.XCAInitiatingGateway, XCAInitiatingGWCfg.class);
        XDS_EXTENSIONS.put(TreeNodeType.XCARespondingGateway, XCARespondingGWCfg.class);
        XDS_EXTENSIONS.put(TreeNodeType.XDSiSource, XDSiSourceCfg.class);

        XDS_REST_PATH.put(TreeNodeType.XDSRegistry, "xds-reg-rs/ctrl/");
        XDS_REST_PATH.put(TreeNodeType.XDSRepository, "xds-rep-rs/ctrl/");
        XDS_REST_PATH.put(TreeNodeType.XCAiInitiatingGateway, "xcai-rs/ctrl/");
        XDS_REST_PATH.put(TreeNodeType.XCAiRespondingGateway, "xcai-rs/ctrl/");
        XDS_REST_PATH.put(TreeNodeType.XCAInitiatingGateway, "xca-rs/ctrl/");
        XDS_REST_PATH.put(TreeNodeType.XCARespondingGateway, "xca-rs/ctrl/");
        XDS_REST_PATH.put(TreeNodeType.XDSiSource, "imgsrc-rs/ctrl/");

    }

    public BasicConfigurationPanel(final String id) {
        super(id);
        add(new Label("reload-message"));
        createChangeTimer();
        setWindowClosedCallback();
        addEchoWindow();
        addEditWindow();
        addRemoveConfirmation();
        addRefreshMessage();
        addForm();
        addCreateDevice();
        addExport();
        addDeviceColumns();
    }

    private void addDeviceColumns() {
        try {
            deviceColumns.add(new CustomTreeColumn(Model.of("Devices")));
            deviceColumns.add(getConfigurationTypeColumn());
            deviceColumns.add(getProtocolColumn());
            deviceColumns.add(getConnectionsColumn());
            deviceColumns.add(getStatusColumn());
            deviceColumns.add(getSendColumn());
            deviceColumns.add(getEmptyModelColumn());
            if (System.getProperty("org.dcm4chee.wizard.config.aeTitle") != null)
                deviceColumns.add(getEchoColum());
            deviceColumns.add(getEditColumn());
            deviceColumns.add(getProfileColumn());
            deviceColumns.add(getDeleteColumn());
            ConfigTreeProvider initCTP = ConfigTreeProvider.init(BasicConfigurationPanel.this);
            configTree = new ConfigTableTree("configTree", deviceColumns, initCTP, Integer.MAX_VALUE);
            renderTree();
        } catch (ConfigurationException ce) {
            log.error(this.getClass().toString() + ": " + "Error creating tree: " + ce.getMessage());
            if (log.isDebugEnabled())
                ce.printStackTrace();
            throw new RuntimeException(ce);
        }
    }

    private void addExport() {
        final Link<Object> export = getExportLink();
        export.add(new Image("exportImg", ImageManager.IMAGE_WIZARD_EXPORT)
                .add(new ImageSizeBehaviour("vertical-align: middle;")));
        export.add(new TooltipBehavior("dicom."));
        export.add(new Label("exportText", new ResourceModel("dicom.export.text"))
                .add(new AttributeAppender("style", Model.of("vertical-align: middle"), " ")));
        form.add(export);

        if (!(((WizardApplication) getApplication()).getDicomConfigurationManager()
                .getDicomConfiguration() instanceof PreferencesDicomConfiguration))
            export.setVisible(false);
    }

    private Link<Object> getExportLink() {
        return new Link<Object>("export") {
            private static final long serialVersionUID = 1L;

            @Override
            public void onClick() {

                RequestCycle.get().replaceAllRequestHandlers(new IRequestHandler() {

                    @Override
                    public void detach(IRequestCycle requestCycle) {
                    }

                    @Override
                    public void respond(IRequestCycle requestCycle) {

                        OutputStream out = null;
                        try {
                            WebResponse response = (WebResponse) getRequestCycle().getResponse();
                            response.setContentType("application/zip");
                            response.setAttachmentHeader("configuration.zip");
                            ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
                            out = zos;
                            ZipEntry entry = new ZipEntry("configuration.xml");
                            zos.putNextEntry(entry);
                            DicomConfiguration dicomConfiguration = ((WizardApplication) getApplication())
                                    .getDicomConfigurationManager().getDicomConfiguration();
                            ((PreferencesDicomConfiguration) dicomConfiguration).getDicomConfigurationRoot()
                                    .exportSubtree(zos);
                            zos.flush();
                            zos.closeEntry();
                        } catch (ZipException ze) {
                            log.warn("Problem creating zip file: " + ze);
                        } catch (ClientAbortException cae) {
                            log.warn("Client aborted zip file download: " + cae);
                        } catch (Exception e) {
                            log.error("An error occurred while attempting to stream zip file for download: ", e);
                        } finally {
                            try {
                                if (out != null)
                                    out.close();
                            } catch (Exception ignore) {
                            }
                        }
                    }
                });
            }
        };
    }

    private void addCreateDevice() {
        AjaxLink<Object> createDevice = getCreateDeviceLink();
        Component createDeviceImg = new Image("createDeviceImg", ImageManager.IMAGE_WIZARD_DEVICE_ADD);
        createDeviceImg.add(new ImageSizeBehaviour("vertical-align: middle;"));
        createDevice.add(createDeviceImg);
        createDevice.add(new TooltipBehavior("dicom."));
        Component createDeviceText = new Label("createDeviceText", new ResourceModel("dicom.createDevice.text"));
        createDeviceText.add(new AttributeAppender("style", Model.of("vertical-align: middle"), " "));
        createDevice.add(createDeviceText);
        form.add(createDevice);
    }

    private AjaxLink<Object> getCreateDeviceLink() {
        return new AjaxLink<Object>("createDevice") {
            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                editWindow.setTitle("").setPageCreator(new ModalWindow.PageCreator() {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public Page createPage() {
                        return new CreateOrEditDevicePage(editWindow, null);
                    }
                }).show(target);
            }
        };
    }

    private void addForm() {
        add(form = new ExtendedForm("form"));
        form.setResourceIdPrefix("dicom.");
    }

    private void addRefreshMessage() {
        refreshMessage = getRefreshMessageWindow();
        refreshMessage.setInitialHeight(150);
        refreshMessage.setWindowClosedCallback(windowClosedCallback);
        add(refreshMessage);
    }

    private MessageWindow getRefreshMessageWindow() {
        return new MessageWindow("refresh-message", new StringResourceModel("dicom.confirmRefresh", this, null)
                .wrapOnAssignment(BasicConfigurationPanel.this)) {

            private static final long serialVersionUID = 1L;

            @Override
            public void onOk(AjaxRequestTarget target) {
                try {
                    log.warn("Reloading device list from configuration");
                    ((WizardApplication) getApplication()).getDicomConfigurationManager().getDicomConfiguration()
                            .sync();
                    ConfigTreeProvider.get().loadDeviceList();
                    for (Iterator<ConfigTreeNode> i = configTree.getModel().getObject().iterator(); i.hasNext();) {
                        ConfigTreeNode root = i.next().getRoot();
                        for (ConfigTreeNode deviceNode : ConfigTreeProvider.get().getNodeList())
                            if (deviceNode.equals(root)
                                    && (((DeviceModel) deviceNode.getModel()).getDevice() == null))
                                ConfigTreeProvider.get().loadDevice(deviceNode);
                    }
                    renderTree();
                } catch (ConfigurationException ce) {
                    log.error("Error reloading configuration after concurrent modification", ce);
                }
            }
        };
    }

    private void addRemoveConfirmation() {
        removeConfirmation = getNewRemoveConfirmation();
        removeConfirmation.setInitialHeight(200);
        removeConfirmation.setWindowClosedCallback(windowClosedCallback);
        add(removeConfirmation);
    }

    private ConfirmationWindow<ConfigTreeNode> getNewRemoveConfirmation() {
        return new ConfirmationWindow<ConfigTreeNode>("remove-confirmation") {

            private static final long serialVersionUID = 1L;

            @Override
            public void onConfirmation(AjaxRequestTarget target, ConfigTreeNode node) {
                try {
                    if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.DEVICE)) {
                        ConfigTreeProvider.get().removeDevice(node);
                    } else {
                        ConfigTreeNode deviceNode = node.getRoot();
                        Device device = ((DeviceModel) deviceNode.getModel()).getDevice();
                        if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.CONNECTION)) {
                            device.removeConnection(((ConnectionModel) node.getModel()).getConnection());

                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.APPLICATION_ENTITY)) {
                            ApplicationEntity applicationEntity = ((ApplicationEntityModel) node.getModel())
                                    .getApplicationEntity();
                            device.removeApplicationEntity(applicationEntity);
                            ConfigTreeProvider.get().unregisterAETitle(applicationEntity.getAETitle());

                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.HL7_APPLICATION)) {
                            HL7Application hl7Application = ((HL7ApplicationModel) node.getModel())
                                    .getHL7Application();
                            device.getDeviceExtension(HL7DeviceExtension.class)
                                    .removeHL7Application(hl7Application);
                            ConfigTreeProvider.get().unregisterHL7Application(hl7Application.getApplicationName());

                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.AUDIT_LOGGER)) {
                            device.removeDeviceExtension(device.getDeviceExtension(AuditLogger.class));

                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.TRANSFER_CAPABILITY)) {
                            TransferCapability transferCapability = ((TransferCapabilityModel) node.getModel())
                                    .getTransferCapability();
                            ((ApplicationEntityModel) node.getAncestor(3).getModel()).getApplicationEntity()
                                    .removeTransferCapabilityFor(transferCapability.getSopClass(),
                                            transferCapability.getRole());

                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.FORWARD_RULE)) {
                            ((ApplicationEntityModel) node.getAncestor(2).getModel()).getApplicationEntity()
                                    .getAEExtension(ProxyAEExtension.class).getForwardRules()
                                    .remove(((ForwardRuleModel) node.getModel()).getForwardRule());

                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.FORWARD_OPTION)) {
                            ((ApplicationEntityModel) node.getAncestor(2).getModel()).getApplicationEntity()
                                    .getAEExtension(ProxyAEExtension.class).getForwardOptions()
                                    .remove(((ForwardOptionModel) node.getModel()).getDestinationAETitle());

                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.RETRY)) {
                            ((ApplicationEntityModel) node.getAncestor(2).getModel()).getApplicationEntity()
                                    .getAEExtension(ProxyAEExtension.class).getRetries()
                                    .remove(((RetryModel) node.getModel()).getRetry());

                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.COERCION)) {
                            ((ApplicationEntityModel) node.getAncestor(2).getModel()).getApplicationEntity()
                                    .getAEExtension(ProxyAEExtension.class).getAttributeCoercions()
                                    .remove(((CoercionModel) node.getModel()).getCoercion());
                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.XCAiInitiatingGateway)) {
                            device.removeDeviceExtension(device.getDeviceExtension(XCAiInitiatingGWCfg.class));
                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.XCAInitiatingGateway)) {
                            device.removeDeviceExtension(device.getDeviceExtension(XCAInitiatingGWCfg.class));
                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.XCAiRespondingGateway)) {
                            device.removeDeviceExtension(device.getDeviceExtension(XCAiRespondingGWCfg.class));
                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.XCARespondingGateway)) {
                            device.removeDeviceExtension(device.getDeviceExtension(XCARespondingGWCfg.class));
                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.XDSRegistry)) {
                            device.removeDeviceExtension(device.getDeviceExtension(XdsRegistry.class));
                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.XDSSource)) {
                            device.removeDeviceExtension(device.getDeviceExtension(XdsSource.class));
                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.XDSiSource)) {
                            device.removeDeviceExtension(device.getDeviceExtension(XDSiSourceCfg.class));
                        } else if (node.getNodeType().equals(TreeNodeType.XDSStorage)) {
                            device.removeDeviceExtension(device.getDeviceExtension(StorageConfiguration.class));
                        } else if (node.getNodeType().equals(ConfigTreeNode.TreeNodeType.XDSRepository)) {
                            device.removeDeviceExtension(device.getDeviceExtension(XdsRepository.class));
                        } else {
                            log.error("Missing type of ConfigurationTreeNode");
                            return;
                        }
                        ConfigTreeProvider.get().mergeDevice(device);
                    }
                } catch (Exception e) {
                    log.error(this.getClass().toString() + ": " + "Error deleting configuration object: "
                            + e.getMessage());
                    log.debug("Exception", e);
                    throw new ModalWindowRuntimeException(e.getLocalizedMessage());
                }
            }
        };
    }

    private void addEditWindow() {
        editWindow = new ModalWindow("edit-window");
        editWindow.setInitialWidth(700).setInitialHeight(500);
        editWindow.setWindowClosedCallback(windowClosedCallback);
        add(editWindow);
    }

    private void addEchoWindow() {
        echoWindow = new ModalWindow("echo-window");
        echoWindow.setInitialWidth(700).setInitialHeight(500);
        echoWindow.setWindowClosedCallback(windowClosedCallback);
        add(echoWindow);
    }

    private void setWindowClosedCallback() {
        windowClosedCallback = getWindowClosedCallback();
    }

    private WindowClosedCallback getWindowClosedCallback() {
        return new ModalWindow.WindowClosedCallback() {

            private static final long serialVersionUID = 1L;

            public void onClose(AjaxRequestTarget target) {
                try {
                    boolean refresh = false;
                    for (ConfigTreeNode deviceNode : ConfigTreeProvider.get().getNodeList())
                        if (deviceNode.getModel() == null) {
                            ConfigTreeProvider.get().loadDevice(deviceNode);
                            refresh = true;
                        }
                    if (refresh || ConfigTreeProvider.get().resync())
                        renderTree();
                } catch (ConfigurationException ce) {
                    log.error(this.getClass().toString() + ": " + "Error refreshing tree: " + ce.getMessage());
                    log.debug("Exception", ce);
                    throw new RuntimeException(ce);
                }
                target.add(form);
            }
        };
    }

    private void createChangeTimer() {
        try {
            String checkForChangesInterval = ((WebApplication) this.getApplication())
                    .getInitParameter("CheckForChangesInterval");
            if (checkForChangesInterval != null && !checkForChangesInterval.equals(""))
                add(getChangeIntervalTimerBehaviour(checkForChangesInterval));
        } catch (Exception e) {
            log.error("Error creating timer for checking changes", e);
        }
    }

    private AbstractAjaxTimerBehavior getChangeIntervalTimerBehaviour(String checkForChangesInterval) {
        return new AbstractAjaxTimerBehavior(Duration.seconds(Integer.parseInt(checkForChangesInterval))) {
            private static final long serialVersionUID = 1L;

            @Override
            protected void onTimer(AjaxRequestTarget target) {
                if (ConfigTreeProvider.get().getLastModificationTime()
                        .before(getDicomConfigurationManager().getLastModificationTime())) {
                    log.warn("Configuration needs to be reloaded because of concurrent modification");
                    refreshMessage.show(target);
                }
            }
        };
    }

    @Override
    public void renderHead(IHeaderResponse response) {
        response.render(OnDomReadyHeaderItem.forScript("Wicket.Window.unloadConfirmation = false"));
    }

    private AbstractColumn<ConfigTreeNode, String> getDeleteColumn() {
        return new AbstractColumn<ConfigTreeNode, String>(Model.of("Delete")) {

            private static final long serialVersionUID = 1L;

            public void populateItem(Item<ICellPopulator<ConfigTreeNode>> cellItem, String componentId,
                    final IModel<ConfigTreeNode> rowModel) {

                final TreeNodeType type = rowModel.getObject().getNodeType();
                if (type == null)
                    throw new RuntimeException("Error: Unknown node type, cannot create delete modal window");

                else if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_CONNECTIONS)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_APPLICATION_ENTITIES)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_HL7_APPLICATIONS)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_AUDIT_LOGGERS)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_TRANSFER_CAPABILITIES)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_TRANSFER_CAPABILITY_TYPE)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_FORWARD_RULES)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_FORWARD_OPTIONS)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_RETRIES)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_COERCIONS)
                        || type.equals(ConfigTreeNode.TreeNodeType.XCAiInitiatingGateway)
                        || type.equals(ConfigTreeNode.TreeNodeType.XCAInitiatingGateway)
                        || type.equals(ConfigTreeNode.TreeNodeType.XCAiRespondingGateway)
                        || type.equals(ConfigTreeNode.TreeNodeType.XCARespondingGateway)
                        || type.equals(ConfigTreeNode.TreeNodeType.XDSRegistry)
                        || type.equals(ConfigTreeNode.TreeNodeType.XDSSource)
                        || type.equals(ConfigTreeNode.TreeNodeType.XDSiSource)
                        || type.equals(TreeNodeType.XDSStorage)
                        || type.equals(ConfigTreeNode.TreeNodeType.XDSRepository)) {
                    cellItem.add(new Label(componentId));
                    return;
                }

                AjaxLink<Object> ajaxLink = getConfirmDeleteLink(rowModel);
                cellItem.add(new LinkPanel(componentId, ajaxLink, ImageManager.IMAGE_WIZARD_COMMON_REMOVE,
                        removeConfirmation))
                        .add(new AttributeAppender("style", Model.of("width: 50px; text-align: center;")));
                if (type.equals(ConfigTreeNode.TreeNodeType.CONNECTION)) {
                    Connection connection = null;
                    try {
                        connection = ((ConnectionModel) rowModel.getObject().getModel()).getConnection();
                        for (ApplicationEntity ae : connection.getDevice().getApplicationEntities())
                            if (ae.getConnections().contains(connection))
                                ajaxLink.setEnabled(false).add(new AttributeModifier("title",
                                        new ResourceModel("dicom.delete.connection.notAllowed")));

                        HL7DeviceExtension hl7DeviceExtension = connection.getDevice()
                                .getDeviceExtension(HL7DeviceExtension.class);
                        if (hl7DeviceExtension != null) {
                            for (HL7Application hl7Application : hl7DeviceExtension.getHL7Applications())
                                if (hl7Application.getConnections().contains(connection))
                                    ajaxLink.setEnabled(false).add(new AttributeModifier("title",
                                            new ResourceModel("dicom.delete.connection.notAllowed")));
                        }

                        AuditLogger auditLogger = connection.getDevice().getDeviceExtension(AuditLogger.class);
                        if (auditLogger != null && auditLogger.getConnections().contains(connection))
                            ajaxLink.setEnabled(false).add(new AttributeModifier("title",
                                    new ResourceModel("dicom.delete.connection.notAllowed")));

                    } catch (ConfigurationException ce) {
                        log.error(this.getClass().toString() + ": "
                                + "Error checking used connections of application entities: " + ce.getMessage());
                        log.debug("Exception", ce);
                        throw new RuntimeException(ce);
                    }
                }
            }
        };
    }

    private AbstractColumn<ConfigTreeNode, String> getProfileColumn() {
        return new AbstractColumn<ConfigTreeNode, String>(Model.of("Profile")) {

            private static final long serialVersionUID = 1L;

            public void populateItem(Item<ICellPopulator<ConfigTreeNode>> cellItem, String componentId,
                    final IModel<ConfigTreeNode> rowModel) {

                final TreeNodeType type = rowModel.getObject().getNodeType();
                if (type == null)
                    throw new RuntimeException("Error: Unknown node type, cannot create profile modal window");

                if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_TRANSFER_CAPABILITIES)) {

                    AjaxLink<Object> ajaxLink = new AjaxLink<Object>("wickettree.link") {

                        private static final long serialVersionUID = 1L;

                        @Override
                        public void onClick(AjaxRequestTarget target) {
                            editWindow.setTitle("Device "
                                    + ((DeviceModel) rowModel.getObject().getRoot().getModel()).getDeviceName())
                                    .setPageCreator(new ModalWindow.PageCreator() {

                                        private static final long serialVersionUID = 1L;

                                        @Override
                                        public Page createPage() {
                                            return new ApplyTransferCapabilityProfilePage(editWindow, null,
                                                    rowModel.getObject().getParent());
                                        }
                                    });
                            editWindow.setWindowClosedCallback(windowClosedCallback).show(target);
                        }
                    };
                    cellItem.add(new LinkPanel(componentId, ajaxLink, ImageManager.IMAGE_WIZARD_COMMON_PROFILE,
                            removeConfirmation))
                            .add(new AttributeAppender("style", Model.of("width: 50px; text-align: center;")));
                } else
                //
                // for proxy devices, that are under our control - add button to open dialog for launching auto-detection of transfer capabilities
                //
                if ( // if it is AE level
                type.equals(ConfigTreeNode.TreeNodeType.APPLICATION_ENTITY) &&

                // if it is a Proxy device
                rowModel.getObject().getConfigurationType().equals(ConfigTreeProvider.ConfigurationType.Proxy) &&

                // if this device is 'connected'
                getDicomConfigurationManager().getConnectedDeviceUrls()
                        .get(rowModel.getObject().getRoot().getName()) != null) {

                    final String deviceName = rowModel.getObject().getRoot().getName();

                    AjaxLink<Object> ajaxLink = new AjaxLink<Object>("wickettree.link") {

                        private static final long serialVersionUID = 1L;

                        @Override
                        public void onClick(AjaxRequestTarget target) {
                            editWindow.setTitle(
                                    "Auto detect transfer capabilities for all related devices of " + deviceName)
                                    .setPageCreator(new ModalWindow.PageCreator() {

                                        private static final long serialVersionUID = 1L;

                                        @Override
                                        public Page createPage() {

                                            IModel<ConfigTreeNode> arowModel = rowModel;
                                            final String connectedDeviceUrl = getDicomConfigurationManager()
                                                    .getConnectedDeviceUrls().get(deviceName);

                                            ApplicationEntity ae = null;
                                            try {
                                                ae = ((ApplicationEntityModel) rowModel.getObject().getModel())
                                                        .getApplicationEntity();
                                            } catch (ConfigurationException e) {
                                                throw new RuntimeException("Cannot get the AE", e);
                                            }

                                            return new AutoDetectTransferCapabilities(editWindow,
                                                    connectedDeviceUrl, ae.getAETitle(), deviceName);
                                        }
                                    });
                            editWindow.setWindowClosedCallback(windowClosedCallback).show(target);
                        }
                    };
                    cellItem.add(new LinkPanel(componentId, ajaxLink,
                            ImageManager.IMAGE_WIZARD_FOLDER_TRANSFER_CAPABILITY_TYPE, removeConfirmation))
                            .add(new AttributeAppender("style", Model.of("width: 50px; text-align: center;")));

                } else {
                    cellItem.add(new Label(componentId));
                    return;
                }

            }
        };
    }

    private AbstractColumn<ConfigTreeNode, String> getEditColumn() {
        return new AbstractColumn<ConfigTreeNode, String>(Model.of("Edit")) {

            private static final long serialVersionUID = 1L;

            public void populateItem(final Item<ICellPopulator<ConfigTreeNode>> cellItem, final String componentId,
                    final IModel<ConfigTreeNode> rowModel) {

                final TreeNodeType type = rowModel.getObject().getNodeType();
                if (type == null)
                    throw new RuntimeException("Error: Unknown node type, cannot create edit modal window");

                AjaxLink<Object> ajaxLink = new AjaxLink<Object>("wickettree.link") {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onClick(AjaxRequestTarget target) {
                        editWindow.setTitle("Device "
                                + ((DeviceModel) rowModel.getObject().getRoot().getModel()).getDeviceName());
                        setEditWindowPageCreator(rowModel, type);
                        editWindow.setWindowClosedCallback(windowClosedCallback).show(target);
                    }
                };

                ajaxLink.setVisible((!type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_APPLICATION_ENTITIES)
                        && !type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_HL7_APPLICATIONS)
                        && !type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_AUDIT_LOGGERS))
                        || rowModel.getObject().getParent().getChildren().get(0).hasChildren());

                try {
                    if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_FORWARD_OPTIONS))
                        ajaxLink.setVisible(ConfigTreeProvider.get().getUniqueAETitles().length > 0);
                } catch (ConfigurationException ce) {
                    log.error("Error listing Registered AE Titles", ce);
                    if (log.isDebugEnabled())
                        ce.printStackTrace();
                }

                try {
                    if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_AUDIT_LOGGERS)
                            && ((DeviceModel) rowModel.getObject().getParent().getModel()).getDevice()
                                    .getDeviceExtension(AuditLogger.class) != null)
                        ajaxLink.setVisible(false);
                } catch (ConfigurationException ce) {
                    log.error("Error accessing Audit Logger", ce);
                }

                ResourceReference image;
                if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_CONNECTIONS)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_APPLICATION_ENTITIES)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_HL7_APPLICATIONS)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_AUDIT_LOGGERS)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_TRANSFER_CAPABILITIES)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_FORWARD_RULES)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_FORWARD_OPTIONS)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_RETRIES)
                        || type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_COERCIONS))
                    image = ImageManager.IMAGE_WIZARD_COMMON_ADD;
                else
                    image = ImageManager.IMAGE_WIZARD_COMMON_EDIT;

                if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_TRANSFER_CAPABILITY_TYPE))
                    cellItem.add(new Label(componentId));
                else
                    cellItem.add(new LinkPanel(componentId, ajaxLink, image, removeConfirmation))
                            .add(new AttributeAppender("style", Model.of("width: 50px; text-align: center;")));
            }
        };
    }

    private AbstractColumn<ConfigTreeNode, String> getEchoColum() {
        return new AbstractColumn<ConfigTreeNode, String>(Model.of("Echo")) {

            private static final long serialVersionUID = 1L;

            public void populateItem(final Item<ICellPopulator<ConfigTreeNode>> cellItem, final String componentId,
                    final IModel<ConfigTreeNode> rowModel) {
                final TreeNodeType type = rowModel.getObject().getNodeType();
                if (type == null)
                    throw new RuntimeException("Error: Unknown node type, cannot create edit modal window");

                AjaxLink<Object> ajaxLink = new AjaxLink<Object>("wickettree.link") {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onClick(AjaxRequestTarget target) {

                        if (type.equals(ConfigTreeNode.TreeNodeType.APPLICATION_ENTITY)) {
                            echoWindow.setPageCreator(new ModalWindow.PageCreator() {

                                private static final long serialVersionUID = 1L;

                                @Override
                                public Page createPage() {
                                    try {
                                        return new DicomEchoPage(echoWindow,
                                                ((ApplicationEntityModel) rowModel.getObject().getModel())
                                                        .getApplicationEntity());
                                    } catch (Exception e) {
                                        log.error(this.getClass().toString() + ": "
                                                + "Error creating DicomEchoPage: " + e.getMessage());
                                        log.debug("Exception", e);
                                        throw new RuntimeException(e);
                                    }
                                }
                            });
                        }
                        echoWindow.setWindowClosedCallback(windowClosedCallback).show(target);
                    }
                };
                if (type.equals(ConfigTreeNode.TreeNodeType.APPLICATION_ENTITY))
                    cellItem.add(new LinkPanel(componentId, ajaxLink, ImageManager.IMAGE_WIZARD_ECHO,
                            removeConfirmation))
                            .add(new AttributeAppender("style", Model.of("width: 50px; text-align: center;")));
                else
                    cellItem.add(new Label(componentId));
            }
        };
    }

    private AbstractColumn<ConfigTreeNode, String> getEmptyModelColumn() {
        return new AbstractColumn<ConfigTreeNode, String>(Model.of("")) {

            private static final long serialVersionUID = 1L;

            public void populateItem(final Item<ICellPopulator<ConfigTreeNode>> cellItem, final String componentId,
                    final IModel<ConfigTreeNode> rowModel) {

                final TreeNodeType type = rowModel.getObject().getNodeType();
                if (type == null)
                    throw new RuntimeException("Error: Unknown node type, cannot create edit modal window");

                if (!type.equals(ConfigTreeNode.TreeNodeType.DEVICE)
                        || !getDicomConfigurationManager().getConnectedDeviceUrls()
                                .containsKey(rowModel.getObject().getName())
                        || !((WizardApplication) getApplication()).getDicomConfigurationManager()
                                .isReload(rowModel.getObject().getName())) {
                    cellItem.add(new Label(componentId));
                    return;
                }

                AjaxLink<Object> reloadWarningLink = new AjaxLink<Object>("wickettree.link") {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onClick(AjaxRequestTarget arg0) {
                    }
                };

                reloadWarningLink
                        .setVisible(((WizardApplication) getApplication()).getDicomConfigurationManager()
                                .isReload(rowModel.getObject().getName()))
                        .setEnabled(false)
                        .add(new AttributeAppender("title", new ResourceModel("dicom.reload.warning.tooltip")));

                cellItem.add(new LinkPanel(componentId, reloadWarningLink, ImageManager.IMAGE_WIZARD_RELOAD_WARNING,
                        null)).add(new AttributeAppender("style", Model.of("width: 50px; text-align: center;")));
            }
        };
    }

    private AbstractColumn<ConfigTreeNode, String> getSendColumn() {
        return new AbstractColumn<ConfigTreeNode, String>(Model.of("Send")) {

            private static final long serialVersionUID = 1L;

            public void populateItem(final Item<ICellPopulator<ConfigTreeNode>> cellItem, final String componentId,
                    final IModel<ConfigTreeNode> rowModel) {

                final TreeNodeType type = rowModel.getObject().getNodeType();
                if (type == null)
                    throw new RuntimeException("Error: Unknown node type, cannot create edit modal window");

                String connectedDeviceUrl = null;
                String restOperation = "restart";
                String deviceName = "";

                if (type.equals(TreeNodeType.DEVICE)
                        && !rowModel.getObject().getConfigurationType().equals(ConfigurationType.XDS)) {
                    deviceName = rowModel.getObject().getName();
                    connectedDeviceUrl = getDicomConfigurationManager().getConnectedDeviceUrls().get(deviceName);
                } else if (XDS_EXTENSIONS.containsKey(type)) {
                    deviceName = rowModel.getObject().getRoot().getName();
                    connectedDeviceUrl = getDicomConfigurationManager().getConnectedDeviceUrls().get(deviceName);
                    restOperation = "reload";
                    if (connectedDeviceUrl != null)
                        connectedDeviceUrl += XDS_REST_PATH.get(type);
                }

                if (connectedDeviceUrl != null) {
                    IndicatingAjaxLink<Object> ajaxLink = new ReloadAjaxLink(connectedDeviceUrl, restOperation,
                            deviceName);
                    String styleAttr = "width: 50px; text-align: center;";
                    if (getDicomConfigurationManager().isReload(deviceName, connectedDeviceUrl))
                        styleAttr += " background-color: red;";
                    cellItem.add(
                            new LinkPanel(componentId, ajaxLink, ImageManager.IMAGE_WIZARD_RELOAD, reloadMessage))
                            .add(new AttributeAppender("style", Model.of(styleAttr)));
                    return;
                }

                // in case there is nothing to show
                cellItem.add(new Label(componentId));
            }
        };
    }

    private AbstractColumn<ConfigTreeNode, String> getStatusColumn() {
        return new AbstractColumn<ConfigTreeNode, String>(Model.of("Status")) {

            private static final long serialVersionUID = 1L;

            public void populateItem(final Item<ICellPopulator<ConfigTreeNode>> cellItem, final String componentId,
                    final IModel<ConfigTreeNode> rowModel) {

                final TreeNodeType type = rowModel.getObject().getNodeType();
                if (type == null)
                    throw new RuntimeException("Error: Unknown node type, cannot create edit modal window");

                String connectedDeviceUrl = null;
                DeviceExtension devExt = null;
                // for device-level status indicator
                if (type.equals(TreeNodeType.DEVICE)
                        && !rowModel.getObject().getConfigurationType().equals(ConfigurationType.XDS)) {

                    connectedDeviceUrl = getDicomConfigurationManager().getConnectedDeviceUrls()
                            .get(rowModel.getObject().getName());
                    // for extension-level status indicator
                } else if (XDS_EXTENSIONS.containsKey(type)) {

                    String deviceName = rowModel.getObject().getRoot().getName();
                    connectedDeviceUrl = getDicomConfigurationManager().getConnectedDeviceUrls().get(deviceName);
                    if (connectedDeviceUrl != null) {
                        connectedDeviceUrl += XDS_REST_PATH.get(type);

                        try {
                            devExt = ((WizardApplication) getApplication()).getDicomConfigurationManager()
                                    .getDicomConfiguration().findDevice(deviceName)
                                    .getDeviceExtension(XDS_EXTENSIONS.get(type));
                        } catch (ConfigurationException e) {
                            log.warn("Could not get a device extension", e);
                        }

                    }
                }

                if (connectedDeviceUrl != null) {

                    StatusAjaxLink ajaxLink = new StatusAjaxLink(connectedDeviceUrl, devExt);
                    StatusAjaxLink.StatusResponse statusResponse = ajaxLink.getStatusResponse()
                            .invoke(BasicConfigurationPanel.this);

                    cellItem.add(new LinkPanel(componentId, ajaxLink, statusResponse.getImage(), null)
                            .setImage(null, statusResponse.getResultMessage()).setOutputMarkupId(true))
                            .add(new AttributeAppender("style", Model.of("width: 50px; text-align: center;")));

                    return;
                }

                cellItem.add(new Label(componentId));
            }
        };
    }

    private AbstractColumn<ConfigTreeNode, String> getConnectionsColumn() {
        return new AbstractColumn<ConfigTreeNode, String>(Model.of("Connections")) {

            private static final long serialVersionUID = 1L;

            public void populateItem(Item<ICellPopulator<ConfigTreeNode>> cellItem, String componentId,
                    IModel<ConfigTreeNode> rowModel) {
                ConfigTreeNode configTreeNode = (ConfigTreeNode) rowModel.getObject();
                RepeatingView connectionsView = new RepeatingView(componentId);
                cellItem.add(connectionsView);
                try {
                    if (configTreeNode.getNodeType().equals(ConfigTreeNode.TreeNodeType.APPLICATION_ENTITY)) {
                        ApplicationEntity applicationEntity = ((ApplicationEntityModel) configTreeNode.getModel())
                                .getApplicationEntity();
                        if (applicationEntity != null)
                            for (Connection connection : applicationEntity.getConnections())
                                connectionsView.add(new ConnectionPanel(connectionsView.newChildId(),
                                        ImageManager.IMAGE_WIZARD_CONNECTION,
                                        Model.of(connection.getCommonName() == null
                                                ? connection.getHostname() + ":" + connection.getPort()
                                                : connection.getCommonName()),
                                        Model.of(connection.toString())));
                    }
                } catch (ConfigurationException ce) {
                    log.error(this.getClass().toString() + ": "
                            + "Error listing connections for application entity: " + ce.getMessage());
                    log.debug("Exception", ce);
                    throw new RuntimeException(ce);
                }
            }
        };
    }

    private AbstractColumn<ConfigTreeNode, String> getProtocolColumn() {
        return new AbstractColumn<ConfigTreeNode, String>(Model.of("Protocol")) {

            private static final long serialVersionUID = 1L;

            public void populateItem(final Item<ICellPopulator<ConfigTreeNode>> cellItem, final String componentId,
                    final IModel<ConfigTreeNode> rowModel) {

                ConfigTreeNode configTreeNode = (ConfigTreeNode) rowModel.getObject();
                String protocol = "";
                if (configTreeNode.getNodeType().equals(ConfigTreeNode.TreeNodeType.CONNECTION))
                    try {
                        protocol = ((ConnectionModel) configTreeNode.getModel()).getConnection().getProtocol()
                                .toString();
                    } catch (ConfigurationException ce) {
                        log.error(this.getClass().toString() + ": " + "Error fetching protocol for connection: "
                                + ce.getMessage());
                        log.debug("Exception", ce);
                    }
                cellItem.add(new Label(componentId, Model.of(protocol)));
            }
        };
    }

    private AbstractColumn<ConfigTreeNode, String> getConfigurationTypeColumn() {
        return new AbstractColumn<ConfigTreeNode, String>(Model.of("ConfigurationType")) {

            private static final long serialVersionUID = 1L;

            public void populateItem(final Item<ICellPopulator<ConfigTreeNode>> cellItem, final String componentId,
                    final IModel<ConfigTreeNode> rowModel) {

                final ConfigurationType configurationType = rowModel.getObject().getConfigurationType();
                cellItem.add(new Label(componentId,
                        Model.of(configurationType == null ? "" : configurationType.toString())));
            }
        };
    }

    public void renderTree() throws ConfigurationException {
        IModel<Set<ConfigTreeNode>> currentState = configTree.getModel();
        configTree = new ConfigTableTree("configTree", deviceColumns, ConfigTreeProvider.get(), Integer.MAX_VALUE);
        configTree.setModel(currentState);
        form.addOrReplace(configTree);
    }

    private boolean getStatus(String statusServiceEndpoint) throws IOException, Exception {

        HttpURLConnection connection = (HttpURLConnection) new URL(
                statusServiceEndpoint + (statusServiceEndpoint.endsWith("/") ? "running" : "/running"))
                        .openConnection();
        connection.setRequestMethod("GET");

        if (connection.getResponseCode() != 200)
            throw new Exception("Expected response 200, but was " + connection.getResponseCode() + "."
                    + connection.getResponseMessage());
        else {
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String nextLine = reader.readLine();
            reader.close();
            return Boolean.parseBoolean(nextLine);
        }
    }

    public static String getModuleName() {
        return MODULE_NAME;
    }

    private PageCreator getModalWindowPageCreator(final IModel<ConfigTreeNode> rowModel, final TreeNodeType type) {
        return new ModalWindow.PageCreator() {

            private static final long serialVersionUID = 1L;

            @Override
            public Page createPage() {
                if (type.equals(ConfigTreeNode.TreeNodeType.DEVICE)) {
                    try {
                        ConfigTreeProvider.get().loadDevice(rowModel.getObject());
                        return new CreateOrEditDevicePage(editWindow,
                                (DeviceModel) rowModel.getObject().getModel());
                    } catch (Exception e) {
                        log.error("Error loading device on edit", e);
                        return null;
                    }
                } else if (type.equals(ConfigTreeNode.TreeNodeType.CONNECTION)) {
                    return new CreateOrEditConnectionPage(editWindow,
                            (ConnectionModel) rowModel.getObject().getModel(), rowModel.getObject().getAncestor(2));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.APPLICATION_ENTITY)) {
                    return new CreateOrEditApplicationEntityPage(editWindow,
                            (ApplicationEntityModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(2));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.HL7_APPLICATION)) {
                    return new CreateOrEditHL7ApplicationPage(editWindow,
                            (HL7ApplicationModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(2));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.AUDIT_LOGGER)) {
                    return new CreateOrEditAuditLoggerPage(editWindow,
                            (AuditLoggerModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(2));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.TRANSFER_CAPABILITY)) {
                    return new CreateOrEditTransferCapabilityPage(editWindow,
                            (TransferCapabilityModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(3));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.FORWARD_RULE)) {
                    return new CreateOrEditForwardRulePage(editWindow,
                            (ForwardRuleModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(2));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.FORWARD_OPTION)) {
                    return new CreateOrEditForwardOptionPage(editWindow,
                            (ForwardOptionModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(2));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.RETRY)) {
                    return new CreateOrEditRetryPage(editWindow, (RetryModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(2));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.COERCION)) {
                    return new CreateOrEditCoercionPage(editWindow, (CoercionModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(2));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.XCAiInitiatingGateway)) {
                    return new XCAiInitiatingGatewayEditPage(editWindow,
                            (XCAiInitiatingGatewayModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(1));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.XCAInitiatingGateway)) {
                    return new XCAInitiatingGatewayEditPage(editWindow,
                            (XCAInitiatingGatewayModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(1));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.XCAiRespondingGateway)) {
                    return new XCAiRespondingGatewayEditPage(editWindow,
                            (XCAiRespondingGatewayModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(1));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.XCARespondingGateway)) {
                    return new XCARespondingGatewayEditPage(editWindow,
                            (XCARespondingGatewayModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(1));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.XDSRegistry)) {
                    return new XDSRegistryEditPage(editWindow, (XDSRegistryModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(1));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.XDSRepository)) {
                    return new XDSRepositoryEditPage(editWindow,
                            (XDSRepositoryModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(1));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.XDSSource)) {
                    return new XDSSourceEditPage(editWindow, (XDSSourceModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(1));
                } else if (type.equals(ConfigTreeNode.TreeNodeType.XDSiSource)) {
                    return new XDSiSourceEditPage(editWindow, (XDSiSourceModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(1));
                } else if (type.equals(TreeNodeType.XDSStorage)) {
                    return new XDSStorageEditPage(editWindow, (XdsStorageModel) rowModel.getObject().getModel(),
                            rowModel.getObject().getAncestor(1));
                } else
                    return null;
            }
        };
    }

    private void setEditWindowPageCreator(final IModel<ConfigTreeNode> rowModel, final TreeNodeType type) {
        if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_CONNECTIONS)) {
            editWindow.setPageCreator(new ModalWindow.PageCreator() {

                private static final long serialVersionUID = 1L;

                @Override
                public Page createPage() {
                    return new CreateOrEditConnectionPage(editWindow, null, rowModel.getObject().getParent());
                }
            });
        } else if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_APPLICATION_ENTITIES)) {
            editWindow.setPageCreator(new ModalWindow.PageCreator() {

                private static final long serialVersionUID = 1L;

                @Override
                public Page createPage() {
                    return new CreateOrEditApplicationEntityPage(editWindow, null,
                            rowModel.getObject().getParent());
                }
            });
        } else if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_HL7_APPLICATIONS)) {
            editWindow.setPageCreator(new ModalWindow.PageCreator() {

                private static final long serialVersionUID = 1L;

                @Override
                public Page createPage() {
                    return new CreateOrEditHL7ApplicationPage(editWindow, null, rowModel.getObject().getParent());
                }
            });
        } else if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_AUDIT_LOGGERS)) {
            editWindow.setPageCreator(new ModalWindow.PageCreator() {

                private static final long serialVersionUID = 1L;

                @Override
                public Page createPage() {
                    return new CreateOrEditAuditLoggerPage(editWindow, null, rowModel.getObject().getParent());
                }
            });
        } else if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_TRANSFER_CAPABILITIES)) {
            editWindow.setPageCreator(new ModalWindow.PageCreator() {

                private static final long serialVersionUID = 1L;

                @Override
                public Page createPage() {
                    return new CreateOrEditTransferCapabilityPage(editWindow, null,
                            rowModel.getObject().getParent());
                }
            });
        } else if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_FORWARD_RULES)) {
            editWindow.setPageCreator(new ModalWindow.PageCreator() {

                private static final long serialVersionUID = 1L;

                @Override
                public Page createPage() {
                    return new CreateOrEditForwardRulePage(editWindow, null, rowModel.getObject().getParent());
                }
            });
        } else if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_FORWARD_OPTIONS)) {
            editWindow.setPageCreator(new ModalWindow.PageCreator() {

                private static final long serialVersionUID = 1L;

                @Override
                public Page createPage() {
                    return new CreateOrEditForwardOptionPage(editWindow, null, rowModel.getObject().getParent());
                }
            });
        } else if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_RETRIES)) {
            editWindow.setPageCreator(new ModalWindow.PageCreator() {

                private static final long serialVersionUID = 1L;

                @Override
                public Page createPage() {
                    return new CreateOrEditRetryPage(editWindow, null, rowModel.getObject().getParent());
                }
            });
        } else if (type.equals(ConfigTreeNode.TreeNodeType.CONTAINER_COERCIONS)) {
            editWindow.setPageCreator(new ModalWindow.PageCreator() {

                private static final long serialVersionUID = 1L;

                @Override
                public Page createPage() {
                    return new CreateOrEditCoercionPage(editWindow, null, rowModel.getObject().getParent());
                }
            });
        } else {
            editWindow.setPageCreator(getModalWindowPageCreator(rowModel, type));
        }
    }

    private AjaxLink<Object> getConfirmDeleteLink(final IModel<ConfigTreeNode> rowModel) {
        return new AjaxLink<Object>("wickettree.link") {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                removeConfirmation.confirm(target, new StringResourceModel("dicom.confirmDelete", this, null,
                        new Object[] { rowModel.getObject().getNodeType(), rowModel.getObject().getName() }),
                        rowModel.getObject());
            }
        };
    }

    public class StatusAjaxLink extends IndicatingAjaxLink<Object> {

        private static final long serialVersionUID = 1L;
        private final String connectedDeviceUrl;
        private DeviceExtension devExt;

        public StatusAjaxLink(String connectedDeviceUrl, DeviceExtension devExt) {
            super("wickettree.link");
            this.connectedDeviceUrl = connectedDeviceUrl;
            this.devExt = devExt;
        }

        public StatusResponse getStatusResponse() {
            return new StatusResponse();
        }

        @Override
        public void onClick(AjaxRequestTarget target) {

            if (connectedDeviceUrl == null) {
                log.warn("Service endpoint for status is not configured correctly");
                return;
            } else
                log.info("Attempting to retrieve status using service endpoint " + connectedDeviceUrl);

            StatusResponse statusResponse = new StatusResponse().invoke(StatusAjaxLink.this);
            ResourceReference image = statusResponse.getImage();
            StringResourceModel resultMessage = statusResponse.getResultMessage();
            ((LinkPanel) this.getParent()).setImage(image, resultMessage);
            target.add(getParent());
        }

        public class StatusResponse {
            private StringResourceModel resultMessage;
            private ResourceReference image;

            public StringResourceModel getResultMessage() {
                return resultMessage;
            }

            public ResourceReference getImage() {
                return image;
            }

            public StatusResponse invoke(Component component) {
                try {
                    boolean result = getStatus(connectedDeviceUrl);

                    // if extension is deactivated
                    if (devExt != null) {
                        if (((Deactivateable) devExt).isDeactivated()) {
                            image = ImageManager.IMAGE_WIZARD_RUNNING_DEACTIVATED;
                            resultMessage = new StringResourceModel("dicom.status.message.failed", component, null,
                                    new Object[] { "Extension is running but deactivated" });
                            return this;
                        }
                    }

                    resultMessage = new StringResourceModel(
                            result ? "dicom.status.message.success" : "dicom.status.message.warning", component,
                            null);
                    image = result ? ImageManager.IMAGE_WIZARD_RUNNING : ImageManager.IMAGE_WIZARD_NOT_RUNNING;

                } catch (Exception e) {
                    log.error("Error retrieving status of connected device (@ {}): {}", connectedDeviceUrl,
                            e.getMessage());
                    if (log.isDebugEnabled())
                        e.printStackTrace();
                    resultMessage = new StringResourceModel("dicom.status.message.failed", component, null,
                            new Object[] { e.getMessage() });
                    image = ImageManager.IMAGE_WIZARD_NOT_RUNNING;
                }
                return this;
            }
        }
    }

    private class ReloadAjaxLink extends IndicatingAjaxLink<Object> {

        private static final long serialVersionUID = 1L;
        private final String connectedDeviceUrl;
        private final String restOperation;
        private final String deviceName;

        public ReloadAjaxLink(String connectedDeviceUrl, String restOperation, String deviceName) {
            super("wickettree.link");
            this.connectedDeviceUrl = connectedDeviceUrl;
            this.restOperation = restOperation;
            this.deviceName = deviceName;
        }

        @Override
        public void onClick(AjaxRequestTarget target) {

            if (connectedDeviceUrl == null) {
                log.warn("Service endpoint for reload is not configured correctly");
                return;
            } else {
                log.info("Attempting to reload configuration using service endpoint " + connectedDeviceUrl);
            }

            HttpURLConnection connection;
            StringResourceModel resultMessage;

            try {
                connection = (HttpURLConnection) new URL(connectedDeviceUrl
                        + (connectedDeviceUrl.endsWith("/") ? restOperation : "/" + restOperation))
                                .openConnection();
                connection.setRequestMethod("GET");
                int responseCode = connection.getResponseCode();
                connection.disconnect();

                if (responseCode != 204) {
                    if (responseCode == 404) {
                        String msg = "The server has not found anything matching the Request-URI "
                                + connection.getURL().toString() + ", HTTP Status " + connection.getResponseCode()
                                + ": " + connection.getResponseMessage();
                        throw new Exception(msg);
                    } else
                        throw new Exception("</br>Expected response 204, but was " + connection.getResponseCode()
                                + ": " + connection.getResponseMessage());
                }

                ((WizardApplication) getApplication()).getDicomConfigurationManager().clearReload(deviceName,
                        connectedDeviceUrl);
            } catch (Exception e) {
                log.error("Error reloading configuration of connected device: " + e.getMessage());
                if (log.isDebugEnabled())
                    e.printStackTrace();
                resultMessage = new StringResourceModel("dicom.reload.message.failed", this, null,
                        new Object[] { e.getMessage() });

                reloadMessage = new MessageWindow("reload-message", resultMessage) {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onOk(AjaxRequestTarget target) {
                    }
                };

                BasicConfigurationPanel.this.addOrReplace(reloadMessage);
                reloadMessage.setWindowClosedCallback(windowClosedCallback).show(target);
            }
            target.add(form);
        }
    }
}