All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.uml2.common.util.CacheAdapter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2004, 2014 IBM Corporation, Embarcadero Technologies, CEA, 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:
 *   IBM - initial API and implementation
 *   Kenn Hussey (Embarcadero Technologies) - 204200, 220065
 *   Kenn Hussey - 335125
 *   Christian W. Damus (CEA) - 389632, 332057
 *   Kenn Hussey (CEA) - 418466
 *
 */
package org.eclipse.uml2.common.util;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;

public class CacheAdapter
		extends ECrossReferenceAdapter {

	protected class InverseCrossReferencer
			extends ECrossReferenceAdapter.InverseCrossReferencer {

		private static final long serialVersionUID = 1L;

		private URI normalizeURI(URI uri, Resource resourceContext) {
			String fragment = uri.fragment();

			if (fragment != null) {
				int length = fragment.length();

				if (length > 0 && fragment.charAt(0) != '/'
					&& fragment.charAt(length - 1) == '?') {

					int index = fragment.lastIndexOf('?', length - 2);

					if (index > 0) {
						uri = uri.trimFragment().appendFragment(
							fragment.substring(0, index));
					}
				}
			}

			if (uriConverter != null) {
				return uriConverter.normalize(uri);
			} else if (resourceContext != null) {
				ResourceSet resourceSetContext = resourceContext
					.getResourceSet();

				if (resourceSetContext != null) {
					return resourceSetContext.getURIConverter().normalize(uri);
				}
			}

			return uri;
		}

		@Override
		protected URI normalizeURI(URI uri, EObject objectContext) {
			return normalizeURI(uri, objectContext.eResource());
		}

		@Override
		protected void addProxy(EObject proxy, EObject context) {

			if (proxy.eIsProxy()) {

				if (proxyMap == null) {
					proxyMap = createHashMap();
				}

				Resource resource = context.eResource();

				if (resource != null) {
					addAdapter(resource);
				}

				URI uri = normalizeURI(((InternalEObject) proxy).eProxyURI(),
					resource);
				List proxies = proxyMap.get(uri);

				if (proxies == null) {
					proxyMap.put(uri,
						proxies = new BasicEList.FastCompare());
				}

				proxies.add(proxy);
			}
		}

		protected Map> getProxyMap() {
			return Collections.unmodifiableMap(proxyMap);
		}
	}

	private static final CacheAdapter INSTANCE = createCacheAdapter();

	protected static final ThreadLocal THREAD_LOCAL = System
		.getProperty("org.eclipse.uml2.common.util.CacheAdapter.ThreadLocal") != null //$NON-NLS-1$
		? new ThreadLocal() {

			@Override
			protected CacheAdapter initialValue() {
				return createCacheAdapter();
			}

		}
		: null;

	/**
	 * @since 1.7
	 */
	public static CacheAdapter getInstance() {
		return THREAD_LOCAL == null
			? INSTANCE
			: THREAD_LOCAL.get();
	}

	private static CacheAdapter createCacheAdapter() {
		CacheAdapter cacheAdapter = UML2Util
			.loadClassFromSystemProperty("org.eclipse.uml2.common.util.CacheAdapter.INSTANCE"); //$NON-NLS-1$

		if (cacheAdapter != null) {
			return cacheAdapter;
		}

		return new CacheAdapter();
	}

	private final Map>> values = Collections
		.synchronizedMap(this
			.>> createHashMap());

	protected boolean adapting = false;

	private URIConverter uriConverter = null;

	public static CacheAdapter getCacheAdapter(Notifier notifier) {
		List eAdapters = notifier.eAdapters();

		for (int i = 0, size = eAdapters.size(); i < size; i++) {
			Object adapter = eAdapters.get(i);

			if (adapter instanceof CacheAdapter) {
				return (CacheAdapter) adapter;
			}
		}

		return null;
	}

	public CacheAdapter() {
		super();

		unloadedEObjects = Collections.synchronizedMap(this
			. createHashMap());

		unloadedResources = new Set() {

			Map map = new WeakHashMap();

			public boolean add(Resource o) {

				if (map.containsKey(o)) {
					return false;
				}

				map.put(o, null);
				return true;
			}

			public boolean addAll(Collection c) {
				boolean result = false;

				for (Resource resource : c) {

					if (add(resource)) {
						result = true;
					}
				}

				return result;
			}

			public void clear() {
				map.keySet().clear();
			}

			public boolean contains(Object o) {
				return map.keySet().contains(o);
			}

			public boolean containsAll(Collection c) {
				return map.keySet().containsAll(c);
			}

			public boolean isEmpty() {
				return map.keySet().isEmpty();
			}

			public Iterator iterator() {
				return map.keySet().iterator();
			}

			public boolean remove(Object o) {
				return map.keySet().remove(o);
			}

			public boolean removeAll(Collection c) {
				return map.keySet().removeAll(c);
			}

			public boolean retainAll(Collection c) {
				return map.keySet().retainAll(c);
			}

			public int size() {
				return map.keySet().size();
			}

			public Object[] toArray() {
				return map.keySet().toArray();
			}

			public  T[] toArray(T[] a) {
				return map.keySet().toArray(a);
			}
		};
	}

	protected  Map createHashMap() {
		return new HashMap();
	}

	@Override
	protected ECrossReferenceAdapter.InverseCrossReferencer createInverseCrossReferencer() {
		return new InverseCrossReferencer();
	}

	protected boolean addAdapter(EList adapters) {
		int index = adapters.indexOf(this);

		switch (index) {
			case 0 :
				break;
			case -1 :
				adapters.add(0, this);
				return true;
			default :
				adapters.move(0, index);
				break;
		}

		return false;
	}

	public boolean adapt(Notifier notifier) {
		boolean result = false;

		if (notifier != null) {
			adapting = true;
			result = addAdapter(notifier.eAdapters());
			adapting = false;
		}

		return result;
	}

	@Override
	protected void addAdapter(Notifier notifier) {
		addAdapter(notifier.eAdapters());
	}

	protected void addAdapter(EObject eObject) {

		if (eObject != null && !eObject.eIsProxy()) {
			Resource eResource = eObject.eResource();

			if (eResource == null) {
				addAdapter(EcoreUtil.getRootContainer(eObject).eAdapters());
			} else {
				ResourceSet resourceSet = eResource.getResourceSet();

				if (resourceSet == null) {
					addAdapter(eResource.eAdapters());
				} else {
					addAdapter(resourceSet.eAdapters());
				}
			}
		}
	}

	@Override
	public Collection getNonNavigableInverseReferences(
			EObject eObject) {
		addAdapter(eObject);

		return super.getNonNavigableInverseReferences(eObject);
	}

	@Override
	public Collection getInverseReferences(
			EObject eObject) {
		addAdapter(eObject);

		return super.getInverseReferences(eObject);
	}

	public void handleCrossReference(EObject eObject) {
		synchronized (inverseCrossReferencer) {
			inverseCrossReferencer.add(eObject);
		}
	}

	@Override
	protected void handleCrossReference(EReference reference,
			Notification notification) {

		synchronized (inverseCrossReferencer) {
			super.handleCrossReference(reference, notification);
		}
	}

	@Override
	public void setTarget(Notifier target) {

		if (!adapting) {
			synchronized (inverseCrossReferencer) {
				super.setTarget(target);
			}
		}
	}

	@Override
	protected void unsetTarget(EObject target) {
		synchronized (inverseCrossReferencer) {
			super.unsetTarget(target);
		}

		// clear at resource scope iff not unloading
		if (uriConverter == null) {
			clear(target.eResource());
		}
	}

	@Override
	protected void unsetTarget(Resource target) {
		super.unsetTarget(target);

		clear(target);
	}

	@Override
	public void notifyChanged(Notification msg) {
		super.notifyChanged(msg);

		Object notifier = msg.getNotifier();

		if (notifier instanceof Resource) {

			switch (msg.getFeatureID(Resource.class)) {
				case Resource.RESOURCE__CONTENTS : {
					clear();

					if (uriConverter == null) {
						Resource resource = (Resource) notifier;

						if (!resource.isLoaded()) {
							ResourceSet resourceSet = resource.getResourceSet();

							if (resourceSet != null) {
								// cache URI converter during unload
								uriConverter = resourceSet.getURIConverter();
							}
						}
					}

					break;
				}
				case Resource.RESOURCE__IS_LOADED : {

					if (!msg.getNewBooleanValue()) {
						uriConverter = null;
					}

					break;
				}
			}
		} else if (notifier instanceof EObject) {
			// clear at resource scope iff not touch
			if (!msg.isTouch()) {
				clear(((EObject) notifier).eResource());
			}
		}
	}

	public void clear() {
		values.clear();
	}

	public void clear(Resource resource) {
		values.remove(resource);

		if (resource != null) {
			values.remove(null);
		}
	}

	public boolean containsKey(EObject eObject, Object key) {
		return containsKey(null, eObject, key);
	}

	public boolean containsKey(Resource resource, EObject eObject, Object key) {
		Map> resourceMap = values.get(resource);

		if (resourceMap != null) {
			Map eObjectMap = resourceMap.get(eObject);

			if (eObjectMap != null) {
				return eObjectMap.containsKey(key);
			}
		}

		return false;
	}

	public Object get(EObject eObject, Object key) {
		return get(null, eObject, key);
	}

	public Object get(Resource resource, EObject eObject, Object key) {
		Map> resourceMap = values.get(resource);

		if (resourceMap != null) {
			Map eObjectMap = resourceMap.get(eObject);

			if (eObjectMap != null) {
				return eObjectMap.get(key);
			}
		}

		return null;
	}

	public Object put(EObject eObject, Object key, Object value) {
		return put(null, eObject, key, value);
	}

	public Object put(Resource resource, EObject eObject, Object key,
			Object value) {

		if (key == null) {
			throw new IllegalArgumentException(String.valueOf(key));
		}

		if (resource != null) {
			addAdapter(resource);
		}

		Map> resourceMap = values.get(resource);

		if (resourceMap == null) {
			resourceMap = Collections.synchronizedMap(this
				.> createHashMap());

			values.put(resource, resourceMap);
		}

		Map eObjectMap = resourceMap.get(eObject);

		if (eObjectMap == null) {
			eObjectMap = Collections.synchronizedMap(this
				. createHashMap());

			resourceMap.put(eObject, eObjectMap);
		}

		return eObjectMap.put(key, value);
	}

	@Override
	protected boolean resolve() {
		return false;
	}

	@Override
	protected boolean isIncluded(EReference eReference) {
		return super.isIncluded(eReference) && eReference.isChangeable();
	}

	public Map> getProxyMap() {
		return ((InverseCrossReferencer) inverseCrossReferencer).getProxyMap();
	}

	@Override
	protected void resolveProxy(Resource resource, EObject eObject,
			EObject proxy, EStructuralFeature.Setting setting) {
		Resource eResource = setting.getEObject().eResource();

		if (eResource != null
			&& eResource.getResourceSet() == resource.getResourceSet()) {

			super.resolveProxy(resource, eObject, proxy, setting);
		}
	}

	@Override
	protected void selfAdapt(Notification notification) {
		Object notifier = notification.getNotifier();

		if (notifier instanceof Resource
			&& notification.getFeatureID(Resource.class) == Resource.RESOURCE__IS_LOADED) {

			if (notification.getNewBooleanValue()) {
				unloadedResources.remove(notifier);

				for (Notifier child : ((Resource) notifier).getContents()) {
					addAdapter(child);
				}
			} else {
				unloadedResources.add((Resource) notifier);

				synchronized (unloadedEObjects) {
					for (Iterator> i = unloadedEObjects
						.entrySet().iterator(); i.hasNext();) {

						Map.Entry entry = i.next();

						if (entry.getValue() == notifier) {
							i.remove();
							EObject eObject = entry.getKey();

							synchronized (inverseCrossReferencer) {
								Collection settings = inverseCrossReferencer
									.get(eObject);

								if (settings != null) {

									for (EStructuralFeature.Setting setting : settings) {
										((InverseCrossReferencer) inverseCrossReferencer)
											.addProxy(eObject,
												setting.getEObject());
									}
								}
							}
						}
					}
				}
			}
		} else {
			super.selfAdapt(notification);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy