/*******************************************************************************
* Copyright (c) 2010, 2014 Willink Transformations 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:
* E.D.Willink - Initial API and implementation
* E.D.Willink - Bug 353171
* Christian W. Damus (CEA LIST) - Bug 434554
*******************************************************************************/
package org.eclipse.ocl.pivot.internal.delegate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.common.delegate.VirtualDelegateMapping;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
/**
* DelegateEPackageAdapter extends an EPackage to cache its DelegateDomain
* that supervises installation of OCL annotations from an OCL document.
*/
public class DelegateEPackageAdapter extends AdapterImpl
{
/**
* Return the DelegateEPackageAdapter for ePackage, if there is one, or null if none.
*/
public static @Nullable DelegateEPackageAdapter findAdapter(@NonNull EPackage ePackage) {
return (DelegateEPackageAdapter) EcoreUtil.getAdapter(ePackage.eAdapters(), DelegateEPackageAdapter.class);
}
/**
* Return the DelegateEPackageAdapter for ePackage, creating
* one if necessary.
*/
public static @NonNull DelegateEPackageAdapter getAdapter(@NonNull EPackage ePackage) {
DelegateEPackageAdapter adapter;
EList<Adapter> eAdapters = ePackage.eAdapters();
synchronized (eAdapters) {
adapter = (DelegateEPackageAdapter) EcoreUtil.getAdapter(eAdapters, DelegateEPackageAdapter.class);
if (adapter == null) {
adapter = new DelegateEPackageAdapter();
eAdapters.add(adapter);
}
}
return adapter;
}
/**
* The map from delegateURI to known DelegateDomain. Mappings are established
* lazily by {@link #getDelegateDomain}.
*/
protected /*@LazyNonNull*/ Map<String, DelegateDomain> delegateDomainMap = null;
protected @NonNull DelegateDomain createDelegateDomain(@NonNull String delegateURI) {
EPackage ePackage = ClassUtil.nonNullState(getTarget());
Class<DelegateDomain.Factory.@NonNull Registry> castClass = DelegateDomain.Factory.Registry.class;
DelegateDomain.Factory.@NonNull Registry registry = OCLDelegateDomain.getDelegateResourceSetRegistry(ePackage, castClass, DelegateDomain.Factory.Registry.INSTANCE);
DelegateDomain.Factory factory = registry.getFactory(delegateURI);
if (factory == null) {
factory = OCLDelegateDomainFactory.INSTANCE;
}
return factory.createDelegateDomain(delegateURI, ePackage);
}
/**
* Return all registered delegate domains.
*/
public @NonNull Collection<DelegateDomain> getAllDelegateDomains() {
if (delegateDomainMap == null) {
getDelegateDomains();
}
return delegateDomainMap.values();
}
/**
* Return the DelegateDomain for this package and for delegateURI, returning null it does not exist.
*/
public @Nullable DelegateDomain getDelegateDomain(@NonNull String delegateURI) {
if (delegateDomainMap == null) {
getDelegateDomains();
}
return delegateDomainMap.get(delegateURI);
}
public synchronized @NonNull Map<String, DelegateDomain> getDelegateDomains() {
Map<String, DelegateDomain> delegateDomainMap2 = delegateDomainMap;
if (delegateDomainMap2 == null) {
delegateDomainMap = delegateDomainMap2 = new HashMap<String, DelegateDomain>();
EPackage ePackage = getTarget();
EAnnotation eAnnotation = ePackage.getEAnnotation(EcorePackage.eNS_URI);
if (eAnnotation != null) {
VirtualDelegateMapping registry = VirtualDelegateMapping.getRegistry(ePackage);
EMap<String, String> details = eAnnotation.getDetails();
for (DelegatedBehavior<?, ?, ?> delegatedBehavior : AbstractDelegatedBehavior.getDelegatedBehaviors()) {
String behaviorName = delegatedBehavior.getName();
String delegateURIs = details.get(behaviorName);
if (delegateURIs != null) {
for (StringTokenizer stringTokenizer = new StringTokenizer(delegateURIs); stringTokenizer.hasMoreTokens();) {
@SuppressWarnings("null")@NonNull String delegateURI = stringTokenizer.nextToken();
@SuppressWarnings("null")@NonNull String resolvedURI = registry.resolve(delegateURI);
loadDelegateDomain(resolvedURI);
}
}
}
}
}
return delegateDomainMap2;
}
@Override
public EPackage getTarget() {
return (EPackage) super.getTarget();
}
@Override
public boolean isAdapterForType(Object type) {
return type == DelegateEPackageAdapter.class;
}
/**
* Return the DelegateDomain for this package and for delegateURI, creating one if it does not already exist.
*/
public @NonNull DelegateDomain loadDelegateDomain(@NonNull String delegateURI) {
if (delegateDomainMap == null) {
getDelegateDomains();
}
DelegateDomain delegateDomain = delegateDomainMap.get(delegateURI);
if (delegateDomain == null) {
synchronized (delegateDomainMap) {
delegateDomain = delegateDomainMap.get(delegateURI);
if (delegateDomain == null) {
delegateDomain = createDelegateDomain(delegateURI);
delegateDomainMap.put(delegateURI, delegateDomain);
}
}
}
return delegateDomain;
}
@Override
public void setTarget(Notifier newTarget) {
EPackage resourceSet = (EPackage) newTarget;
super.setTarget(resourceSet);
}
public void unloadDelegates() {
if (delegateDomainMap != null) {
List<DelegateDomain> delegateDomains;
synchronized (delegateDomainMap) {
delegateDomains = new ArrayList<DelegateDomain>(delegateDomainMap.values());
// delegateDomainMap.clear(); -- don't clear else tests fail since registrations do not occur
}
for (DelegateDomain delegateDomain : delegateDomains) {
delegateDomain.reset();
}
}
}
@Override
public void unsetTarget(Notifier oldTarget) {
super.unsetTarget(oldTarget);
unloadDelegates();
}
}