com.google.gwt.eclipse.oophm.model.WebAppDebugModel.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.eclipse.oophm.model.WebAppDebugModel.java

Source

/*******************************************************************************
 * Copyright 2011 Google Inc. All Rights Reserved.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package com.google.gwt.eclipse.oophm.model;

import com.google.gwt.eclipse.oophm.devmode.DevModeServiceClientManager;

import org.eclipse.debug.core.ILaunch;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * The model for the OOPHM data. At the top level, the model consists of a list of
 * {@link LaunchConfiguration}.
 *
 * This class is thread-safe, except for the initializeModel() method. TODO: initializeModel()
 * method gone, determine impact on thread safety.
 */
public class WebAppDebugModel implements IModelNode {

    private static WebAppDebugModel INSTANCE = new WebAppDebugModel();

    /**
     * Get the global model instance.
     */
    public static WebAppDebugModel getInstance() {
        return INSTANCE;
    }

    private final int id;
    private final List<LaunchConfiguration> launchConfigurations = new ArrayList<LaunchConfiguration>();
    private final AtomicInteger nextModelNodeId = new AtomicInteger();

    private final Object privateInstanceLock = new Object();

    private final List<IWebAppDebugModelListener> webAppDebugModelListeners = new ArrayList<IWebAppDebugModelListener>();

    WebAppDebugModel() {
        // Not instantiable
        id = getModelNodeNextId();
    }

    /**
     * Adds the launch configuration to the model, or returns the existing launch configuration. Fires
     * an event to all listeners on the model if the launch configuration was added.
     *
     * @param clientId optional if newLaunch is non-null
     * @param factory if non-null, this will be used to instantiate a {@link LaunchConfiguration} to
     *        be added
     */
    public LaunchConfiguration addOrReturnExistingLaunchConfiguration(ILaunch newLaunch, String clientId,
            ILaunchConfigurationFactory factory) {
        LaunchConfiguration launchConfiguration;

        synchronized (privateInstanceLock) {
            for (LaunchConfiguration lc : launchConfigurations) {
                if (lc.getLaunch().equals(newLaunch)) {
                    return lc;
                }
            }

            String name = LaunchConfiguration.computeNamePrefix(newLaunch, clientId);
            if (factory != null) {
                launchConfiguration = factory.newLaunchConfiguration(newLaunch, name, this);
            } else {
                launchConfiguration = new LaunchConfiguration(newLaunch, name, this);
            }
            launchConfigurations.add(launchConfiguration);
        }

        // Only fire events when we're not holding any locks. Otherwise, deadlock
        // may happen.
        WebAppDebugModelEvent<LaunchConfiguration> launchedEvent = new WebAppDebugModelEvent<LaunchConfiguration>(
                launchConfiguration);
        fireLaunchConfigurationLaunched(launchedEvent);

        // Clean up terminated launch configurations with the same name as the added
        // launch configuration
        removeAllAssociatedTerminatedLaunchConfigsExceptMostRecent(launchConfiguration);

        return launchConfiguration;
    }

    /**
     * TODO extract possibly? 
     *
     * @param launchConfiguration
     */
    public void addLaunchConfiguration(LaunchConfiguration launchConfiguration) {
        synchronized (privateInstanceLock) {
            for (LaunchConfiguration lc : launchConfigurations) {
                if (lc.equals(launchConfiguration)) {
                    return;
                }
            }
            launchConfigurations.add(launchConfiguration);
        }

        // Only fire events when we're not holding any locks. Otherwise, deadlock
        // may happen.
        WebAppDebugModelEvent<LaunchConfiguration> launchedEvent = new WebAppDebugModelEvent<LaunchConfiguration>(
                launchConfiguration);
        fireLaunchConfigurationLaunched(launchedEvent);

        // Clean up terminated launch configurations with the same name as the added
        // launch configuration
        removeAllAssociatedTerminatedLaunchConfigsExceptMostRecent(launchConfiguration);
    }

    /**
     * Add a listener for changes to the model.
     */
    public void addWebAppDebugModelListener(IWebAppDebugModelListener listener) {
        synchronized (privateInstanceLock) {
            webAppDebugModelListeners.add(listener);
        }
    }

    @Override
    public List<? extends IModelNode> getChildren() {
        return getLaunchConfigurations();
    }

    @Override
    public int getId() {
        return id;
    }

    /**
     * Returns the most-recently created launch configuration that has not been terminated as yet, or
     * <code>null</code> if no such launch configuration can be found.
     */
    public LaunchConfiguration getLatestActiveLaunchConfiguration() {
        synchronized (privateInstanceLock) {
            for (int i = launchConfigurations.size() - 1; i > -1; i--) {
                LaunchConfiguration lc = launchConfigurations.get(i);
                if (!lc.isTerminated()) {
                    return lc;
                }
            }
            return null;
        }
    }

    /**
     * Get the launch configurations.
     */
    public List<LaunchConfiguration> getLaunchConfigurations() {
        synchronized (privateInstanceLock) {
            return new ArrayList<LaunchConfiguration>(launchConfigurations);
        }
    }

    @Override
    public String getName() {
        // The WebAppDebugModel doesn't have a name; return the empty string
        return "";
    }

    @Override
    public String getNeedsAttentionLevel() {
        return null;
    }

    @Override
    public IModelNode getParent() {
        return null;
    }

    /**
     * Returns the terminated launch configurations that are part of the model.
     */
    public List<LaunchConfiguration> getTerminatedLaunchConfigurations() {
        List<LaunchConfiguration> launchConfigurations = getLaunchConfigurations();
        Iterator<LaunchConfiguration> iter = launchConfigurations.iterator();
        while (iter.hasNext()) {
            LaunchConfiguration next = iter.next();
            if (!next.isTerminated()) {
                iter.remove();
            }
        }

        return launchConfigurations;
    }

    /**
     * Returns a list of the {@link IWebAppDebugModelListener} instances that are registered with the
     * model.
     */
    public List<IWebAppDebugModelListener> getWebAppDebugModelListeners() {
        synchronized (privateInstanceLock) {
            return new ArrayList<IWebAppDebugModelListener>(webAppDebugModelListeners);
        }
    }

    @Override
    public boolean isTerminated() {
        return false;
    }

    /**
     * Given a {@link ILaunch} of a terminated launch, find the associated launch configuration in the
     * model, and mark it as terminated. Fires an event to all listeners on the
     * {@link WebAppDebugModel}.
     *
     * This method does nothing if no such launch configuration can be found.
     */
    public void launchTerminated(ILaunch launch) {
        LaunchConfiguration launchConfiguration = null;
        synchronized (privateInstanceLock) {
            for (LaunchConfiguration lc : launchConfigurations) {
                if (lc.getLaunch() == launch) {
                    launchConfiguration = lc;
                    break;
                }
            }
        }

        if (launchConfiguration != null) {
            launchConfiguration.setTerminated();
        }
    }

    /**
     * Remove the launch configuration. Fires an event for the launch configuration that was removed.
     *
     * @return true if the launch configuration was removed successfully
     */
    public boolean removeLaunchConfiguration(LaunchConfiguration lc) {
        boolean wasRemoved = false;
        synchronized (privateInstanceLock) {
            // TODO: Mark launch configuration as removed, and force the removal of
            // all of its browser tabs and servers
            wasRemoved = launchConfigurations.remove(lc);
        }

        if (wasRemoved) {
            DevModeServiceClientManager.getInstance().removeClient(lc);

            // Only fire events when we're not holding any locks. Otherwise, deadlock
            // may happen.
            WebAppDebugModelEvent<LaunchConfiguration> removedEvent = new WebAppDebugModelEvent<LaunchConfiguration>(
                    lc);
            fireLaunchConfigurationRemoved(removedEvent);
        }
        return wasRemoved;
    }

    /**
     * Removes all launches that have been terminated from the model. Fires an event for each launch
     * configuration that was removed.
     *
     * {@link #removeLaunchConfiguration(LaunchConfiguration)}
     */
    public void removeTerminatedLaunchesFromModel() {
        List<LaunchConfiguration> terminatedLaunchConfigs = new ArrayList<LaunchConfiguration>();
        synchronized (privateInstanceLock) {
            for (LaunchConfiguration lc : launchConfigurations) {
                if (lc.isTerminated()) {
                    terminatedLaunchConfigs.add(lc);
                }
            }
        }

        for (LaunchConfiguration lc : terminatedLaunchConfigs) {
            removeLaunchConfiguration(lc);
        }
    }

    /**
     * Remove a listener registered to receive notifications about model changes.
     *
     * @return true if the listener was removed successfully
     */
    public boolean removeWebAppDebugModelListener(IWebAppDebugModelListener listener) {
        synchronized (privateInstanceLock) {
            return webAppDebugModelListeners.remove(listener);
        }
    }

    int getModelNodeNextId() {
        return nextModelNodeId.getAndIncrement();
    }

    private void fireLaunchConfigurationLaunched(WebAppDebugModelEvent<LaunchConfiguration> launchedEvent) {
        for (IWebAppDebugModelListener webAppDebugModelListener : getWebAppDebugModelListeners()) {
            webAppDebugModelListener.launchConfigurationLaunched(launchedEvent);
        }
    }

    private void fireLaunchConfigurationRemoved(WebAppDebugModelEvent<LaunchConfiguration> removedEvent) {
        for (IWebAppDebugModelListener webAppDebugModelListener : getWebAppDebugModelListeners()) {
            webAppDebugModelListener.launchConfigurationRemoved(removedEvent);
        }
    }

    private void removeAllAssociatedTerminatedLaunchConfigsExceptMostRecent(
            LaunchConfiguration addedLaunchConfiguration) {
        List<LaunchConfiguration> terminatedAssociatedLaunchConfigs = new ArrayList<LaunchConfiguration>();
        synchronized (privateInstanceLock) {
            for (LaunchConfiguration lc : launchConfigurations) {
                if (lc.isTerminated() && lc.getName().equals(addedLaunchConfiguration.getName())) {
                    terminatedAssociatedLaunchConfigs.add(lc);
                }
            }
        }

        int numTerminatedLaunchesToRemove = terminatedAssociatedLaunchConfigs.size() - 1;
        for (int i = 0; i < numTerminatedLaunchesToRemove; i++) {
            removeLaunchConfiguration(terminatedAssociatedLaunchConfigs.get(i));
        }
    }
}