org.artifactory.webapp.wicket.page.config.repos.remote.HttpRepoPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.artifactory.webapp.wicket.page.config.repos.remote.HttpRepoPanel.java

Source

/*
 * Artifactory is a binaries repository manager.
 * Copyright (C) 2012 JFrog Ltd.
 *
 * Artifactory is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Artifactory is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Artifactory.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.artifactory.webapp.wicket.page.config.repos.remote;

import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
import org.apache.wicket.extensions.markup.html.tabs.ITab;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import org.artifactory.addon.wicket.GemsWebAddon;
import org.artifactory.addon.wicket.NuGetWebAddon;
import org.artifactory.addon.wicket.PropertiesWebAddon;
import org.artifactory.addon.wicket.ReplicationWebAddon;
import org.artifactory.common.wicket.behavior.CssClass;
import org.artifactory.common.wicket.component.CreateUpdateAction;
import org.artifactory.common.wicket.component.links.TitledAjaxSubmitLink;
import org.artifactory.common.wicket.util.AjaxUtils;
import org.artifactory.descriptor.config.MutableCentralConfigDescriptor;
import org.artifactory.descriptor.property.PropertySet;
import org.artifactory.descriptor.replication.RemoteReplicationDescriptor;
import org.artifactory.descriptor.repo.HttpRepoDescriptor;
import org.artifactory.descriptor.repo.RemoteRepoDescriptor;
import org.artifactory.descriptor.repo.RepoType;
import org.artifactory.security.crypto.CryptoHelper;
import org.artifactory.util.HttpClientConfigurator;
import org.artifactory.util.HttpClientUtils;
import org.artifactory.util.HttpUtils;
import org.artifactory.util.PathUtils;
import org.artifactory.webapp.wicket.page.config.repos.CachingDescriptorHelper;
import org.artifactory.webapp.wicket.page.config.repos.RepoConfigCreateUpdatePanel;
import org.artifactory.webapp.wicket.panel.tabbed.tab.BaseTab;
import org.artifactory.webapp.wicket.util.CronUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

/**
 * Remote repository configuration panel.
 *
 * @author Yossi Shaul
 */
public class HttpRepoPanel extends RepoConfigCreateUpdatePanel<HttpRepoDescriptor> {
    private static final Logger log = LoggerFactory.getLogger(HttpRepoPanel.class);

    private RemoteReplicationDescriptor replicationDescriptor;

    public HttpRepoPanel(CreateUpdateAction action, HttpRepoDescriptor repoDescriptor,
            CachingDescriptorHelper cachingDescriptorHelper) {
        super(action, repoDescriptor, cachingDescriptorHelper);
        setWidth(770);
    }

    @Override
    protected List<ITab> getConfigurationTabs() {
        List<ITab> tabs = Lists.newArrayList();

        tabs.add(new AbstractTab(Model.of("Basic Settings")) {
            @Override
            public Panel getPanel(String panelId) {
                return new HttpRepoBasicPanel(panelId, entity);
            }
        });

        tabs.add(new BaseTab(Model.of("Advanced Settings")) {
            @Override
            public Panel getPanel(String panelId) {
                return new HttpRepoAdvancedPanel(panelId, action, entity,
                        cachingDescriptorHelper.getModelMutableDescriptor());
            }

            @Override
            public void onNewTabLink(Component link) {
                super.onNewTabLink(link);
                link.add(new CssClass("wide-tab"));
            }
        });

        List<PropertySet> propertySets = getCachingDescriptorHelper().getModelMutableDescriptor().getPropertySets();
        PropertiesWebAddon propertiesWebAddon = addons.addonByType(PropertiesWebAddon.class);
        tabs.add(propertiesWebAddon.getRepoConfigPropertySetsTab("Property Sets", entity, propertySets));

        replicationDescriptor = cachingDescriptorHelper.getModelMutableDescriptor()
                .getRemoteReplication(entity.getKey());
        if (replicationDescriptor == null) {
            replicationDescriptor = new RemoteReplicationDescriptor();
            replicationDescriptor.setRepoKey(entity.getKey());
        }
        ReplicationWebAddon replicationWebAddon = addons.addonByType(ReplicationWebAddon.class);
        tabs.add(replicationWebAddon.getHttpRepoReplicationPanel("Replication", entity, replicationDescriptor,
                action));

        // packages tab contains add-ons configuration
        tabs.add(new AbstractTab(Model.of("Packages")) {
            @Override
            public Panel getPanel(String panelId) {
                return new HttpRepoPackagesPanel<>(panelId, entity, isCreate());
            }
        });
        return tabs;
    }

    @Override
    public void addAndSaveDescriptor(HttpRepoDescriptor repoDescriptor) {
        CachingDescriptorHelper helper = getCachingDescriptorHelper();
        MutableCentralConfigDescriptor mccd = helper.getModelMutableDescriptor();
        if (StringUtils.isBlank(repoDescriptor.getP2OriginalUrl())) {
            repoDescriptor.setP2OriginalUrl(getUrlWithoutSubpath(repoDescriptor.getUrl()));
        }
        mccd.addRemoteRepository(repoDescriptor);
        if (replicationDescriptor.isEnabled()) {
            if (StringUtils.isBlank(replicationDescriptor.getRepoKey())) {
                replicationDescriptor.setRepoKey(repoDescriptor.getKey());
            }
            mccd.addRemoteReplication(replicationDescriptor);
        }
        helper.syncAndSaveRemoteRepositories();
    }

    @Override
    public void saveEditDescriptor(HttpRepoDescriptor repoDescriptor) {
        CachingDescriptorHelper helper = getCachingDescriptorHelper();
        MutableCentralConfigDescriptor mccd = helper.getModelMutableDescriptor();
        //update the model being saved
        Map<String, RemoteRepoDescriptor> remoteRepositoriesMap = mccd.getRemoteRepositoriesMap();
        if (remoteRepositoriesMap.containsKey(repoDescriptor.getKey())) {
            if (StringUtils.isBlank(repoDescriptor.getP2OriginalUrl())) {
                RemoteRepoDescriptor oldDescriptor = helper.getSavedMutableDescriptor().getRemoteRepositoriesMap()
                        .get(repoDescriptor.getKey());
                if (oldDescriptor != null) {
                    repoDescriptor.setP2OriginalUrl(getUrlWithoutSubpath(oldDescriptor.getUrl()));
                }
            }
            remoteRepositoriesMap.put(repoDescriptor.getKey(), repoDescriptor);
        }
        if (replicationDescriptor.isEnabled() && !mccd.isRemoteReplicationExists(replicationDescriptor)) {
            if (StringUtils.isBlank(replicationDescriptor.getRepoKey())) {
                replicationDescriptor.setRepoKey(repoDescriptor.getKey());
            }
            mccd.addRemoteReplication(replicationDescriptor);
        }
        helper.syncAndSaveRemoteRepositories();
    }

    private String getUrlWithoutSubpath(String url) {
        int slashslash = url.indexOf("//") + 2;
        int nextSlash = url.indexOf('/', slashslash);
        return nextSlash < 0 ? url : PathUtils.trimSlashes(url.substring(0, nextSlash)).toString();
    }

    @Override
    protected boolean validate(HttpRepoDescriptor repoDescriptor) {
        boolean urlValid = StringUtils.isNotEmpty(repoDescriptor.getUrl());
        if (!urlValid) {
            error("Field 'Url' is required.");
            return false;
        }

        if (repoDescriptor.getSocketTimeoutMillis() < 0) {
            error("Socket Timeout must be positive or zero.");
            return false;
        }

        if (replicationDescriptor != null && replicationDescriptor.isEnabled()) {
            String cronExp = replicationDescriptor.getCronExp();
            if (StringUtils.isBlank(cronExp) || !CronUtils.isValid(cronExp)) {
                error("Invalid cron expression");
                return false;
            }
        }

        repoDescriptor.setPassword(CryptoHelper.encryptIfNeeded(repoDescriptor.getPassword()));

        return true;
    }

    @Override
    protected TitledAjaxSubmitLink createTestButton() {
        return new TitledAjaxSubmitLink("test", "Test", form) {
            @Override
            protected void onSubmit(AjaxRequestTarget target, Form form) {
                HttpRepoDescriptor repo = getRepoDescriptor();
                if (!validate(repo)) {
                    AjaxUtils.refreshFeedback();
                    return;
                }
                // always test with url trailing slash
                String url = PathUtils.addTrailingSlash(repo.getUrl());
                HttpRequestBase testMethod = getRemoteRepoTestMethod(url);
                CloseableHttpClient client = getRemoteRepoTestHttpClient(repo, url);
                CloseableHttpResponse response = null;
                try {
                    response = client.execute(testMethod);
                    boolean success = remoteRepoTestValidStatus(response.getStatusLine().getStatusCode());
                    if (!success) {
                        IOUtils.closeQuietly(response);
                        final Header serverHeader = response.getFirstHeader("Server");
                        // S3 hosted repositories are not hierarchical and does not have a notion of "collection" (folder, directory)
                        // Therefore we should not add the trailing slash when testing them
                        if (serverHeader != null && "AmazonS3".equals(serverHeader.getValue())) {
                            log.debug("Remote repository is hosted on Amazon S3, trying without a trailing slash");

                            url = repo.getUrl();
                            testMethod = getRemoteRepoTestMethod(url);
                            response = client.execute(testMethod);
                            success = remoteRepoTestValidStatus(response.getStatusLine().getStatusCode());
                        }
                    }
                    if (!success) {
                        error("Connection failed: Error " + response.getStatusLine().getStatusCode() + ": "
                                + response.getStatusLine().getReasonPhrase());
                    } else {
                        info("Successfully connected to server");
                    }
                } catch (Exception e) {
                    error("Connection failed with exception: " + HttpClientUtils.getErrorMessage(e));
                    log.debug("Test connection to '" + url + "' failed with exception", e);
                } finally {
                    IOUtils.closeQuietly(response);
                    IOUtils.closeQuietly(client);
                }
                AjaxUtils.refreshFeedback(target);
            }
        };
    }

    protected HttpRequestBase getRemoteRepoTestMethod(String url) {
        HttpRequestBase testMethod = null;
        HttpRepoDescriptor repo = getRepoDescriptor();

        if (repo.getType().equals(RepoType.Gems)) {
            GemsWebAddon gemsAddon = addons.addonByType(GemsWebAddon.class);
            testMethod = gemsAddon.getRemoteRepoTestMethod(url, repo);
        }
        if (testMethod == null) {
            testMethod = addons.addonByType(NuGetWebAddon.class).getRemoteRepoTestMethod(url, repo);
        }
        if (testMethod == null) {
            testMethod = new HttpHead(HttpUtils.encodeQuery(url));
        }
        return testMethod;
    }

    protected CloseableHttpClient getRemoteRepoTestHttpClient(HttpRepoDescriptor repo, String url) {
        return new HttpClientConfigurator().hostFromUrl(url).connectionTimeout(repo.getSocketTimeoutMillis())
                .soTimeout(repo.getSocketTimeoutMillis()).staleCheckingEnabled(true).retry(1, false)
                .localAddress(repo.getLocalAddress()).proxy(repo.getProxy())
                .authentication(repo.getUsername(), CryptoHelper.decryptIfNeeded(repo.getPassword()),
                        repo.isAllowAnyHostAuth())
                .enableCookieManagement(repo.isEnableCookieManagement()).getClient();
    }

    protected boolean remoteRepoTestValidStatus(int status) {
        return status == HttpServletResponse.SC_OK || status == HttpServletResponse.SC_NO_CONTENT;
    }
}