| /* |
| * Copyright (c) 2009-2013, 2016, 2019 Eike Stepper (Loehne, Germany) 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: |
| * Eike Stepper - initial API and implementation |
| * Stefan Winkler - Bug 332912 - Caching subtype-relationships in the CDOPackageRegistry |
| */ |
| package org.eclipse.emf.cdo.internal.common.model; |
| |
| import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; |
| import org.eclipse.emf.cdo.common.model.CDOModelUtil; |
| import org.eclipse.emf.cdo.common.model.CDOPackageInfo; |
| import org.eclipse.emf.cdo.common.model.CDOPackageUnit; |
| import org.eclipse.emf.cdo.common.model.CDOPackageUnit.State; |
| import org.eclipse.emf.cdo.internal.common.bundle.OM; |
| import org.eclipse.emf.cdo.internal.common.messages.Messages; |
| import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; |
| import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry; |
| import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; |
| |
| import org.eclipse.net4j.util.CheckUtil; |
| import org.eclipse.net4j.util.ImplementationError; |
| import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; |
| import org.eclipse.net4j.util.event.EventUtil; |
| import org.eclipse.net4j.util.event.IListener; |
| import org.eclipse.net4j.util.lifecycle.LifecycleException; |
| import org.eclipse.net4j.util.lifecycle.LifecycleState; |
| import org.eclipse.net4j.util.lifecycle.LifecycleUtil; |
| import org.eclipse.net4j.util.om.trace.ContextTracer; |
| |
| import org.eclipse.emf.common.util.Enumerator; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EEnum; |
| import org.eclipse.emf.ecore.EEnumLiteral; |
| import org.eclipse.emf.ecore.EModelElement; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.impl.EPackageRegistryImpl; |
| |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements InternalCDOPackageRegistry |
| { |
| public static final EModelElement[] SYSTEM_ELEMENTS = new EModelElement[10]; |
| |
| private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, CDOPackageRegistryImpl.class); |
| |
| private static final long serialVersionUID = 1L; |
| |
| private static final boolean eagerInternalCaches = false; |
| |
| private boolean replacingDescriptors; |
| |
| private PackageProcessor packageProcessor; |
| |
| private PackageLoader packageLoader; |
| |
| private transient boolean active; |
| |
| @ExcludeFromDump |
| private transient InternalCDOPackageInfo[] packageInfos; |
| |
| @ExcludeFromDump |
| private transient InternalCDOPackageUnit[] packageUnits; |
| |
| @ExcludeFromDump |
| private transient Map<EClass, List<EClass>> subTypes; |
| |
| private Map<Enumerator, EEnumLiteral> enumLiterals = new HashMap<>(); |
| |
| private Set<CDOPackageInfo> visitedPackages = new HashSet<>(); |
| |
| private Map<EPackage, InternalCDOPackageInfo> packageInfoMap = new HashMap<>(); |
| |
| public CDOPackageRegistryImpl() |
| { |
| } |
| |
| @Override |
| public boolean isReplacingDescriptors() |
| { |
| return replacingDescriptors; |
| } |
| |
| @Override |
| public void setReplacingDescriptors(boolean replacingDescriptors) |
| { |
| this.replacingDescriptors = replacingDescriptors; |
| } |
| |
| @Override |
| public PackageProcessor getPackageProcessor() |
| { |
| return packageProcessor; |
| } |
| |
| @Override |
| public void setPackageProcessor(PackageProcessor packageProcessor) |
| { |
| this.packageProcessor = packageProcessor; |
| } |
| |
| @Override |
| public PackageLoader getPackageLoader() |
| { |
| return packageLoader; |
| } |
| |
| @Override |
| public void setPackageLoader(PackageLoader packageLoader) |
| { |
| LifecycleUtil.checkInactive(this); |
| this.packageLoader = packageLoader; |
| } |
| |
| static int lockCount; |
| |
| @Override |
| public Object get(Object key) |
| { |
| LifecycleUtil.checkActive(this); |
| return super.get(key); |
| } |
| |
| @Override |
| public synchronized Set<String> getAllKeys() |
| { |
| LifecycleUtil.checkActive(this); |
| Set<String> result = new HashSet<>(); |
| result.addAll(keySet()); |
| if (delegateRegistry != null) |
| { |
| if (delegateRegistry instanceof InternalCDOPackageRegistry) |
| { |
| result.addAll(((InternalCDOPackageRegistry)delegateRegistry).getAllKeys()); |
| } |
| else |
| { |
| result.addAll(delegateRegistry.keySet()); |
| } |
| } |
| |
| return result; |
| } |
| |
| @Override |
| public synchronized Object getWithDelegation(String nsURI, boolean resolve) |
| { |
| LifecycleUtil.checkActive(this); |
| Object result = getFrom(this, nsURI, resolve); |
| if (result == null && delegateRegistry != null) |
| { |
| result = getFrom(delegateRegistry, nsURI, resolve); |
| } |
| |
| return result; |
| } |
| |
| private static Object getFrom(EPackage.Registry registry, String nsURI, boolean resolve) |
| { |
| if (resolve) |
| { |
| return registry.getEPackage(nsURI); |
| } |
| |
| return registry.get(nsURI); |
| } |
| |
| @Override |
| public synchronized Object basicPut(String nsURI, Object value) |
| { |
| LifecycleUtil.checkActive(this); |
| if (TRACER.isEnabled()) |
| { |
| TRACER.format("Registering {0} --> {1}", nsURI, value); //$NON-NLS-1$ |
| } |
| |
| if (packageProcessor != null) |
| { |
| value = packageProcessor.processPackage(value); |
| } |
| |
| Object oldValue = get(nsURI); |
| if (oldValue instanceof InternalCDOPackageInfo && value instanceof EPackage) |
| { |
| InternalCDOPackageInfo oldPackageInfo = (InternalCDOPackageInfo)oldValue; |
| EPackage newValue = (EPackage)value; |
| if (oldPackageInfo.getEPackage(false) == null) |
| { |
| registerPackageInfo(newValue, oldPackageInfo); |
| oldPackageInfo.getPackageUnit().setState(CDOPackageUnit.State.LOADED); |
| } |
| } |
| else if (oldValue instanceof EPackage && value instanceof InternalCDOPackageInfo) |
| { |
| EPackage oldPackage = (EPackage)oldValue; |
| InternalCDOPackageInfo oldPackageInfo = getPackageInfo(oldPackage); |
| InternalCDOPackageInfo newPackageInfo = (InternalCDOPackageInfo)value; |
| |
| InternalCDOPackageUnit oldPackageUnit = oldPackageInfo.getPackageUnit(); |
| InternalCDOPackageUnit newPackageUnit = newPackageInfo.getPackageUnit(); |
| if (oldPackageUnit.getState() == CDOPackageUnit.State.NEW && newPackageUnit.getState() != CDOPackageUnit.State.NEW) |
| { |
| oldPackageUnit.setState(CDOPackageUnit.State.LOADED); |
| } |
| |
| // Keep old value! |
| return null; |
| } |
| |
| return super.put(nsURI, value); |
| } |
| |
| @Override |
| public synchronized Object put(String nsURI, Object value) |
| { |
| LifecycleUtil.checkActive(this); |
| if (replacingDescriptors && value instanceof EPackage.Descriptor) |
| { |
| EPackage.Descriptor descriptor = (EPackage.Descriptor)value; |
| value = descriptor.getEPackage(); |
| } |
| |
| if (value instanceof EPackage) |
| { |
| EPackage ePackage = (EPackage)value; |
| InternalCDOPackageInfo packageInfo = getPackageInfo(ePackage); |
| if (packageInfo == null) |
| { |
| initPackageUnit(ePackage); |
| return null; |
| } |
| } |
| |
| return basicPut(nsURI, value); |
| } |
| |
| @Override |
| public synchronized Object putEPackage(EPackage ePackage) |
| { |
| LifecycleUtil.checkActive(this); |
| return put(ePackage.getNsURI(), ePackage); |
| } |
| |
| @Override |
| public synchronized void putPackageUnit(InternalCDOPackageUnit packageUnit) |
| { |
| LifecycleUtil.checkActive(this); |
| packageUnit.setPackageRegistry(this); |
| for (InternalCDOPackageInfo packageInfo : packageUnit.getPackageInfos()) |
| { |
| EPackage ePackage = packageInfo.getEPackage(false); |
| if (ePackage != null) |
| { |
| registerPackageInfo(ePackage, packageInfo); |
| basicPut(ePackage.getNsURI(), ePackage); |
| } |
| else |
| { |
| basicPut(packageInfo.getPackageURI(), packageInfo); |
| } |
| } |
| |
| resetInternalCaches(); |
| } |
| |
| @Override |
| public synchronized void putPackageUnits(InternalCDOPackageUnit[] packageUnits, State state) |
| { |
| LifecycleUtil.checkActive(this); |
| for (InternalCDOPackageUnit packageUnit : packageUnits) |
| { |
| if (state != null) |
| { |
| packageUnit.setState(state); |
| } |
| |
| putPackageUnit(packageUnit); |
| } |
| } |
| |
| @Override |
| public synchronized void registerPackageInfo(EPackage ePackage, InternalCDOPackageInfo packageInfo) |
| { |
| packageInfo.setEPackage(ePackage); |
| packageInfoMap.put(ePackage, packageInfo); |
| } |
| |
| @Override |
| public synchronized InternalCDOPackageInfo getPackageInfo(EPackage ePackage) |
| { |
| LifecycleUtil.checkActive(this); |
| |
| // Looks up a package descriptor in the registry |
| Object object = get(ePackage.getNsURI()); |
| if (object instanceof InternalCDOPackageInfo) |
| { |
| InternalCDOPackageInfo packageInfo = (InternalCDOPackageInfo)object; |
| if (packageInfo.getPackageUnit().getPackageRegistry() == this) |
| { |
| return packageInfo; |
| } |
| } |
| |
| // Looks up a package info in the packageInfoMap |
| return packageInfoMap.get(ePackage); |
| } |
| |
| @Override |
| public synchronized InternalCDOPackageInfo[] getPackageInfos() |
| { |
| LifecycleUtil.checkActive(this); |
| if (packageInfos == null) |
| { |
| List<InternalCDOPackageInfo> result = new ArrayList<>(); |
| for (Object value : values()) |
| { |
| if (value instanceof InternalCDOPackageInfo) |
| { |
| result.add((InternalCDOPackageInfo)value); |
| } |
| else if (value instanceof EPackage) |
| { |
| InternalCDOPackageInfo packageInfo = getPackageInfo((EPackage)value); |
| if (packageInfo != null) |
| { |
| result.add(packageInfo); |
| } |
| } |
| } |
| |
| packageInfos = result.toArray(new InternalCDOPackageInfo[result.size()]); |
| Arrays.sort(packageInfos); |
| } |
| |
| return packageInfos; |
| } |
| |
| @Override |
| public synchronized InternalCDOPackageUnit getPackageUnit(EPackage ePackage) |
| { |
| LifecycleUtil.checkActive(this); |
| CDOPackageInfo packageInfo = getPackageInfo(ePackage); |
| if (packageInfo == null) |
| { |
| putEPackage(ePackage); |
| packageInfo = getPackageInfo(ePackage); |
| if (packageInfo == null) |
| { |
| throw new ImplementationError(MessageFormat.format(Messages.getString("CDOPackageRegistryImpl.0"), ePackage)); //$NON-NLS-1$ |
| } |
| } |
| |
| return (InternalCDOPackageUnit)packageInfo.getPackageUnit(); |
| } |
| |
| @Override |
| public synchronized InternalCDOPackageUnit getPackageUnit(String id) |
| { |
| LifecycleUtil.checkActive(this); |
| for (Object value : values()) |
| { |
| InternalCDOPackageUnit packageUnit = null; |
| if (value instanceof InternalCDOPackageInfo) |
| { |
| packageUnit = ((InternalCDOPackageInfo)value).getPackageUnit(); |
| } |
| else if (value instanceof EPackage) |
| { |
| InternalCDOPackageInfo packageInfo = getPackageInfo((EPackage)value); |
| if (packageInfo != null) |
| { |
| packageUnit = packageInfo.getPackageUnit(); |
| } |
| } |
| |
| if (packageUnit != null && id.equals(packageUnit.getID())) |
| { |
| return packageUnit; |
| } |
| } |
| |
| return null; |
| } |
| |
| @Override |
| public synchronized InternalCDOPackageUnit[] getPackageUnits(long startTime, long endTime) |
| { |
| LifecycleUtil.checkActive(this); |
| if (endTime == CDOBranchPoint.UNSPECIFIED_DATE) |
| { |
| endTime = Long.MAX_VALUE; |
| } |
| |
| Set<InternalCDOPackageUnit> result = new HashSet<>(); |
| for (Object value : values()) |
| { |
| InternalCDOPackageUnit packageUnit = null; |
| if (value instanceof InternalCDOPackageInfo) |
| { |
| packageUnit = ((InternalCDOPackageInfo)value).getPackageUnit(); |
| } |
| else if (value instanceof EPackage) |
| { |
| InternalCDOPackageInfo packageInfo = getPackageInfo((EPackage)value); |
| if (packageInfo != null) |
| { |
| packageUnit = packageInfo.getPackageUnit(); |
| } |
| } |
| |
| if (packageUnit != null) |
| { |
| long timeStamp = packageUnit.getTimeStamp(); |
| if (startTime <= timeStamp && timeStamp <= endTime) |
| { |
| result.add(packageUnit); |
| } |
| } |
| } |
| |
| return result.toArray(new InternalCDOPackageUnit[result.size()]); |
| } |
| |
| @Override |
| public synchronized InternalCDOPackageUnit[] getPackageUnits(boolean withSystemPackages) |
| { |
| LifecycleUtil.checkActive(this); |
| return collectPackageUnits(withSystemPackages); |
| } |
| |
| @Override |
| public synchronized InternalCDOPackageUnit[] getPackageUnits() |
| { |
| LifecycleUtil.checkActive(this); |
| if (packageUnits == null) |
| { |
| packageUnits = collectPackageUnits(true); |
| Arrays.sort(packageUnits); |
| } |
| |
| return packageUnits; |
| } |
| |
| private InternalCDOPackageUnit[] collectPackageUnits(boolean withSystemPackages) |
| { |
| Set<InternalCDOPackageUnit> result = new HashSet<>(); |
| for (Object value : values()) |
| { |
| InternalCDOPackageUnit packageUnit = collectPackageUnit(value); |
| if (packageUnit != null && (withSystemPackages || !packageUnit.isSystem())) |
| { |
| result.add(packageUnit); |
| } |
| } |
| |
| return result.toArray(new InternalCDOPackageUnit[result.size()]); |
| } |
| |
| private InternalCDOPackageUnit collectPackageUnit(Object value) |
| { |
| if (value instanceof InternalCDOPackageInfo) |
| { |
| return ((InternalCDOPackageInfo)value).getPackageUnit(); |
| } |
| |
| if (value instanceof EPackage) |
| { |
| InternalCDOPackageInfo packageInfo = getPackageInfo((EPackage)value); |
| if (packageInfo != null) |
| { |
| InternalCDOPackageUnit packageUnit = packageInfo.getPackageUnit(); |
| return packageUnit; |
| } |
| } |
| |
| return null; |
| } |
| |
| @Override |
| public synchronized EPackage[] getEPackages() |
| { |
| LifecycleUtil.checkActive(this); |
| List<EPackage> result = new ArrayList<>(); |
| for (String packageURI : keySet()) |
| { |
| EPackage ePackage = getEPackage(packageURI); |
| if (ePackage != null) |
| { |
| result.add(ePackage); |
| } |
| } |
| |
| return result.toArray(new EPackage[result.size()]); |
| } |
| |
| @Override |
| public synchronized EEnumLiteral getEnumLiteralFor(Enumerator value) |
| { |
| LifecycleUtil.checkActive(this); |
| EEnumLiteral result = enumLiterals.get(value); |
| if (result != null) |
| { |
| return result; |
| } |
| |
| for (CDOPackageUnit packageUnit : getPackageUnits()) |
| { |
| for (CDOPackageInfo packageInfo : packageUnit.getPackageInfos()) |
| { |
| if (visitedPackages.add(packageInfo)) |
| { |
| result = visitPackage(packageInfo, value); |
| if (result != null) |
| { |
| return result; |
| } |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| private EEnumLiteral visitPackage(CDOPackageInfo packageInfo, Enumerator value) |
| { |
| EEnumLiteral result = null; |
| for (EClassifier classifier : packageInfo.getEPackage().getEClassifiers()) |
| { |
| if (classifier instanceof EEnum) |
| { |
| EEnum eenum = (EEnum)classifier; |
| for (EEnumLiteral eEnumLiteral : eenum.getELiterals()) |
| { |
| Enumerator instance = eEnumLiteral.getInstance(); |
| enumLiterals.put(instance, eEnumLiteral); |
| if (instance == value) |
| { |
| result = eEnumLiteral; |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| @Override |
| public synchronized Map<EClass, List<EClass>> getSubTypes() |
| { |
| LifecycleUtil.checkActive(this); |
| if (subTypes == null) |
| { |
| subTypes = CDOModelUtil.getSubTypes(this); |
| } |
| |
| return subTypes; |
| } |
| |
| @Override |
| public String toString() |
| { |
| return "PackageRegistry"; |
| } |
| |
| @Override |
| public void addListener(IListener listener) |
| { |
| // Do nothing |
| } |
| |
| @Override |
| public void removeListener(IListener listener) |
| { |
| // Do nothing |
| } |
| |
| @Override |
| public IListener[] getListeners() |
| { |
| return EventUtil.NO_LISTENERS; |
| } |
| |
| @Override |
| public boolean hasListeners() |
| { |
| return false; |
| } |
| |
| @Override |
| public synchronized boolean isActive() |
| { |
| return active; |
| } |
| |
| @Override |
| public synchronized LifecycleState getLifecycleState() |
| { |
| return active ? LifecycleState.ACTIVE : LifecycleState.INACTIVE; |
| } |
| |
| @Override |
| public synchronized void activate() throws LifecycleException |
| { |
| if (!active) |
| { |
| CheckUtil.checkState(packageLoader, "packageLoader"); //$NON-NLS-1$ |
| active = true; |
| } |
| } |
| |
| @Override |
| public synchronized Exception deactivate() |
| { |
| if (active) |
| { |
| try |
| { |
| packageInfoMap.clear(); |
| disposePackageUnits(); |
| clear(); |
| active = false; |
| } |
| catch (RuntimeException ex) |
| { |
| return ex; |
| } |
| } |
| |
| return null; |
| } |
| |
| protected void disposePackageUnits() |
| { |
| for (InternalCDOPackageUnit packageUnit : getPackageUnits()) |
| { |
| packageUnit.dispose(); |
| } |
| |
| packageInfos = null; |
| packageUnits = null; |
| subTypes = null; |
| } |
| |
| protected void initPackageUnit(EPackage ePackage) |
| { |
| InternalCDOPackageUnit packageUnit = createPackageUnit(); |
| packageUnit.init(ePackage); |
| resetInternalCaches(); |
| } |
| |
| protected void resetInternalCaches() |
| { |
| packageInfos = null; |
| packageUnits = null; |
| subTypes = null; |
| if (eagerInternalCaches) |
| { |
| getPackageInfos(); |
| getPackageUnits(); |
| getSubTypes(); |
| } |
| } |
| |
| @Override |
| public InternalCDOPackageUnit createPackageUnit() |
| { |
| InternalCDOPackageUnit packageUnit = (InternalCDOPackageUnit)CDOModelUtil.createPackageUnit(); |
| packageUnit.setPackageRegistry(this); |
| return packageUnit; |
| } |
| } |