com.microsoft.tfs.core.TFSTeamProjectCollection.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.tfs.core.TFSTeamProjectCollection.java

Source

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the repository root.

package com.microsoft.tfs.core;

import java.net.URI;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.microsoft.tfs.core.clients.build.IBuildServer;
import com.microsoft.tfs.core.clients.commonstructure.CommonStructureClient;
import com.microsoft.tfs.core.clients.commonstructure.ProjectInfo;
import com.microsoft.tfs.core.clients.framework.ServerDataProvider;
import com.microsoft.tfs.core.clients.framework.catalog.ICatalogService;
import com.microsoft.tfs.core.clients.framework.configuration.TFSEntitySession;
import com.microsoft.tfs.core.clients.framework.configuration.catalog.ProjectCollectionCatalogEntity;
import com.microsoft.tfs.core.clients.framework.configuration.catalog.TeamProjectCatalogEntity;
import com.microsoft.tfs.core.clients.framework.configuration.entities.ProjectCollectionEntity;
import com.microsoft.tfs.core.clients.framework.configuration.internal.TFSEntitySessionFactory;
import com.microsoft.tfs.core.clients.framework.internal.ServiceInterfaceNames;
import com.microsoft.tfs.core.clients.framework.location.ConnectOptions;
import com.microsoft.tfs.core.clients.framework.location.ILocationService;
import com.microsoft.tfs.core.clients.framework.location.LocationServiceConstants;
import com.microsoft.tfs.core.clients.registration.RegistrationClient;
import com.microsoft.tfs.core.clients.versioncontrol.SourceControlCapabilityFlags;
import com.microsoft.tfs.core.clients.versioncontrol.VersionControlClient;
import com.microsoft.tfs.core.clients.versioncontrol.WebServiceLevel;
import com.microsoft.tfs.core.clients.workitem.WorkItemClient;
import com.microsoft.tfs.core.config.ConnectionAdvisor;
import com.microsoft.tfs.core.config.DefaultConnectionAdvisor;
import com.microsoft.tfs.core.exceptions.NotSupportedException;
import com.microsoft.tfs.core.httpclient.Credentials;
import com.microsoft.tfs.core.util.URIUtils;
import com.microsoft.tfs.util.GUID;

/**
 * <p>
 * A connection to a team project collection in a TFS 2010 or later server, or
 * to the entire service area of a TFS 2005 or TFS 2008 server.
 * </p>
 *
 * @see TFSConnection
 *
 * @since TEE-SDK-10.1
 * @threadsafety thread-safe
 */
public class TFSTeamProjectCollection extends TFSConnection {
    private static final Log log = LogFactory.getLog(TFSTeamProjectCollection.class);

    /**
     * The single configuration server for this project collection.
     *
     * Initialized lazily by {@link #getConfigurationServer()}.
     */
    private TFSConfigurationServer configurationServer;
    private final Object configurationServerLock = new Object();

    /**
     * Provide information about the server we're connected to. Initialized
     * lazily by {@link #getServerDataProvider()}.
     */
    private ServerDataProvider serverDataProvider;
    private final Object serverDataProviderLock = new Object();

    /**
     * The catalog service based configuration session ("entity session" in .NET
     * OM) for this {@link TFSTeamProjectCollection}. Initialized lazily by
     * {@link #getConfigurationSession(boolean)}.
     */
    private TFSEntitySession configurationSession;
    private final Object configurationSessionLock = new Object();

    /**
     * A convenience constructor to create a {@link TFSTeamProjectCollection}
     * from a {@link URI}. A default {@link ConnectionAdvisor} is used.
     *
     * @param uri
     *        the {@link URI} to use to connect (must not be <code>null</code>)
     * @param credentials
     *        the {@link Credentials} to connect with (or <code>null</code> to
     *        attempt to use the best available credentials)
     */
    public TFSTeamProjectCollection(final URI serverURI, final Credentials credentials) {
        this(serverURI, credentials, new DefaultConnectionAdvisor(Locale.getDefault(), TimeZone.getDefault()));
    }

    /**
     * The most complete way of creating a {@link TFSTeamProjectCollection}. A
     * {@link URI}, {@link Credentials} and a {@link ConnectionAdvisor} are
     * specified.
     *
     * @param serverURI
     *        the {@link URI} to connect to (must not be <code>null</code>)
     * @param credentials
     *        the {@link Credentials} to connect with (or <code>null</code> to
     *        attempt to use the best available credentials)
     * @param advisor
     *        the {@link ConnectionAdvisor} to use (must not be
     *        <code>null</code>)
     */
    public TFSTeamProjectCollection(final URI serverURI, final Credentials credentials,
            final ConnectionAdvisor advisor) {
        this(serverURI, new AtomicReference<Credentials>(credentials), advisor);
    }

    /**
     * Package-protected constructor that allows {@link TFSConfigurationServer}
     * and {@link TFSTeamProjectCollection}s to share credentials (that may be
     * updated at any time) by way of an {@link AtomicReference}.
     *
     * @param serverURI
     *        the {@link URI} to connect to (must not be <code>null</code>)
     * @param credentialsHolder
     *        an {@link AtomicReference} to the {@link Credentials} to connect
     *        with (must not be <code>null</code>)
     * @param advisor
     *        the {@link ConnectionAdvisor} to use (must not be
     *        <code>null</code>)
     */
    protected TFSTeamProjectCollection(final URI serverURI, final AtomicReference<Credentials> credentialsHolder,
            final ConnectionAdvisor advisor) {
        super(serverURI, credentialsHolder, advisor,
                LocationServiceConstants.COLLECTION_LOCATION_SERVICE_RELATIVE_PATH);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ServerDataProvider getServerDataProvider() {
        checkNotClosed();
        synchronized (serverDataProviderLock) {
            if (serverDataProvider == null) {
                try {
                    /*
                     * Create a FrameworkServerDataProvider and see if there's
                     * cached data for it.
                     */
                    final FrameworkServerDataProvider tempFrameworkProvider = new FrameworkServerDataProvider(this);

                    if (tempFrameworkProvider.hasLocalCacheDataForConnection()) {
                        /*
                         * Cached data, use the FrameworkServerDataProvider
                         * provider.
                         */
                        serverDataProvider = tempFrameworkProvider;
                    } else {
                        /*
                         * No cache data, we have to contact the server. Use a
                         * PreFrameworkServerDataProvider, so we can talk with
                         * old servers.
                         */
                        final PreFrameworkServerDataProvider tempPreFrameworkProvider = new PreFrameworkServerDataProvider(
                                this);

                        /*
                         * Query for the location service (a TFS 2010
                         * Framework-era service).
                         */
                        final String locationServiceLocation = tempPreFrameworkProvider
                                .locationForCurrentConnection(ServiceInterfaceNames.LOCATION,
                                        LocationServiceConstants.SELF_REFERENCE_LOCATION_SERVICE_IDENTIFIER);

                        /*
                         * If the Location service was not found, the server is
                         * a pre-framework server (< 2010), so use that kind of
                         * provider. Otherwise, use the Framework provider and
                         * connect it immediately.
                         */
                        if (locationServiceLocation == null) {
                            log.error(MessageFormat.format(
                                    "You cannot connect to {0} because it is running a version of Team Foundation Server that is not supported by your version of Visual Studio. Upgrade your server to Team Foundation Server 2010 (or a newer version), or use Visual Studio 2010, Visual Studio 2012 or Visual Studio 2015.", //$NON-NLS-1$
                                    getBaseURI()));

                            throw new NotSupportedException(MessageFormat.format(
                                    Messages.getString("TFSTeamProjectCollection.NotSupportedTfsVersionFormat"), //$NON-NLS-1$
                                    getBaseURI()));
                        } else {
                            tempFrameworkProvider.connect(ConnectOptions.INCLUDE_SERVICES);
                            serverDataProvider = tempFrameworkProvider;
                        }
                    }

                } catch (final RuntimeException e) {
                    log.warn("Error getting data provider", e); //$NON-NLS-1$

                    // TODO catch the right kind of connection exception and
                    // make a
                    // good error message

                    // WebException webException = ex as WebException;
                    // if (webException != null)
                    // {
                    // HttpWebResponse webResponse = webException.Response as
                    // HttpWebResponse;
                    // if (webResponse != null && webResponse.StatusCode ==
                    // HttpStatusCode.NotFound)
                    // {
                    // throw new
                    // TeamFoundationServiceUnavailableException(ClientResources.ConnectToTfs_AddServer_UnableToConnect_WithTechnicalInfo(Uri.ToString(),
                    // Uri.ToString(), ex.Message), ex);
                    // }
                    // }

                    throw e;
                }
            }

            return serverDataProvider;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected ICatalogService getCatalogService() {
        checkNotClosed();
        /*
         * Use the catalog service from our configuration server.
         */
        return getConfigurationServer().getCatalogService();
    }

    /**
     * @return this team project collection's configuration server connection.
     */
    public TFSConfigurationServer getConfigurationServer() {
        checkNotClosed();
        synchronized (configurationServerLock) {
            if (configurationServer == null) {
                final String location = getServerDataProvider().locationForCurrentConnection(
                        ServiceInterfaceNames.LOCATION,
                        LocationServiceConstants.APPLICATION_LOCATION_SERVICE_IDENTIFIER);

                if (location != null && location.length() > 0) {
                    final URI locationURI = URIUtils.newURI(location);

                    configurationServer = new TFSConfigurationServer(locationURI, getCredentialsHolder(),
                            getConnectionAdvisor());
                    configurationServer.setHTTPClientReference(getHTTPClientReference());
                }
            }
            return configurationServer;
        }
    }

    @Override
    public void close() {
        if (isClosed()) {
            warnClosed();
            return;
        }

        super.close();

        synchronized (configurationServerLock) {
            if (configurationServer != null && !configurationServer.isClosed()) {
                configurationServer.close();
            }
            configurationServer = null;
        }
    }

    public ILocationService getCollectionLocationService() {
        checkNotClosed();
        return (ILocationService) getClient(ILocationService.class);
    }

    /**
     * Gets the catalog service {@link TFSEntitySession} for this team project
     * collection.
     *
     * @param refresh
     *        <code>true</code> to force a refresh of the data from the server,
     *        <code>false</code> to use cached data
     * @return The {@link TFSEntitySession} for this project collection
     */
    public TFSEntitySession getConfigurationSession(final boolean refresh) {
        checkNotClosed();
        synchronized (configurationSessionLock) {
            if (configurationSession == null || refresh) {
                configurationSession = TFSEntitySessionFactory.newEntitySession(this);
            }

            return configurationSession;
        }
    }

    /**
     * Gets the team {@link ProjectCollectionEntity} for this collection.
     *
     * @param refresh
     *        <code>true</code> to force a refresh of the data from the server,
     *        <code>false</code> to use cached data
     * @return the catalog-service based project collection entity for this team
     *         project collection, or <code>null</code> if none could be found
     *         (ie, pre-framework server.)
     */
    public ProjectCollectionEntity getTeamProjectCollectionEntity(final boolean refresh) {
        checkNotClosed();
        final TFSEntitySession configurationSession = getConfigurationSession(refresh);

        if (configurationSession == null || configurationSession.getOrganizationalRoot() == null) {
            return null;
        }

        if (configurationSession.getOrganizationalRoot().getTeamFoundationServer() == null) {
            log.warn("Could not load Team Foundation Server entity from organizational root"); //$NON-NLS-1$
            return null;
        }

        final ProjectCollectionEntity collectionEntity = configurationSession.getOrganizationalRoot()
                .getTeamFoundationServer().getProjectCollection(getInstanceID());

        if (collectionEntity == null) {
            log.warn(MessageFormat.format("Could not load Team Project Collection entity for instance id {0}", //$NON-NLS-1$
                    getInstanceID()));
        }

        return collectionEntity;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public synchronized boolean hasAuthenticated() {
        checkNotClosed();
        final ServerDataProvider serverDataProvider;

        synchronized (serverDataProviderLock) {
            serverDataProvider = this.serverDataProvider;
        }

        return (serverDataProvider != null) ? serverDataProvider.hasAuthenticated() : false;
    }

    /*
     * Convenience methods for client access (so the user doesn't have to guess
     * the class type to pass to getClient()).
     */

    /**
     * {@inheritDoc}
     */
    @Override
    public RegistrationClient getRegistrationClient() {
        checkNotClosed();
        return (RegistrationClient) getClient(RegistrationClient.class);
    }

    /**
     * A convenience method to get the version control client from this
     * {@link TFSConnection}.
     *
     * @return the {@link VersionControlClient}
     */
    public VersionControlClient getVersionControlClient() {
        checkNotClosed();
        return (VersionControlClient) getClient(VersionControlClient.class);
    }

    /**
     * A convenience method to get the WIT client from this
     * {@link TFSConnection}.
     *
     * @return the {@link WorkItemClient}
     */
    public WorkItemClient getWorkItemClient() {
        checkNotClosed();
        return (WorkItemClient) getClient(WorkItemClient.class);
    }

    /**
     * A convenience method to get the Build service client from this
     * {@link TFSConnection}.
     *
     * @return the {@link BuildClient} which implements {@link IBuildServer}
     */
    public IBuildServer getBuildServer() {
        checkNotClosed();
        return (IBuildServer) getClient(IBuildServer.class);
    }

    /**
     * A convenience method to get the common structure service client from this
     * {@link TFSConnection}.
     *
     * @return the {@link CommonStructureClient}
     */
    public CommonStructureClient getCommonStructureClient() {
        checkNotClosed();
        return (CommonStructureClient) getClient(CommonStructureClient.class);
    }

    public SourceControlCapabilityFlags getSourceControlCapability(final ProjectInfo project) {
        checkNotClosed();
        if (getVersionControlClient().getWebServiceLayer().getServiceLevel()
                .getValue() < WebServiceLevel.TFS_2012_QU1.getValue()) {
            return SourceControlCapabilityFlags.TFS;
        } else {
            try {
                ProjectCollectionCatalogEntity collectionCatalogEntry = (ProjectCollectionCatalogEntity) getTeamProjectCollectionEntity(
                        false);
                if (collectionCatalogEntry == null) {
                    // Refresh if the collection entry is stale
                    collectionCatalogEntry = (ProjectCollectionCatalogEntity) getTeamProjectCollectionEntity(true);
                }

                TeamProjectCatalogEntity projectCatalogEntry = (TeamProjectCatalogEntity) collectionCatalogEntry
                        .getTeamProject(new GUID(project.getGUID()));
                if (projectCatalogEntry == null) {
                    // Refresh if the collection catalog entry is stale
                    collectionCatalogEntry = (ProjectCollectionCatalogEntity) getTeamProjectCollectionEntity(true);
                    projectCatalogEntry = (TeamProjectCatalogEntity) collectionCatalogEntry
                            .getTeamProject(new GUID(project.getGUID()));
                }

                SourceControlCapabilityFlags sourceControlCapabilityFlag = SourceControlCapabilityFlags.NONE;

                if (projectCatalogEntry.isGitSupported()) {
                    sourceControlCapabilityFlag = sourceControlCapabilityFlag
                            .combine(SourceControlCapabilityFlags.GIT);
                }

                if (projectCatalogEntry.isTfvcSupported()) {
                    sourceControlCapabilityFlag = sourceControlCapabilityFlag
                            .combine(SourceControlCapabilityFlags.TFS);
                }

                return sourceControlCapabilityFlag;
            } catch (final Exception e) {
                log.error("Unexpected error accessing Catalog Entry: ", e); //$NON-NLS-1$
                return SourceControlCapabilityFlags.TFS;
            }
        }
    }

}