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

Java tutorial

Introduction

Here is the source code for com.microsoft.tfs.core.TFSConfigurationServer.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.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
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.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.entities.ProjectCollectionEntity;
import com.microsoft.tfs.core.clients.framework.configuration.entities.TeamFoundationServerEntity;
import com.microsoft.tfs.core.clients.framework.configuration.internal.TFSEntitySessionFactory;
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.config.ConnectionAdvisor;
import com.microsoft.tfs.core.config.DefaultConnectionAdvisor;
import com.microsoft.tfs.core.httpclient.Credentials;
import com.microsoft.tfs.util.Check;
import com.microsoft.tfs.util.GUID;

/**
 * A connection to the configuration server area of a TFS 2010 or later
 * installation.
 *
 * @see TFSConnection
 *
 * @since TEE-SDK-10.1
 * @since TFS 2010
 * @threadsafety thread-safe
 */
public class TFSConfigurationServer extends TFSConnection {
    private static final Log log = LogFactory.getLog(TFSConfigurationServer.class);

    /**
     * Provide information about the server we're connected to.
     */
    private ServerDataProvider serverDataProvider;
    private final Object serverDataProviderLock = new Object();

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

    /**
     * A cache of the {@link TFSTeamProjectCollection}s we have loaded. Key is
     * {@link String} (the collection location) and value is
     * {@link TFSTeamProjectCollection}. Synchronize on this object.
     */
    private final Map<String, TFSTeamProjectCollection> collections = new HashMap<String, TFSTeamProjectCollection>();
    private final Object collectionsLock = new Object();

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

        /*
         * TODO Remove this when we have an SDK so they don't get warnings? For
         * now it helps with the persistence transition.
         */
        final String messageFormat = "Using {0} for TFSConfigurationServer, which is undesirable for Team Foundation Server client applications"; //$NON-NLS-1$
        final String message = MessageFormat.format(messageFormat, DefaultConnectionAdvisor.class.getName());
        log.warn(message);
    }

    /**
     * The most complete way of creating a {@link TFSConfigurationServer}. 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
     * @param advisor
     *        the {@link ConnectionAdvisor} to use (must not be
     *        <code>null</code>)
     */
    public TFSConfigurationServer(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 TFSConfigurationServer(final URI serverURI, final AtomicReference<Credentials> credentialsHolder,
            final ConnectionAdvisor advisor) {
        super(serverURI, credentialsHolder, advisor,
                LocationServiceConstants.APPLICATION_LOCATION_SERVICE_RELATIVE_PATH);
    }

    /**
     * Gets the {@link TFSTeamProjectCollection} for the specified ID.
     *
     * @param collectionID
     *        the collection's ID (must not be <code>null</code>)
     * @return the {@link TFSTeamProjectCollection} that matches the ID, or
     *         <code>null</code> if no matching collection was found
     */
    public TFSTeamProjectCollection getTeamProjectCollection(final GUID collectionID) {
        checkNotClosed();

        Check.notNull(collectionID, "collectionID"); //$NON-NLS-1$

        final String collectionLocation = getServerDataProvider().findServerLocation(collectionID);

        TFSTeamProjectCollection ret = null;

        synchronized (collectionsLock) {
            if (collectionLocation != null) {
                if (collections.containsKey(collectionLocation)) {
                    ret = collections.get(collectionLocation);
                } else {
                    /*
                     * Collection location comes from the server data provider
                     * as a properly formed (escaped) URI. Do not use helper
                     * methods that would re-escape.
                     */
                    final URI collectionLocationURI;

                    try {
                        collectionLocationURI = new URI(collectionLocation);
                    } catch (final URISyntaxException e) {
                        throw new IllegalArgumentException(e.getLocalizedMessage(), e);
                    }

                    ret = new TFSTeamProjectCollection(collectionLocationURI, getCredentialsHolder(),
                            getConnectionAdvisor());
                    ret.setHTTPClientReference(getHTTPClientReference());

                    collections.put(collectionLocation, ret);
                }
            }
        }

        return ret;
    }

    /**
     * Gets the catalog service {@link TFSEntitySession} for this configuration
     * server.
     *
     * @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 configuration server
     */
    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 configuration
     * server.
     *
     * @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 server entity for this configuration
     *         server project collection, or <code>null</code> if none could be
     *         found (ie, pre-framework server.)
     */
    public TeamFoundationServerEntity getTeamFoundationServerEntity(final boolean refresh) {
        checkNotClosed();

        final TFSEntitySession configurationSession = getConfigurationSession(refresh);

        if (configurationSession == null || configurationSession.getOrganizationalRoot() == null) {
            log.warn(MessageFormat.format("Could not load configuration session for instance id {0}", //$NON-NLS-1$
                    getInstanceID()));
            return null;
        }

        final TeamFoundationServerEntity serverEntity = configurationSession.getOrganizationalRoot()
                .getTeamFoundationServer();

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

        return serverEntity;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ServerDataProvider getServerDataProvider() {
        checkNotClosed();

        synchronized (serverDataProviderLock) {
            if (serverDataProvider == null) {
                try {
                    /*
                     * Create a FrameworkServerDataProvider and see if there's
                     * cached data for it. If there is no cached data, connect.
                     */
                    final FrameworkServerDataProvider tempFrameworkProvider = new FrameworkServerDataProvider(this);

                    if (tempFrameworkProvider.hasLocalCacheDataForConnection() == false) {
                        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
    public ICatalogService getCatalogService() {
        checkNotClosed();

        return (ICatalogService) getClient(ICatalogService.class);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean hasAuthenticated() {
        checkNotClosed();

        final ServerDataProvider serverDataProvider;

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

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

    public void reactToPossibleServerUpdate(final int locationServiceLastChangeId) {
        checkNotClosed();

        getServerDataProvider().reactToPossibleServerUpdate(locationServiceLastChangeId);
    }

    /**
     * The registration service is not available for a configuration server
     * instance.
     *
     * {@inheritDoc}
     */
    @Override
    public RegistrationClient getRegistrationClient() {
        checkNotClosed();

        return null;
    }

    public ILocationService getLocationService() {
        checkNotClosed();

        return (ILocationService) getClient(ILocationService.class);
    }
}