Package org.eclipse.ecf.internal.sync.resources.core

Source Code of org.eclipse.ecf.internal.sync.resources.core.SyncResourcesCore

/*******************************************************************************
* Copyright (c) 2008, 2009 Composent, Inc. and others.
* 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
*
* Contributors:
*    Composent, Inc. - initial API and implementation
******************************************************************************/
package org.eclipse.ecf.internal.sync.resources.core;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.DefaultScope;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.util.ECFException;
import org.eclipse.ecf.sync.IModelChange;
import org.eclipse.ecf.sync.IModelChangeMessage;
import org.eclipse.ecf.sync.resources.core.preferences.PreferenceConstants;
import org.osgi.framework.BundleContext;
import org.osgi.service.prefs.Preferences;

public class SyncResourcesCore extends Plugin implements
    IResourceChangeListener, IResourceDeltaVisitor {

  public static final String PLUGIN_ID = "org.eclipse.ecf.sync.resources.core"; //$NON-NLS-1$

  private static final int LIMIT = 25;

  private static final Hashtable channels = new Hashtable();

  private static LinkedList enqueuedChanges = new LinkedList();

  private static SyncResourcesCore instance;

  private Map resourceChanges = new HashMap();

  public static ResourcesShare getResourcesShare(ID containerID) {
    return (ResourcesShare) channels.get(containerID);
  }

  public static void addResourcesShare(ID containerID, ResourcesShare share) {
    channels.put(containerID, share);
  }

  public static ResourcesShare removeResourcesShare(ID containerID) {
    return (ResourcesShare) channels.remove(containerID);
  }

  public static Collection getResourceShares() {
    return Collections.unmodifiableCollection(channels.values());
  }

  /**
   * Checks and returns whether the specified project is currently being
   * shared.
   */
  public static boolean isSharing(String projectName) {
    for (Iterator it = channels.values().iterator(); it.hasNext();) {
      ResourcesShare share = (ResourcesShare) it.next();
      if (share.isSharing(projectName)) {
        return true;
      }
    }
    return false;
  }

  private static boolean locked = false;

  /**
   * Requests that all resource changes be ignored. That is, they should not
   * be monitored for distribution to remote peers.
   */
  public static void lock() {
    locked = true;
  }

  /**
   * Unlocks by requesting that that all resource changes be monitored for
   * distribution to remote peers.
   */
  public static void unlock() {
    locked = false;
  }

  public boolean visit(IResourceDelta delta) throws CoreException {
    if (locked) {
      return false;
    }

    IResource resource = delta.getResource();
    int type = resource.getType();
    if (type == IResource.ROOT) {
      return true;
    }

    String projectName = resource.getProject().getName();
    boolean isSharing = isSharing(projectName);
    if (isSharing) {
      if (type == IResource.PROJECT) {
        return true;
      }
    } else {
      // this project is not being shared so we don't care about its
      // changes, return false
      return false;
    }

    // we are only interested in non-derived resources
    if (!resource.isDerived() && checkDelta(delta)) {
      for (Iterator it = channels.values().iterator(); it.hasNext();) {
        ResourcesShare share = (ResourcesShare) it.next();
        if (share.isSharing(projectName)) {
          IModelChange change = ResourceChangeMessage
              .createResourceChange(resource, delta.getKind());
          if (change != null) {
            List changes = (List) resourceChanges.get(share);
            if (changes == null) {
              changes = new ArrayList();
              resourceChanges.put(share, changes);
            }

            changes.add(change);
          }
        }
      }
    }
    return type == IResource.FOLDER;
  }

  private static boolean checkDelta(IResourceDelta delta) {
    return checkFlags(delta.getFlags()) || checkKind(delta.getKind());
  }

  private static boolean checkKind(int kind) {
    return kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED;
  }

  /**
   * Checks the flags of a how a resource has been modified and returns
   * whether this change should be propagated to remote peers.
   *
   * @param flags
   *            the detail flags of a resource delta
   * @return <code>true</code> if the delta should be propagated,
   *         <code>false</code> otherwise
   */
  private static boolean checkFlags(int flags) {
    // we are only interested in content change, marker changes also fire
    // resource change events but we don't care about those, from
    // preliminary investigations, monitoring marker changes will cause
    // infinite loops
    return (flags & IResourceDelta.CONTENT) != 0;
  }

  public void resourceChanged(IResourceChangeEvent event) {
    try {
      event.getDelta().accept(this);
    } catch (CoreException e) {
      // ignored, this isn't possible as we never throw one
    } finally {
      try {
        // we're done, at least, "partially", distribute changes
        distributeChanges();
      } finally {
        // clear the cached changes
        resourceChanges.clear();
      }
    }
  }

  private void distributeChanges() {
    for (Iterator it = resourceChanges.entrySet().iterator(); it.hasNext();) {
      Entry entry = (Entry) it.next();
      ResourcesShare share = (ResourcesShare) entry.getKey();
      List changes = (List) entry.getValue();

      List messages = new ArrayList();
      for (int i = 0; i < changes.size(); i++) {
        ResourceChangeMessage change = (ResourceChangeMessage) changes
            .get(i);

        switch (change.getKind()) {
        case IResourceDelta.ADDED:
          if (getInt(PreferenceConstants.LOCAL_RESOURCE_ADDITION) == PreferenceConstants.IGNORE_VALUE) {
            change.setIgnored(true);
            continue;
          }
          break;
        case IResourceDelta.CHANGED:
          if (getInt(PreferenceConstants.LOCAL_RESOURCE_CHANGE) == PreferenceConstants.IGNORE_VALUE) {
            change.setIgnored(true);
            continue;
          }
          break;
        case IResourceDelta.REMOVED:
          if (getInt(PreferenceConstants.LOCAL_RESOURCE_DELETION) == PreferenceConstants.IGNORE_VALUE) {
            change.setIgnored(true);
            continue;
          }
          break;
        }

        IModelChangeMessage[] changeMessages = ResourcesSynchronizationStrategy
            .getInstance().registerLocalChange(change);
        messages.addAll(Arrays.asList(changeMessages));
      }

      try {
        if (!messages.isEmpty()) {
          IModelChangeMessage[] messagesArray = (IModelChangeMessage[]) messages
              .toArray(new IModelChangeMessage[messages.size()]);
          BatchModelChange batchChange = new BatchModelChange(
              messagesArray);
          share.send(Message.serialize(batchChange));

          add(batchChange);
        }
      } catch (ECFException e) {
        getDefault().getLog().log(
            new Status(IStatus.ERROR, PLUGIN_ID,
                "Could not send resource change message", e)); //$NON-NLS-1$
      }
    }
  }

  private static IView viewInstance;

  public static synchronized void setView(IView resourcesView) {
    viewInstance = resourcesView;
    if (resourcesView != null) {
      resourcesView.setInput(enqueuedChanges);
    }
  }

  public static synchronized void add(Object object) {
    if (enqueuedChanges.size() == LIMIT) {
      remove();
    }

    enqueuedChanges.addFirst(object);
    if (viewInstance != null) {
      viewInstance.add(object);
    }
  }

  private static synchronized void remove() {
    Object object = enqueuedChanges.removeLast();
    if (viewInstance != null) {
      viewInstance.remove(object);
    }
  }

  private static Preferences preferences;
  private static Preferences defaultPreferences;

  public SyncResourcesCore() {
    instance = this;
  }

  void attachListener() {
    ResourcesPlugin.getWorkspace().addResourceChangeListener(this,
        IResourceChangeEvent.POST_CHANGE);
  }

  void detachListener() {
    ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext
   * )
   */
  public void start(BundleContext ctxt) throws Exception {
    super.start(ctxt);
    attachListener();
    preferences = new InstanceScope().getNode(SyncResourcesCore.PLUGIN_ID);
    defaultPreferences = new DefaultScope()
        .getNode(SyncResourcesCore.PLUGIN_ID);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
   */
  public void stop(BundleContext context) throws Exception {
    instance = null;
    detachListener();
    super.stop(context);
  }

  public static SyncResourcesCore getDefault() {
    return instance;
  }

  public static int getInt(String key) {
    return preferences.getInt(key, defaultPreferences.getInt(key,
        PreferenceConstants.COMMIT_VALUE));
  }

}
TOP

Related Classes of org.eclipse.ecf.internal.sync.resources.core.SyncResourcesCore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.