diff --git a/com.avaloq.tools.ddk.xtext.builder/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.xtext.builder/META-INF/MANIFEST.MF index db646e863..d6973206a 100644 --- a/com.avaloq.tools.ddk.xtext.builder/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.xtext.builder/META-INF/MANIFEST.MF @@ -6,6 +6,7 @@ Bundle-Version: 14.2.0.qualifier Bundle-Vendor: Avaloq Group AG Require-Bundle: org.eclipse.xtext.builder, org.eclipse.xtext.ui, + com.avaloq.tools.ddk, com.avaloq.tools.ddk.xtext, org.eclipse.xtext.common.types.ui Bundle-RequiredExecutionEnvironment: JavaSE-17 diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/CurrentDescriptions2.java b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/CurrentDescriptions2.java index ef64b39fb..8a1abac7d 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/CurrentDescriptions2.java +++ b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/CurrentDescriptions2.java @@ -24,10 +24,10 @@ import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; import com.avaloq.tools.ddk.xtext.builder.layered.NullResourceDescriptionsData; -import com.avaloq.tools.ddk.xtext.extensions.DelegatingResourceDescriptionsData; -import com.avaloq.tools.ddk.xtext.extensions.IResourceDescriptionsData; -import com.avaloq.tools.ddk.xtext.extensions.ResourceDescriptions2; +import com.avaloq.tools.ddk.xtext.resource.extensions.DelegatingResourceDescriptionsData; import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptions2; +import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptionsData; +import com.avaloq.tools.ddk.xtext.resource.extensions.ResourceDescriptions2; /** diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/MonitoredClusteringBuilderState.java b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/MonitoredClusteringBuilderState.java index 691c5878b..6d6da1933 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/MonitoredClusteringBuilderState.java +++ b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/MonitoredClusteringBuilderState.java @@ -80,14 +80,17 @@ import com.avaloq.tools.ddk.xtext.builder.tracing.ResourceLinkingMemoryEvent; import com.avaloq.tools.ddk.xtext.builder.tracing.ResourceProcessingEvent; import com.avaloq.tools.ddk.xtext.builder.tracing.ResourceValidationEvent; -import com.avaloq.tools.ddk.xtext.extensions.AbstractResourceDescriptionsData; -import com.avaloq.tools.ddk.xtext.extensions.IResourceDescriptionsData; -import com.avaloq.tools.ddk.xtext.extensions.ResourceDescriptions2; import com.avaloq.tools.ddk.xtext.linking.ILazyLinkingResource2; import com.avaloq.tools.ddk.xtext.resource.AbstractCachingResourceDescriptionManager; import com.avaloq.tools.ddk.xtext.resource.AbstractResourceDescriptionDelta; +import com.avaloq.tools.ddk.xtext.resource.DerivedObjectAssociations; +import com.avaloq.tools.ddk.xtext.resource.FixedCopiedResourceDescription; +import com.avaloq.tools.ddk.xtext.resource.IDerivedObjectAssociationsStore; +import com.avaloq.tools.ddk.xtext.resource.extensions.AbstractResourceDescriptionsData; import com.avaloq.tools.ddk.xtext.resource.extensions.ForwardingResourceDescriptions; import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptions2; +import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptionsData; +import com.avaloq.tools.ddk.xtext.resource.extensions.ResourceDescriptions2; import com.avaloq.tools.ddk.xtext.resource.persistence.DirectLinkingResourceStorageFacade; import com.avaloq.tools.ddk.xtext.scoping.ImplicitReferencesAdapter; import com.avaloq.tools.ddk.xtext.tracing.ITraceSet; diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/DefaultXtextTargetPlatform.java b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/DefaultXtextTargetPlatform.java index 59db2a371..b0f61b7ae 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/DefaultXtextTargetPlatform.java +++ b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/DefaultXtextTargetPlatform.java @@ -20,9 +20,9 @@ import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; import com.avaloq.tools.ddk.xtext.builder.IBinaryModelStore; -import com.avaloq.tools.ddk.xtext.builder.IDerivedObjectAssociationsStore; -import com.avaloq.tools.ddk.xtext.extensions.DelegatingResourceDescriptionsData; -import com.avaloq.tools.ddk.xtext.extensions.IResourceDescriptionsData; +import com.avaloq.tools.ddk.xtext.resource.IDerivedObjectAssociationsStore; +import com.avaloq.tools.ddk.xtext.resource.extensions.DelegatingResourceDescriptionsData; +import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptionsData; import com.google.inject.Inject; diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/IXtextTargetPlatform.java b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/IXtextTargetPlatform.java index 3688548ae..77d63e511 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/IXtextTargetPlatform.java +++ b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/IXtextTargetPlatform.java @@ -17,8 +17,9 @@ import org.eclipse.core.runtime.IProgressMonitor; import com.avaloq.tools.ddk.xtext.builder.IBinaryModelStore; -import com.avaloq.tools.ddk.xtext.builder.IDerivedObjectAssociationsStore; -import com.avaloq.tools.ddk.xtext.extensions.IResourceDescriptionsData; +import com.avaloq.tools.ddk.xtext.builder.layered.DefaultXtextTargetPlatform; +import com.avaloq.tools.ddk.xtext.resource.IDerivedObjectAssociationsStore; +import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptionsData; import com.google.inject.ImplementedBy; diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/NullResourceDescriptionsData.java b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/NullResourceDescriptionsData.java index 68f31124b..91c325b39 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/NullResourceDescriptionsData.java +++ b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/NullResourceDescriptionsData.java @@ -19,8 +19,8 @@ import org.eclipse.xtext.resource.IResourceDescription; import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; -import com.avaloq.tools.ddk.xtext.extensions.DelegatingResourceDescriptionsData; -import com.avaloq.tools.ddk.xtext.extensions.IResourceDescriptionsData; +import com.avaloq.tools.ddk.xtext.resource.extensions.DelegatingResourceDescriptionsData; +import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptionsData; /** diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/NullXtextTargetPlatform.java b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/NullXtextTargetPlatform.java index 8240dfd8e..68e7751b9 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/NullXtextTargetPlatform.java +++ b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/layered/NullXtextTargetPlatform.java @@ -16,8 +16,8 @@ import org.eclipse.core.runtime.IProgressMonitor; import com.avaloq.tools.ddk.xtext.builder.IBinaryModelStore; -import com.avaloq.tools.ddk.xtext.builder.IDerivedObjectAssociationsStore; -import com.avaloq.tools.ddk.xtext.extensions.IResourceDescriptionsData; +import com.avaloq.tools.ddk.xtext.resource.IDerivedObjectAssociationsStore; +import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptionsData; /** diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/DirtyStateAwareResourceDescriptions2.java b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/DirtyStateAwareResourceDescriptions2.java index a061a2324..a6bd39d43 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/DirtyStateAwareResourceDescriptions2.java +++ b/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/DirtyStateAwareResourceDescriptions2.java @@ -25,6 +25,7 @@ import org.eclipse.xtext.ui.notification.IStateChangeEventBroker; import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptions2; +import com.avaloq.tools.ddk.xtext.resource.extensions.ResourceDescriptions2; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; diff --git a/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF index 10dc9f129..634f3e81f 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF @@ -26,7 +26,8 @@ Require-Bundle: com.avaloq.tools.ddk.xtext, org.hamcrest.library, org.slf4j.ext, com.avaloq.tools.ddk.check.runtime.core, - org.eclipse.emf.common + org.eclipse.emf.common, + com.avaloq.tools.ddk Import-Package: org.apache.logging.log4j,org.apache.log4j Export-Package: com.avaloq.tools.ddk.xtext.test, com.avaloq.tools.ddk.xtext.test.contentassist, diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/scoping/AbstractScopingTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/scoping/AbstractScopingTest.java index 7de35a8ce..ad5df858a 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/scoping/AbstractScopingTest.java +++ b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/scoping/AbstractScopingTest.java @@ -56,13 +56,13 @@ import org.eclipse.xtext.util.Triple; import org.eclipse.xtext.xbase.lib.Pair; +import com.avaloq.tools.ddk.caching.Regexps; import com.avaloq.tools.ddk.xtext.linking.AbstractFragmentProvider; import com.avaloq.tools.ddk.xtext.naming.QualifiedNames; import com.avaloq.tools.ddk.xtext.resource.IFingerprintComputer; import com.avaloq.tools.ddk.xtext.scoping.ContainerQuery; import com.avaloq.tools.ddk.xtext.scoping.IDomain; import com.avaloq.tools.ddk.xtext.test.AbstractXtextMarkerBasedTest; -import com.avaloq.tools.ddk.xtext.util.Regexps; import com.google.common.base.Function; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; diff --git a/com.avaloq.tools.ddk.xtext/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.xtext/META-INF/MANIFEST.MF index 506beb20b..3f4c997e8 100644 --- a/com.avaloq.tools.ddk.xtext/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.xtext/META-INF/MANIFEST.MF @@ -13,11 +13,10 @@ Require-Bundle: com.google.guava, org.eclipse.core.runtime, org.eclipse.emf.ecore, org.eclipse.jdt.annotation, + com.avaloq.tools.ddk, org.eclipse.xtext, - org.eclipse.xtext.builder, org.eclipse.xtext.util -Export-Package: com.avaloq.tools.ddk.caching, - com.avaloq.tools.ddk.xtext.build, +Export-Package: com.avaloq.tools.ddk.xtext.build, com.avaloq.tools.ddk.xtext.delegation, com.avaloq.tools.ddk.xtext.documentation, com.avaloq.tools.ddk.xtext.extension, diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/naming/QualifiedNamePattern.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/naming/QualifiedNamePattern.java index 84fc37dfe..c663c7f95 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/naming/QualifiedNamePattern.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/naming/QualifiedNamePattern.java @@ -19,7 +19,7 @@ import org.eclipse.xtext.naming.QualifiedName; -import com.avaloq.tools.ddk.xtext.util.Regexps; +import com.avaloq.tools.ddk.caching.Regexps; import com.google.common.base.Function; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/naming/QualifiedNameSegmentTreeLookup.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/naming/QualifiedNameSegmentTreeLookup.java index f84d9c72e..2fa44f773 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/naming/QualifiedNameSegmentTreeLookup.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/naming/QualifiedNameSegmentTreeLookup.java @@ -10,6 +10,7 @@ *******************************************************************************/ package com.avaloq.tools.ddk.xtext.naming; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -18,8 +19,11 @@ import org.eclipse.xtext.naming.QualifiedName; +import com.avaloq.tools.ddk.caching.CacheManager; import com.avaloq.tools.ddk.caching.CacheStatistics; +import com.avaloq.tools.ddk.caching.ICache; import com.avaloq.tools.ddk.xtext.util.ArrayUtils; +import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -385,6 +389,33 @@ private abstract static class Visitor { private long hits; private long misses; + /** + * Creates a new cache to lookup qualified names. + * + * @param + * the key type + * @param + * the value type + * @param name + * the name of the cache, must not be {@code null} + * @param clazz + * the value class + * @param shareValues + * whether the value array of a node should be shared with its parent if they're equal + * @return the qualified name lookup, never {@code null} + */ + public static QualifiedNameLookup createNameLookupCache(final String name, final Class clazz, final boolean shareValues) { + QualifiedNameLookup cache = new QualifiedNameSegmentTreeLookup(clazz, shareValues); + CacheManager cacheManager = CacheManager.getInstance(); + if (cacheManager.isMonitoringEnabled()) { + ArrayListMultimap>> caches = cacheManager.getCaches(); + synchronized (caches) { + caches.put(name, new WeakReference>(cache)); + } + } + return cache; + } + public QualifiedNameSegmentTreeLookup(final Class elementType, final boolean shareValues) { // NOPMD root = shareValues ? new ValueSharingSegmentNode("") : new SegmentNode(""); //$NON-NLS-1$ //$NON-NLS-2$ init(); diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/DerivedObjectAssociations.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/DerivedObjectAssociations.java similarity index 96% rename from com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/DerivedObjectAssociations.java rename to com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/DerivedObjectAssociations.java index c7213a410..5f2a50e25 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/DerivedObjectAssociations.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/DerivedObjectAssociations.java @@ -1,83 +1,83 @@ -/******************************************************************************* - * Copyright (c) 2018 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.builder; - -import java.util.Collections; -import java.util.Map; -import java.util.Set; - -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - - -/** - * Derived objects associated with resource description. - *

- * Instances of this class are attached to resource descriptions or resource description delta. - *

- *

- * Main purpose of the associations is to manage life cycle of the derived resources. - * Associations enable generators to identify what derived objects (sources) should be dropped. - *

- *

- * There can be many producers of derived objects, where generators executed by builder participants - * are the most common kind. Objects produced by generators may be other sources, but could also be some - * entities specific to the business application of a DSL (i.e. database objects). Derived objects - * could also be valid Xtext resources visible to the builder. Therefore the framework in not trying - * to interpret the information about the derived objects, but stores it grouped by the producer (generator id). - *

- *

- * For simplicity we will refer to all producers of derived objects as to generators. - *

- */ -public class DerivedObjectAssociations { - - private final Map> derivedObjects = Maps.newHashMap(); - - /** - * Adds the association for a derived object created the given generator. - * - * @param generatorType - * an identifier of the generator that created the object, must not be {@code null} - * @param derivedObjectUri - * the URI of the derived object (freely defined by the generator), must not be {@code null} - */ - public void add(final String generatorType, final String derivedObjectUri) { - derivedObjects.computeIfAbsent(generatorType, s -> Sets.newHashSet()).add(derivedObjectUri); - } - - /** - * Returns identifiers of all generators that created derived objects for the given resource. - * - * @return identifiers of generators that created derived objects, never {@code null} - */ - public Set getGeneratorTypes() { - return derivedObjects.keySet(); - } - - /** - * Returns set of derived object URIs for the given generator. - * - * @param generatorType - * the identifier of the generator, must not be {@code null} - * @return set of URIs of derived objects, never {@code null} - */ - public Set getDerivedObjects(final String generatorType) { - return derivedObjects.getOrDefault(generatorType, Collections.emptySet()); - } - - @Override - public String toString() { - return derivedObjects.toString(); - } - -} +/******************************************************************************* + * Copyright (c) 2018 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.resource; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + + +/** + * Derived objects associated with resource description. + *

+ * Instances of this class are attached to resource descriptions or resource description delta. + *

+ *

+ * Main purpose of the associations is to manage life cycle of the derived resources. + * Associations enable generators to identify what derived objects (sources) should be dropped. + *

+ *

+ * There can be many producers of derived objects, where generators executed by builder participants + * are the most common kind. Objects produced by generators may be other sources, but could also be some + * entities specific to the business application of a DSL (i.e. database objects). Derived objects + * could also be valid Xtext resources visible to the builder. Therefore the framework in not trying + * to interpret the information about the derived objects, but stores it grouped by the producer (generator id). + *

+ *

+ * For simplicity we will refer to all producers of derived objects as to generators. + *

+ */ +public class DerivedObjectAssociations { + + private final Map> derivedObjects = Maps.newHashMap(); + + /** + * Adds the association for a derived object created the given generator. + * + * @param generatorType + * an identifier of the generator that created the object, must not be {@code null} + * @param derivedObjectUri + * the URI of the derived object (freely defined by the generator), must not be {@code null} + */ + public void add(final String generatorType, final String derivedObjectUri) { + derivedObjects.computeIfAbsent(generatorType, s -> Sets.newHashSet()).add(derivedObjectUri); + } + + /** + * Returns identifiers of all generators that created derived objects for the given resource. + * + * @return identifiers of generators that created derived objects, never {@code null} + */ + public Set getGeneratorTypes() { + return derivedObjects.keySet(); + } + + /** + * Returns set of derived object URIs for the given generator. + * + * @param generatorType + * the identifier of the generator, must not be {@code null} + * @return set of URIs of derived objects, never {@code null} + */ + public Set getDerivedObjects(final String generatorType) { + return derivedObjects.getOrDefault(generatorType, Collections.emptySet()); + } + + @Override + public String toString() { + return derivedObjects.toString(); + } + +} diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/FixedCopiedResourceDescription.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/FixedCopiedResourceDescription.java similarity index 93% rename from com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/FixedCopiedResourceDescription.java rename to com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/FixedCopiedResourceDescription.java index ec16913c7..b9b204d6d 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/FixedCopiedResourceDescription.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/FixedCopiedResourceDescription.java @@ -1,124 +1,122 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.builder; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.InternalEObject; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.xtext.naming.QualifiedName; -import org.eclipse.xtext.resource.EObjectDescription; -import org.eclipse.xtext.resource.IEObjectDescription; -import org.eclipse.xtext.resource.IReferenceDescription; -import org.eclipse.xtext.resource.IResourceDescription; -import org.eclipse.xtext.resource.impl.AbstractResourceDescription; -import org.eclipse.xtext.resource.impl.EObjectDescriptionLookUp; - -import com.avaloq.tools.ddk.xtext.resource.IDetachableDescription; -import com.avaloq.tools.ddk.xtext.resource.PatternAwareEObjectDescriptionLookUp; -import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescription2; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; - - -/** - * Fix a contract-breaking default implementation ({@link CopiedResourceDescription}) in Xtext 2.0.1. Further use LinkedHashMap instead of HashMap to preserve - * order of user data entries. - * Also the {@link IDetachableDescription} is respected in order to reuse descriptions and computed data where possible. - * This descriptor, like {@link CopiedResourceDescription} should be local to a single build run and never survive that single build cycle. - * Within the build loop, imported names and reference descriptions should never be necessary, thus the original implementation logs an error - * if getImportedNames or getReferenceDescriptions are ever called. - * The ASMD builder calls though getReferenceDescriptions when exporting descriptors to the database, so at the time being we cannot guard this method as we - * would like to. - */ -public class FixedCopiedResourceDescription extends AbstractResourceDescription implements IResourceDescription2 { - - private static final Logger LOG = LogManager.getLogger(FixedCopiedResourceDescription.class); - - private final URI uri; - private final List exported; - - @SuppressWarnings("unchecked") - public FixedCopiedResourceDescription(final IResourceDescription original) { - this.uri = original.getURI(); - this.exported = ImmutableList.copyOf(Iterables.transform(original.getExportedObjects(), from -> { - if (from.getEObjectOrProxy().eIsProxy()) { - return from; - } else if (from instanceof IDetachableDescription) { - return ((IDetachableDescription) from).detach(); - } - InternalEObject result = (InternalEObject) EcoreUtil.create(from.getEClass()); - result.eSetProxyURI(from.getEObjectURI()); - ImmutableMap.Builder userData = ImmutableMap.builder(); - for (final String key : from.getUserDataKeys()) { - userData.put(key, from.getUserData(key)); - } - return EObjectDescription.create(from.getName(), result, userData.build()); - })); - } - - @Override - public URI getURI() { - return uri; - } - - @Override - protected List computeExportedObjects() { - return exported; - } - - @Override - protected EObjectDescriptionLookUp getLookUp() { - if (lookup == null) { - lookup = new PatternAwareEObjectDescriptionLookUp(computeExportedObjects()); - } - return lookup; - } - - @Override - public Iterable getImportedNames() { - IllegalStateException exception = new IllegalStateException("getImportedNames " + getURI()); //$NON-NLS-1$ - LOG.warn(exception, exception); - return Collections.emptyList(); - } - - @Override - public Iterable getReferenceDescriptions() { - return Collections.emptyList(); - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(getClass().getName()); - result.append('@'); - result.append(Integer.toHexString(hashCode())); - - result.append(" (URI: "); //$NON-NLS-1$ - result.append(uri); - result.append(')'); - - return result.toString(); - } - - @Override - public Map> getImportedNamesTypes() { - return Maps.newHashMap(); - } -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.resource; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.resource.EObjectDescription; +import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.resource.IReferenceDescription; +import org.eclipse.xtext.resource.IResourceDescription; +import org.eclipse.xtext.resource.impl.AbstractResourceDescription; +import org.eclipse.xtext.resource.impl.EObjectDescriptionLookUp; + +import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescription2; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; + + +/** + * Fix a contract-breaking default implementation ({@link CopiedResourceDescription}) in Xtext 2.0.1. Further use LinkedHashMap instead of HashMap to preserve + * order of user data entries. + * Also the {@link IDetachableDescription} is respected in order to reuse descriptions and computed data where possible. + * This descriptor, like {@link CopiedResourceDescription} should be local to a single build run and never survive that single build cycle. + * Within the build loop, imported names and reference descriptions should never be necessary, thus the original implementation logs an error + * if getImportedNames or getReferenceDescriptions are ever called. + * The ASMD builder calls though getReferenceDescriptions when exporting descriptors to the database, so at the time being we cannot guard this method as we + * would like to. + */ +public class FixedCopiedResourceDescription extends AbstractResourceDescription implements IResourceDescription2 { + + private static final Logger LOG = LogManager.getLogger(FixedCopiedResourceDescription.class); + + private final URI uri; + private final List exported; + + @SuppressWarnings("unchecked") + public FixedCopiedResourceDescription(final IResourceDescription original) { + this.uri = original.getURI(); + this.exported = ImmutableList.copyOf(Iterables.transform(original.getExportedObjects(), from -> { + if (from.getEObjectOrProxy().eIsProxy()) { + return from; + } else if (from instanceof IDetachableDescription) { + return ((IDetachableDescription) from).detach(); + } + InternalEObject result = (InternalEObject) EcoreUtil.create(from.getEClass()); + result.eSetProxyURI(from.getEObjectURI()); + ImmutableMap.Builder userData = ImmutableMap.builder(); + for (final String key : from.getUserDataKeys()) { + userData.put(key, from.getUserData(key)); + } + return EObjectDescription.create(from.getName(), result, userData.build()); + })); + } + + @Override + public URI getURI() { + return uri; + } + + @Override + protected List computeExportedObjects() { + return exported; + } + + @Override + protected EObjectDescriptionLookUp getLookUp() { + if (lookup == null) { + lookup = new PatternAwareEObjectDescriptionLookUp(computeExportedObjects()); + } + return lookup; + } + + @Override + public Iterable getImportedNames() { + IllegalStateException exception = new IllegalStateException("getImportedNames " + getURI()); //$NON-NLS-1$ + LOG.warn(exception, exception); + return Collections.emptyList(); + } + + @Override + public Iterable getReferenceDescriptions() { + return Collections.emptyList(); + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(getClass().getName()); + result.append('@'); + result.append(Integer.toHexString(hashCode())); + + result.append(" (URI: "); //$NON-NLS-1$ + result.append(uri); + result.append(')'); + + return result.toString(); + } + + @Override + public Map> getImportedNamesTypes() { + return Maps.newHashMap(); + } +} diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/GlobalResources.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/GlobalResources.java index 00b37ec26..269e58282 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/GlobalResources.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/GlobalResources.java @@ -25,7 +25,7 @@ *

* The idea is that other resource sets delegate the load operation to {@link #getResource(URI)} for all global resources. *

- * Access the ressources is made threadsafe so that (suspected) lazy adding of ressources does not cause concurrent access errors with existing reads. + * Access the resources is made threadsafe so that (suspected) lazy adding of resources does not cause concurrent access errors with existing reads. */ public final class GlobalResources { diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/IDerivedObjectAssociationsAccess.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/IDerivedObjectAssociationsAccess.java similarity index 95% rename from com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/IDerivedObjectAssociationsAccess.java rename to com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/IDerivedObjectAssociationsAccess.java index d54f2179e..a830a8f1d 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/IDerivedObjectAssociationsAccess.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/IDerivedObjectAssociationsAccess.java @@ -1,48 +1,48 @@ -/******************************************************************************* - * Copyright (c) 2018 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.builder; - -import java.util.Set; - -import org.eclipse.emf.common.util.URI; - - -/** - * Store API for associations between resources processed by the builder and the objects (i.e. sources) - * derived by various providers (i.e. by builder participants) for those resources. - *

- * Read more about associations in {@see DerivedObjectAssociations}. - *

- */ -public interface IDerivedObjectAssociationsAccess { - /** - * Update associated derived artifacts for the given generator and resource. - * - * @param resourceUri - * URI identifying the resource processed by the builder, the URI must be known to the Xtext index - * @param generatorType - * the name of the generator that processed the resource - * @param derivedObjectUris - * URIs identifying the generated objects - */ - void registerAssociations(URI resourceUri, String generatorType, Set derivedObjectUris); - - /** - * Returns associations for objects derived for the given resource identified by a resource URI. - * - * @param resourceUri - * the resource URI, must not be {@code null} - * @return the associations, never {@code null} for existing sources, or {@code null} if the passed URI is not known to the builder - */ - DerivedObjectAssociations getAssociations(URI resourceUri); - -} +/******************************************************************************* + * Copyright (c) 2018 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.resource; + +import java.util.Set; + +import org.eclipse.emf.common.util.URI; + + +/** + * Store API for associations between resources processed by the builder and the objects (i.e. sources) + * derived by various providers (i.e. by builder participants) for those resources. + *

+ * Read more about associations in {@see DerivedObjectAssociations}. + *

+ */ +public interface IDerivedObjectAssociationsAccess { + /** + * Update associated derived artifacts for the given generator and resource. + * + * @param resourceUri + * URI identifying the resource processed by the builder, the URI must be known to the Xtext index + * @param generatorType + * the name of the generator that processed the resource + * @param derivedObjectUris + * URIs identifying the generated objects + */ + void registerAssociations(URI resourceUri, String generatorType, Set derivedObjectUris); + + /** + * Returns associations for objects derived for the given resource identified by a resource URI. + * + * @param resourceUri + * the resource URI, must not be {@code null} + * @return the associations, never {@code null} for existing sources, or {@code null} if the passed URI is not known to the builder + */ + DerivedObjectAssociations getAssociations(URI resourceUri); + +} diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/IDerivedObjectAssociationsStore.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/IDerivedObjectAssociationsStore.java similarity index 94% rename from com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/IDerivedObjectAssociationsStore.java rename to com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/IDerivedObjectAssociationsStore.java index c8f3c1310..da5cadeed 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/IDerivedObjectAssociationsStore.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/IDerivedObjectAssociationsStore.java @@ -1,35 +1,35 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ - -package com.avaloq.tools.ddk.xtext.builder; - -import java.util.Collection; -import java.util.function.BiConsumer; - -import org.eclipse.emf.common.util.URI; - - -/** - * Store API for associations used as an extension for platform. - */ -public interface IDerivedObjectAssociationsStore extends IDerivedObjectAssociationsAccess { - - /** - * Iterates through a {@link Collection} of {@link URI}s, calling the {@link BiConsumer} {@link derivedObjectAssociations} on each URI. - * - * @param allURIs - * A collection of the URIs for which we wish to retrieve associations - * @param derivedObjectAssociations - * The consumer function that receives URI associations as input - */ - void forEach(Collection allURIs, BiConsumer derivedObjectAssociations); - -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ + +package com.avaloq.tools.ddk.xtext.resource; + +import java.util.Collection; +import java.util.function.BiConsumer; + +import org.eclipse.emf.common.util.URI; + + +/** + * Store API for associations used as an extension for platform. + */ +public interface IDerivedObjectAssociationsStore extends IDerivedObjectAssociationsAccess { + + /** + * Iterates through a {@link Collection} of {@link URI}s, calling the {@link BiConsumer} {@link derivedObjectAssociations} on each URI. + * + * @param allURIs + * A collection of the URIs for which we wish to retrieve associations + * @param derivedObjectAssociations + * The consumer function that receives URI associations as input + */ + void forEach(Collection allURIs, BiConsumer derivedObjectAssociations); + +} diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/IDetachableDescription.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/IDetachableDescription.java index 6b61e4197..ce14d1ac2 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/IDetachableDescription.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/IDetachableDescription.java @@ -25,7 +25,7 @@ * * @param * type of description (one of IResourceDescription, IEObjectDescription, or IReferenceDescription) - * @see com.avaloq.tools.ddk.xtext.builder.IDescriptionCopier + * @see com.avaloq.tools.ddk.xtext.builder.builder.IDescriptionCopier */ public interface IDetachableDescription { diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/PatternAwareEObjectDescriptionLookUp.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/PatternAwareEObjectDescriptionLookUp.java index e75ed8c9b..d9f7979d6 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/PatternAwareEObjectDescriptionLookUp.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/PatternAwareEObjectDescriptionLookUp.java @@ -23,9 +23,9 @@ import org.eclipse.xtext.resource.IEObjectDescription; import org.eclipse.xtext.resource.impl.EObjectDescriptionLookUp; -import com.avaloq.tools.ddk.caching.CacheManager; import com.avaloq.tools.ddk.xtext.naming.QualifiedNameLookup; import com.avaloq.tools.ddk.xtext.naming.QualifiedNamePattern; +import com.avaloq.tools.ddk.xtext.naming.QualifiedNameSegmentTreeLookup; import com.avaloq.tools.ddk.xtext.util.EObjectUtil; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; @@ -92,11 +92,10 @@ protected QualifiedNameLookup getNameToObjectsLookup() { if (nameToObjectsLookup == null) { // CHECKSTYLE:ON with volatile it is ok Iterable allDescriptions = getExportedObjects(); - QualifiedNameLookup localMap = CacheManager.getInstance().createNameLookupCache("PatternAwareEObjectDescriptionLookUp#localMap", IEObjectDescription.class, false); //$NON-NLS-1$ + QualifiedNameLookup localMap = QualifiedNameSegmentTreeLookup.createNameLookupCache("PatternAwareEObjectDescriptionLookUp#localMap", IEObjectDescription.class, false); //$NON-NLS-1$ if (allDescriptions instanceof RandomAccess) { List asList = (List) allDescriptions; - for (int i = 0; i < asList.size(); i++) { - IEObjectDescription description = asList.get(i); + for (IEObjectDescription description : asList) { localMap.put(description.getName().toLowerCase(), description); } } else { diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/ResourceCache.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/ResourceCache.java similarity index 60% rename from com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/ResourceCache.java rename to com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/ResourceCache.java index acf1a4836..da3fcb396 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/ResourceCache.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/ResourceCache.java @@ -1,104 +1,147 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.caching; - -import java.lang.reflect.Field; -import java.util.Map; - -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.xtext.util.OnChangeEvictingCache; -import org.eclipse.xtext.util.OnChangeEvictingCache.CacheAdapter; - - -/** - * A cache whose lifecycle is associated to that of a resource. - * - * @param - * the key type - * @param - * the value type - */ -public class ResourceCache implements ICache, OnChangeEvictingCache.Listener { - - private final OnChangeEvictingCache.CacheAdapter backend; - private final Resource resource; - - ResourceCache(final Resource resource, final boolean addAsListener) { - this.resource = resource; - backend = new OnChangeEvictingCache().getOrCreate(resource); - if (addAsListener) { - backend.addCacheListener(this); - } - } - - /** - * Returns a value from the cache. - * - * @param key - * the key, must not be {@code null} - * @return the value, or {@code null} if not found - */ - public V get(final K key) { - return backend.get(key); - } - - /** - * Stores a value in the cache. - * - * @param key - * the key, must not be {@code null} - * @param value - * the value, may be {@code null} - */ - public void set(final K key, final V value) { - backend.set(key, value); - } - - @Override - @SuppressWarnings("unchecked") - public CacheStatistics getStatistics() { - try { - Field hitsField = backend.getClass().getDeclaredField("hits"); //$NON-NLS-1$ - hitsField.setAccessible(true); - int hits = hitsField.getInt(backend); - - Field missesField = backend.getClass().getDeclaredField("misses"); //$NON-NLS-1$ - missesField.setAccessible(true); - int misses = missesField.getInt(backend); - - Field valuesField = backend.getClass().getDeclaredField("values"); //$NON-NLS-1$ - valuesField.setAccessible(true); - Map values = (Map) valuesField.get(backend); - - return new CacheStatistics(values.size(), hits, misses); - // CHECKSTYLE:OFF If getting statistics fails, we should just return an empty result - } catch (Exception e) { - // CHECKSTYLE:ON - return new CacheStatistics(); - } - } - - @Override - public void onEvict(final CacheAdapter cache) { - // This is needed to make the backend hold a reference to this cache, thus making their lifecycles match - } - - /** - * Checks whether this cache is attached to the given resource. - * - * @param newResource - * the resource to check against, must not me {@code null} - * @return true, if the cache is attached to the resource - */ - public boolean handles(final Resource newResource) { - return resource.equals(newResource); - } -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.resource; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.Map; + +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.util.OnChangeEvictingCache; +import org.eclipse.xtext.util.OnChangeEvictingCache.CacheAdapter; + +import com.avaloq.tools.ddk.caching.CacheManager; +import com.avaloq.tools.ddk.caching.CacheStatistics; +import com.avaloq.tools.ddk.caching.ICache; +import com.google.common.collect.ArrayListMultimap; + + +/** + * A cache whose lifecycle is associated to that of a resource. + * + * @param + * the key type + * @param + * the value type + */ +public class ResourceCache implements ICache, OnChangeEvictingCache.Listener { + + private final OnChangeEvictingCache.CacheAdapter backend; + private final Resource resource; + + /** + * Creates a new cache or retrieves an existing one associated with the given resource. + * + * @param + * the key type + * @param + * the value type + * @param name + * the name of the cache, must not be {@code null} + * @param resource + * the resource to associate the cache with, must not be {@code null} + * @return an existing or a new resource cache instance, never {@code null} + */ + @SuppressWarnings("unchecked") + public static ResourceCache getOrCreateResourceCache(final String name, final Resource resource) { + CacheManager cacheManager = CacheManager.getInstance(); + if (!cacheManager.isMonitoringEnabled()) { + return new ResourceCache(resource, false); + } + + // Encode the resource object hash into the multimap key, so that caches with the same name coming from different resources + // are much less likely to collide (since the hash is not guaranteed to be unique per object, collisions are still possible) + final String key = name + CacheManager.KEY_SEPARATOR + Integer.toHexString(resource.hashCode()); + ArrayListMultimap>> caches = cacheManager.getCaches(); + synchronized (caches) { + for (WeakReference> matchReference : caches.get(key)) { + ICache match = matchReference.get(); + if ((match instanceof ResourceCache) && ((ResourceCache) match).handles(resource)) { + return (ResourceCache) match; + } + } + ResourceCache cache = new ResourceCache(resource, true); + caches.put(key, new WeakReference>(cache)); + return cache; + } + } + + public ResourceCache(final Resource resource, final boolean addAsListener) { + this.resource = resource; + backend = new OnChangeEvictingCache().getOrCreate(resource); + if (addAsListener) { + backend.addCacheListener(this); + } + } + + /** + * Returns a value from the cache. + * + * @param key + * the key, must not be {@code null} + * @return the value, or {@code null} if not found + */ + public V get(final K key) { + return backend.get(key); + } + + /** + * Stores a value in the cache. + * + * @param key + * the key, must not be {@code null} + * @param value + * the value, may be {@code null} + */ + public void set(final K key, final V value) { + backend.set(key, value); + } + + @Override + @SuppressWarnings("unchecked") + public CacheStatistics getStatistics() { + try { + Field hitsField = backend.getClass().getDeclaredField("hits"); //$NON-NLS-1$ + hitsField.setAccessible(true); + int hits = hitsField.getInt(backend); + + Field missesField = backend.getClass().getDeclaredField("misses"); //$NON-NLS-1$ + missesField.setAccessible(true); + int misses = missesField.getInt(backend); + + Field valuesField = backend.getClass().getDeclaredField("values"); //$NON-NLS-1$ + valuesField.setAccessible(true); + Map values = (Map) valuesField.get(backend); + + return new CacheStatistics(values.size(), hits, misses); + // CHECKSTYLE:OFF If getting statistics fails, we should just return an empty result + } catch (Exception e) { + // CHECKSTYLE:ON + return new CacheStatistics(); + } + } + + @Override + public void onEvict(final CacheAdapter cache) { + // This is needed to make the backend hold a reference to this cache, thus making their lifecycles match + } + + /** + * Checks whether this cache is attached to the given resource. + * + * @param newResource + * the resource to check against, must not me {@code null} + * @return true, if the cache is attached to the resource + */ + public boolean handles(final Resource newResource) { + return resource.equals(newResource); + } +} diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/AbstractResourceDescriptionsData.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/AbstractResourceDescriptionsData.java similarity index 94% rename from com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/AbstractResourceDescriptionsData.java rename to com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/AbstractResourceDescriptionsData.java index b0b50a0dc..4cadd966a 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/AbstractResourceDescriptionsData.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/AbstractResourceDescriptionsData.java @@ -1,39 +1,39 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.extensions; - -import java.util.Collections; -import java.util.Map; - -import org.eclipse.emf.common.util.URI; -import org.eclipse.xtext.naming.QualifiedName; -import org.eclipse.xtext.resource.IResourceDescription; -import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; - - -/** - * Unfortunately, {@link ResourceDescriptionsData} does not implement {@link org.eclipse.xtext.resource.IResourceDescriptions IResourceDescriptions}... - */ -public abstract class AbstractResourceDescriptionsData extends ResourceDescriptionsData implements IResourceDescriptionsData { - - public AbstractResourceDescriptionsData() { - this(Collections. emptyList()); - } - - protected AbstractResourceDescriptionsData(final Iterable resourceDescriptions) { - super(resourceDescriptions); - } - - protected AbstractResourceDescriptionsData(final Map resourceDescriptionMap, final Map lookupMap) { - super(resourceDescriptionMap, lookupMap); - } - -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.resource.extensions; + +import java.util.Collections; +import java.util.Map; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.resource.IResourceDescription; +import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; + + +/** + * Unfortunately, {@link ResourceDescriptionsData} does not implement {@link org.eclipse.xtext.resource.IResourceDescriptions IResourceDescriptions}... + */ +public abstract class AbstractResourceDescriptionsData extends ResourceDescriptionsData implements IResourceDescriptionsData { + + public AbstractResourceDescriptionsData() { + this(Collections. emptyList()); + } + + protected AbstractResourceDescriptionsData(final Iterable resourceDescriptions) { + super(resourceDescriptions); + } + + protected AbstractResourceDescriptionsData(final Map resourceDescriptionMap, final Map lookupMap) { + super(resourceDescriptionMap, lookupMap); + } + +} diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/DelegatingResourceDescriptionsData.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/DelegatingResourceDescriptionsData.java similarity index 94% rename from com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/DelegatingResourceDescriptionsData.java rename to com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/DelegatingResourceDescriptionsData.java index 1482ee786..a72f18ea3 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/DelegatingResourceDescriptionsData.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/DelegatingResourceDescriptionsData.java @@ -1,159 +1,158 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.extensions; - -import java.util.Set; - -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.naming.QualifiedName; -import org.eclipse.xtext.resource.IEObjectDescription; -import org.eclipse.xtext.resource.IReferenceDescription; -import org.eclipse.xtext.resource.IResourceDescription; -import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; - -import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptions2; -import com.google.common.collect.Sets; - - -/** - * A {@link ResourceDescriptionsData} that delegates all operations to another {@link ResourceDescriptionsData}. - */ -public class DelegatingResourceDescriptionsData extends AbstractResourceDescriptionsData implements IResourceDescriptionsData { - - private final ResourceDescriptionsData delegate; - private final IResourceDescriptions2 wrapped; - - public DelegatingResourceDescriptionsData(final Iterable descriptions) { - this(new ResourceDescriptionsData(descriptions)); - } - - public DelegatingResourceDescriptionsData(final ResourceDescriptionsData resourceDescriptionsData) { - super(null, null); - delegate = resourceDescriptionsData; - wrapped = new ResourceDescriptions2(delegate); - } - - @Override - public ResourceDescriptionsData copy() { - return new DelegatingResourceDescriptionsData(delegate.copy()); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public Iterable getAllResourceDescriptions() { - return delegate.getAllResourceDescriptions(); - } - - @Override - public IResourceDescription getResourceDescription(final URI uri) { - return delegate.getResourceDescription(uri); - } - - @Override - public void removeDescription(final URI uri) { - delegate.removeDescription(uri); - } - - @Override - public Iterable getExportedObjects() { - return delegate.getExportedObjects(); - } - - @Override - public Iterable getExportedObjects(final EClass type, final QualifiedName qualifiedName, final boolean ignoreCase) { - return delegate.getExportedObjects(type, qualifiedName, ignoreCase); - } - - @Override - public Iterable getExportedObjectsByObject(final EObject object) { - return delegate.getExportedObjectsByObject(object); - } - - @Override - public Iterable getExportedObjectsByType(final EClass type) { - return delegate.getExportedObjectsByType(type); - } - - @Override - protected Iterable getSelectables() { - return delegate.getAllResourceDescriptions(); // delegate.getSelectables is not visible here?! - } - - @Override - public Set getAllURIs() { - return delegate.getAllURIs(); - } - - @Override - public void addDescription(final URI uri, final IResourceDescription newDescription) { - delegate.addDescription(uri, newDescription); - } - - @Override - public Iterable findAllReferencingResources(final Set targetResources, final ReferenceMatchPolicy matchPolicy) { - return wrapped.findAllReferencingResources(targetResources, matchPolicy); - } - - @Override - public Iterable findExactReferencingResources(final Set targetObjects, final ReferenceMatchPolicy matchPolicy) { - return wrapped.findExactReferencingResources(targetObjects, matchPolicy); - } - - @Override - public Iterable findReferencesToObjects(final Set targetObjects) { - return wrapped.findReferencesToObjects(targetObjects); - } - - @Override - public void importData(final Iterable descriptions) { - for (IResourceDescription desc : descriptions) { - delegate.addDescription(desc.getURI(), desc); - } - } - - @Override - public void clear() { - for (URI uri : Sets.newHashSet(delegate.getAllURIs())) { - delegate.removeDescription(uri); - } - } - - @Override - public void beginChanges() { - // No-op. - } - - @Override - public void flushChanges() { - // No-op. - } - - @Override - public void commitChanges() { - // No-op. - } - - @Override - public void rollbackChanges() { - // No-op. - } - - protected ResourceDescriptionsData getDelegate() { - return delegate; - } - -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.resource.extensions; + +import java.util.Set; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.resource.IReferenceDescription; +import org.eclipse.xtext.resource.IResourceDescription; +import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; + +import com.google.common.collect.Sets; + + +/** + * A {@link ResourceDescriptionsData} that delegates all operations to another {@link ResourceDescriptionsData}. + */ +public class DelegatingResourceDescriptionsData extends AbstractResourceDescriptionsData implements IResourceDescriptionsData { + + private final ResourceDescriptionsData delegate; + private final IResourceDescriptions2 wrapped; + + public DelegatingResourceDescriptionsData(final Iterable descriptions) { + this(new ResourceDescriptionsData(descriptions)); + } + + public DelegatingResourceDescriptionsData(final ResourceDescriptionsData resourceDescriptionsData) { + super(null, null); + delegate = resourceDescriptionsData; + wrapped = new ResourceDescriptions2(delegate); + } + + @Override + public ResourceDescriptionsData copy() { + return new DelegatingResourceDescriptionsData(delegate.copy()); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public Iterable getAllResourceDescriptions() { + return delegate.getAllResourceDescriptions(); + } + + @Override + public IResourceDescription getResourceDescription(final URI uri) { + return delegate.getResourceDescription(uri); + } + + @Override + public void removeDescription(final URI uri) { + delegate.removeDescription(uri); + } + + @Override + public Iterable getExportedObjects() { + return delegate.getExportedObjects(); + } + + @Override + public Iterable getExportedObjects(final EClass type, final QualifiedName qualifiedName, final boolean ignoreCase) { + return delegate.getExportedObjects(type, qualifiedName, ignoreCase); + } + + @Override + public Iterable getExportedObjectsByObject(final EObject object) { + return delegate.getExportedObjectsByObject(object); + } + + @Override + public Iterable getExportedObjectsByType(final EClass type) { + return delegate.getExportedObjectsByType(type); + } + + @Override + protected Iterable getSelectables() { + return delegate.getAllResourceDescriptions(); // delegate.getSelectables is not visible here?! + } + + @Override + public Set getAllURIs() { + return delegate.getAllURIs(); + } + + @Override + public void addDescription(final URI uri, final IResourceDescription newDescription) { + delegate.addDescription(uri, newDescription); + } + + @Override + public Iterable findAllReferencingResources(final Set targetResources, final ReferenceMatchPolicy matchPolicy) { + return wrapped.findAllReferencingResources(targetResources, matchPolicy); + } + + @Override + public Iterable findExactReferencingResources(final Set targetObjects, final ReferenceMatchPolicy matchPolicy) { + return wrapped.findExactReferencingResources(targetObjects, matchPolicy); + } + + @Override + public Iterable findReferencesToObjects(final Set targetObjects) { + return wrapped.findReferencesToObjects(targetObjects); + } + + @Override + public void importData(final Iterable descriptions) { + for (IResourceDescription desc : descriptions) { + delegate.addDescription(desc.getURI(), desc); + } + } + + @Override + public void clear() { + for (URI uri : Sets.newHashSet(delegate.getAllURIs())) { + delegate.removeDescription(uri); + } + } + + @Override + public void beginChanges() { + // No-op. + } + + @Override + public void flushChanges() { + // No-op. + } + + @Override + public void commitChanges() { + // No-op. + } + + @Override + public void rollbackChanges() { + // No-op. + } + + protected ResourceDescriptionsData getDelegate() { + return delegate; + } + +} diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/IResourceDescriptionsData.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/IResourceDescriptionsData.java similarity index 92% rename from com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/IResourceDescriptionsData.java rename to com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/IResourceDescriptionsData.java index 29e9a239b..128206627 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/IResourceDescriptionsData.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/IResourceDescriptionsData.java @@ -1,85 +1,83 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.extensions; - -import org.eclipse.emf.common.util.URI; -import org.eclipse.xtext.resource.IResourceDescription; -import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; - -import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptions2; - - -/** - * Marker interface; should be implemented by {@link org.eclipse.xtext.builder.builderState.ResourceDescriptionsData ResourceDescriptionsData}. - */ -public interface IResourceDescriptionsData extends IResourceDescriptions2 { - - /** - * Add a new resource description. - * - * @param uri - * of the resource - * @param newDescription - * the description - */ - void addDescription(URI uri, IResourceDescription newDescription); - - /** - * Remove a resource description. - * - * @param uri - * of the resource whose description shall be removed. - */ - void removeDescription(URI uri); - - /** - * Create a copy of this index. - * - * @return the copied index. - */ - ResourceDescriptionsData copy(); - - /** - * Include all the given resource descriptions into this index, i.e. into the internal resource-description data representation by the one supplied as - * {@link IResourceDescription}s, usually from an externally serialized - * representation. - * - * @param descriptions - * The {@link IResourceDescription}s to add. - */ - void importData(Iterable descriptions); - - /** - * Remove all resource descriptions from this index. - */ - void clear(); - - /** - * Indicate that the index will be changed. Subsequent changes are guaranteed to be permanent only after the next call to {@link commitChanges}. - */ - void beginChanges(); - - /** - * Flushes the currently buffered changes without committing them to make them available to queries within this transaction. The implementation is also - * permitted to make the buffered changes available to queries before this method is called. - */ - void flushChanges(); - - /** - * Make all pending changes in this index permanent. - */ - void commitChanges(); - - /** - * Rollback all pending changes. - */ - void rollbackChanges(); -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.resource.extensions; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.xtext.resource.IResourceDescription; +import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; + + +/** + * Marker interface; should be implemented by {@link org.eclipse.xtext.builder.builderState.ResourceDescriptionsData ResourceDescriptionsData}. + */ +public interface IResourceDescriptionsData extends IResourceDescriptions2 { + + /** + * Add a new resource description. + * + * @param uri + * of the resource + * @param newDescription + * the description + */ + void addDescription(URI uri, IResourceDescription newDescription); + + /** + * Remove a resource description. + * + * @param uri + * of the resource whose description shall be removed. + */ + void removeDescription(URI uri); + + /** + * Create a copy of this index. + * + * @return the copied index. + */ + ResourceDescriptionsData copy(); + + /** + * Include all the given resource descriptions into this index, i.e. into the internal resource-description data representation by the one supplied as + * {@link IResourceDescription}s, usually from an externally serialized + * representation. + * + * @param descriptions + * The {@link IResourceDescription}s to add. + */ + void importData(Iterable descriptions); + + /** + * Remove all resource descriptions from this index. + */ + void clear(); + + /** + * Indicate that the index will be changed. Subsequent changes are guaranteed to be permanent only after the next call to {@link commitChanges}. + */ + void beginChanges(); + + /** + * Flushes the currently buffered changes without committing them to make them available to queries within this transaction. The implementation is also + * permitted to make the buffered changes available to queries before this method is called. + */ + void flushChanges(); + + /** + * Make all pending changes in this index permanent. + */ + void commitChanges(); + + /** + * Rollback all pending changes. + */ + void rollbackChanges(); +} diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/ResourceDescriptions2.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/ResourceDescriptions2.java similarity index 92% rename from com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/ResourceDescriptions2.java rename to com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/ResourceDescriptions2.java index cc24ec015..645910266 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/extensions/ResourceDescriptions2.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/resource/extensions/ResourceDescriptions2.java @@ -1,104 +1,101 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.extensions; - -import java.util.Set; - -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.naming.QualifiedName; -import org.eclipse.xtext.resource.IEObjectDescription; -import org.eclipse.xtext.resource.IReferenceDescription; -import org.eclipse.xtext.resource.IResourceDescription; -import org.eclipse.xtext.resource.IResourceDescriptions; -import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; - -import com.avaloq.tools.ddk.xtext.resource.extensions.IResourceDescriptions2; -import com.avaloq.tools.ddk.xtext.resource.extensions.ResourceDescriptionsUtil; - - -/** - * Wrapper to convert old-style {@link IResourceDescriptions} into new-style {@link IResourceDescriptions2}. The new operations are implemented as simple - * filtered iterations over {@link IResourceDescriptions#getAllResourceDescriptions getAllResourceDescriptions}. - */ -public class ResourceDescriptions2 implements IResourceDescriptions2 { - - private final IResourceDescriptions delegate; - - public ResourceDescriptions2(final IResourceDescriptions data) { - delegate = data; - } - - public ResourceDescriptions2(final ResourceDescriptionsData data) { - delegate = data; - } - - @Override - public Iterable getAllResourceDescriptions() { - return delegate.getAllResourceDescriptions(); - } - - @Override - public IResourceDescription getResourceDescription(final URI normalizedURI) { - return delegate.getResourceDescription(normalizedURI); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public Iterable getExportedObjects() { - return delegate.getExportedObjects(); - } - - @Override - public Iterable getExportedObjects(final EClass type, final QualifiedName name, final boolean ignoreCase) { - return delegate.getExportedObjects(type, name, ignoreCase); - } - - @Override - public Iterable getExportedObjectsByType(final EClass type) { - return delegate.getExportedObjectsByType(type); - } - - @Override - public Iterable getExportedObjectsByObject(final EObject object) { - return delegate.getExportedObjectsByObject(object); - } - - @Override - public Set getAllURIs() { - return ResourceDescriptionsUtil.getAllURIs(delegate); - } - - @Override - public Iterable findAllReferencingResources(final Set targetResources, final ReferenceMatchPolicy matchPolicy) { - return ResourceDescriptionsUtil.findReferencesToResources(delegate, targetResources, matchPolicy); - } - - @Override - public Iterable findExactReferencingResources(final Set targetObjects, final ReferenceMatchPolicy matchPolicy) { - return ResourceDescriptionsUtil.findExactReferencingResources(delegate, targetObjects, matchPolicy); - } - - @Override - public Iterable findReferencesToObjects(final Set targetObjects) { - return ResourceDescriptionsUtil.findReferencesToObjects(delegate, targetObjects); - } - - public Iterable findExactReferencingResources(final Set targetObjects, final boolean matchImportedNames) { - return null; - } - -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.resource.extensions; + +import java.util.Set; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.resource.IReferenceDescription; +import org.eclipse.xtext.resource.IResourceDescription; +import org.eclipse.xtext.resource.IResourceDescriptions; +import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; + + +/** + * Wrapper to convert old-style {@link IResourceDescriptions} into new-style {@link IResourceDescriptions2}. The new operations are implemented as simple + * filtered iterations over {@link IResourceDescriptions#getAllResourceDescriptions getAllResourceDescriptions}. + */ +public class ResourceDescriptions2 implements IResourceDescriptions2 { + + private final IResourceDescriptions delegate; + + public ResourceDescriptions2(final IResourceDescriptions data) { + delegate = data; + } + + public ResourceDescriptions2(final ResourceDescriptionsData data) { + delegate = data; + } + + @Override + public Iterable getAllResourceDescriptions() { + return delegate.getAllResourceDescriptions(); + } + + @Override + public IResourceDescription getResourceDescription(final URI normalizedURI) { + return delegate.getResourceDescription(normalizedURI); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public Iterable getExportedObjects() { + return delegate.getExportedObjects(); + } + + @Override + public Iterable getExportedObjects(final EClass type, final QualifiedName name, final boolean ignoreCase) { + return delegate.getExportedObjects(type, name, ignoreCase); + } + + @Override + public Iterable getExportedObjectsByType(final EClass type) { + return delegate.getExportedObjectsByType(type); + } + + @Override + public Iterable getExportedObjectsByObject(final EObject object) { + return delegate.getExportedObjectsByObject(object); + } + + @Override + public Set getAllURIs() { + return ResourceDescriptionsUtil.getAllURIs(delegate); + } + + @Override + public Iterable findAllReferencingResources(final Set targetResources, final ReferenceMatchPolicy matchPolicy) { + return ResourceDescriptionsUtil.findReferencesToResources(delegate, targetResources, matchPolicy); + } + + @Override + public Iterable findExactReferencingResources(final Set targetObjects, final ReferenceMatchPolicy matchPolicy) { + return ResourceDescriptionsUtil.findExactReferencingResources(delegate, targetObjects, matchPolicy); + } + + @Override + public Iterable findReferencesToObjects(final Set targetObjects) { + return ResourceDescriptionsUtil.findReferencesToObjects(delegate, targetObjects); + } + + public Iterable findExactReferencingResources(final Set targetObjects, final boolean matchImportedNames) { + return null; + } + +} diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/AbstractPolymorphicScopeProvider.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/AbstractPolymorphicScopeProvider.java index b452709a8..d7f44847e 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/AbstractPolymorphicScopeProvider.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/scoping/AbstractPolymorphicScopeProvider.java @@ -38,9 +38,8 @@ import org.eclipse.xtext.scoping.IScope; import org.eclipse.xtext.scoping.impl.AbstractScopeProvider; -import com.avaloq.tools.ddk.caching.CacheManager; -import com.avaloq.tools.ddk.caching.ResourceCache; import com.avaloq.tools.ddk.xtext.naming.QualifiedNames; +import com.avaloq.tools.ddk.xtext.resource.ResourceCache; import com.avaloq.tools.ddk.xtext.scoping.impl.BranchingScope; import com.avaloq.tools.ddk.xtext.scoping.impl.DataFilteringScope; import com.avaloq.tools.ddk.xtext.util.EObjectUtil; @@ -331,7 +330,7 @@ protected List getVisibleContainers(final EObject context, final Res */ protected List getVisibleContainers(final XtextResource resource) { URI uri = resource.getURI(); - final ResourceCache> cache = CacheManager.getInstance().getOrCreateResourceCache("AbstractPolymorphicScopeProvider#visibleContainers", resource); //$NON-NLS-1$ + final ResourceCache> cache = ResourceCache.getOrCreateResourceCache("AbstractPolymorphicScopeProvider#visibleContainers", resource); //$NON-NLS-1$ if (cache != null) { List result = cache.get(uri); if (result != null) { @@ -399,7 +398,7 @@ protected IScope internalGetScope(final EObject context, final ENamedElement nam } } if (result == null && doCache(context, namedElement, scopeName, originalResource)) { - resourceScopeCache = CacheManager.getInstance().getOrCreateResourceCache("AbstractPolymorphicScopeProvider#resourceScopeCache", originalResource); //$NON-NLS-1$ + resourceScopeCache = ResourceCache.getOrCreateResourceCache("AbstractPolymorphicScopeProvider#resourceScopeCache", originalResource); //$NON-NLS-1$ cacheKey = getCacheKey(context, namedElement, scopeName); result = resourceScopeCache.get(cacheKey); } diff --git a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/tracing/ResourceIndexAccessSummaryEvent.java b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/tracing/ResourceIndexAccessSummaryEvent.java similarity index 89% rename from com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/tracing/ResourceIndexAccessSummaryEvent.java rename to com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/tracing/ResourceIndexAccessSummaryEvent.java index cd7d20240..3749e2078 100644 --- a/com.avaloq.tools.ddk.xtext.builder/src/com/avaloq/tools/ddk/xtext/builder/tracing/ResourceIndexAccessSummaryEvent.java +++ b/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/tracing/ResourceIndexAccessSummaryEvent.java @@ -1,34 +1,31 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.builder.tracing; - -import com.avaloq.tools.ddk.xtext.tracing.ResourceEvent; - - -/** - * Event which contains index access statistics for a given resource. This event will typically have a {@link ResourceProcessingEvent} as its parent, but it - * could also be a more specific event like a {@link ResourceValidationEvent}. - */ -public class ResourceIndexAccessSummaryEvent extends ResourceEvent { - - /** - * Creates a new instance of {@link ResourceIndexAccessSummaryEvent}. - * - * @param trigger - * event trigger - * @param data - * event data, where the first data object is expected to be the resource's {@link org.eclipse.emf.common.util.URI} this event pertains to - */ - public ResourceIndexAccessSummaryEvent(final Trigger trigger, final Object... data) { - super(trigger, data); - } - -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.xtext.tracing; + +/** + * Event which contains index access statistics for a given resource. This event will typically have a {@link ResourceProcessingEvent} as its parent, but it + * could also be a more specific event like a {@link ResourceValidationEvent}. + */ +public class ResourceIndexAccessSummaryEvent extends ResourceEvent { + + /** + * Creates a new instance of {@link ResourceIndexAccessSummaryEvent}. + * + * @param trigger + * event trigger + * @param data + * event data, where the first data object is expected to be the resource's {@link org.eclipse.emf.common.util.URI} this event pertains to + */ + public ResourceIndexAccessSummaryEvent(final Trigger trigger, final Object... data) { + super(trigger, data); + } + +} diff --git a/com.avaloq.tools.ddk/.classpath b/com.avaloq.tools.ddk/.classpath new file mode 100644 index 000000000..6d8d0db14 --- /dev/null +++ b/com.avaloq.tools.ddk/.classpath @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/com.avaloq.tools.ddk/.project b/com.avaloq.tools.ddk/.project new file mode 100644 index 000000000..30948ed6b --- /dev/null +++ b/com.avaloq.tools.ddk/.project @@ -0,0 +1,93 @@ + + + com.avaloq.tools.ddk + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + net.sf.eclipsecs.core.CheckstyleBuilder + + + + + net.sourceforge.pmd.eclipse.plugin.pmdBuilder + + + + + edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + net.sourceforge.pmd.eclipse.plugin.pmdNature + net.sf.eclipsecs.core.CheckstyleNature + edu.umd.cs.findbugs.plugin.eclipse.findbugsNature + + + + .checkstyle + 1 + PARENT-1-PROJECT_LOC/ddk-configuration/.checkstyle + + + .fbprefs + 1 + PARENT-1-PROJECT_LOC/ddk-configuration/.fbprefs + + + .pmd + 1 + PARENT-1-PROJECT_LOC/ddk-configuration/.pmd + + + .settings/edu.umd.cs.findbugs.plugin.eclipse.prefs + 1 + PARENT-1-PROJECT_LOC/ddk-configuration/.settings/edu.umd.cs.findbugs.plugin.eclipse.prefs + + + .settings/org.eclipse.core.resources.prefs + 1 + PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.resources.prefs + + + .settings/org.eclipse.core.runtime.prefs + 1 + PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.runtime.prefs + + + .settings/org.eclipse.jdt.core.prefs + 1 + PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.core.prefs + + + .settings/org.eclipse.jdt.ui.prefs + 1 + PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.ui.prefs + + + .settings/org.eclipse.pde.core.prefs + 1 + PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.pde.core.prefs + + + diff --git a/com.avaloq.tools.ddk/.settings/.gitignore b/com.avaloq.tools.ddk/.settings/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/com.avaloq.tools.ddk/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk/META-INF/MANIFEST.MF new file mode 100644 index 000000000..4846c2946 --- /dev/null +++ b/com.avaloq.tools.ddk/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: com.avaloq.tools.ddk +Bundle-SymbolicName: com.avaloq.tools.ddk;singleton:=true +Bundle-Version: 14.2.0.qualifier +Bundle-Vendor: Avaloq Group AG +Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-ActivationPolicy: lazy +Require-Bundle: com.google.guava, + org.apache.commons.lang, + org.eclipse.jdt.annotation, + org.eclipse.core.resources, + org.eclipse.core.runtime +Export-Package: com.avaloq.tools.ddk.caching +Import-Package: org.apache.logging.log4j,org.apache.log4j +Automatic-Module-Name: com.avaloq.tools.ddk + diff --git a/com.avaloq.tools.ddk/build.properties b/com.avaloq.tools.ddk/build.properties new file mode 100644 index 000000000..f9c9c0881 --- /dev/null +++ b/com.avaloq.tools.ddk/build.properties @@ -0,0 +1,8 @@ +# + +bin.includes = .,\ + META-INF/,\ + plugin.xml +jars.compile.order = . +source.. = src/ +output.. = bin/ diff --git a/com.avaloq.tools.ddk/plugin.properties b/com.avaloq.tools.ddk/plugin.properties new file mode 100644 index 000000000..bda3db5bf --- /dev/null +++ b/com.avaloq.tools.ddk/plugin.properties @@ -0,0 +1,4 @@ +# + +pluginName = DDK Xtext +providerName = www.avaloq.com diff --git a/com.avaloq.tools.ddk/plugin.xml b/com.avaloq.tools.ddk/plugin.xml new file mode 100644 index 000000000..43a5daed3 --- /dev/null +++ b/com.avaloq.tools.ddk/plugin.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/com.avaloq.tools.ddk/pom.xml b/com.avaloq.tools.ddk/pom.xml new file mode 100644 index 000000000..42db32f5e --- /dev/null +++ b/com.avaloq.tools.ddk/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + + ddk-parent + com.avaloq.tools.ddk + 14.2.0-SNAPSHOT + ../ddk-parent + + com.avaloq.tools.ddk + com.avaloq.tools.ddk + eclipse-plugin + \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/CacheConfiguration.java b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/CacheConfiguration.java similarity index 96% rename from com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/CacheConfiguration.java rename to com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/CacheConfiguration.java index c9e1623d3..6d4589b6e 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/CacheConfiguration.java +++ b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/CacheConfiguration.java @@ -1,99 +1,99 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.caching; - -/** - * Allows the behaviour of a cache to be configured. - */ -public class CacheConfiguration { - static final int UNSET_INT = -1; - - private boolean arraySize; - private boolean softValues; - private boolean statistics; - - private long cacheSize = UNSET_INT; - private int initialCapacity = UNSET_INT; - - /** - * All values stored in the cache are wrapped as {@link java.lang.ref.SoftReference SoftReference}, allowing them to be garbage collected as necessary. - * - * @return the cache configuration - */ - public CacheConfiguration useSoftValues() { - softValues = true; - return this; - } - - /** - * If enabled, the cache will treat the values as arrays and count their total entries when determining the maximum number of allowed entries. - * - * @return the cache configuration - */ - public CacheConfiguration useArraySize() { - arraySize = true; - return this; - } - - /** - * Enables the collection of statistics for the cache, with a possible performance penalty. - * - * @return the cache configuration - */ - public CacheConfiguration enableStatistics() { - statistics = true; - return this; - } - - /** - * Sets the maximum number of entries that can be stored in the cache, before old entries get evicted. - * - * @param size - * the maximum size - * @return the cache configuration - */ - public CacheConfiguration setMaximumSize(final long size) { - cacheSize = size; - return this; - } - - public boolean isSoftValuesEnabled() { - return softValues; - } - - public boolean isStatisticsEnabled() { - return statistics; - } - - public long getMaximumSize() { - return cacheSize; - } - - public boolean isArraySizeEnabled() { - return arraySize; - } - - /** - * Sets the initial size for the cache. - * - * @param capacity - * the initial capacity - * @return the cache configuration - */ - public CacheConfiguration setInitialCapacity(final int capacity) { - initialCapacity = capacity; - return this; - } - - public int getInitialCapacity() { - return initialCapacity; - } -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.caching; + +/** + * Allows the behaviour of a cache to be configured. + */ +public class CacheConfiguration { + static final int UNSET_INT = -1; + + private boolean arraySize; + private boolean softValues; + private boolean statistics; + + private long cacheSize = UNSET_INT; + private int initialCapacity = UNSET_INT; + + /** + * All values stored in the cache are wrapped as {@link java.lang.ref.SoftReference SoftReference}, allowing them to be garbage collected as necessary. + * + * @return the cache configuration + */ + public CacheConfiguration useSoftValues() { + softValues = true; + return this; + } + + /** + * If enabled, the cache will treat the values as arrays and count their total entries when determining the maximum number of allowed entries. + * + * @return the cache configuration + */ + public CacheConfiguration useArraySize() { + arraySize = true; + return this; + } + + /** + * Enables the collection of statistics for the cache, with a possible performance penalty. + * + * @return the cache configuration + */ + public CacheConfiguration enableStatistics() { + statistics = true; + return this; + } + + /** + * Sets the maximum number of entries that can be stored in the cache, before old entries get evicted. + * + * @param size + * the maximum size + * @return the cache configuration + */ + public CacheConfiguration setMaximumSize(final long size) { + cacheSize = size; + return this; + } + + public boolean isSoftValuesEnabled() { + return softValues; + } + + public boolean isStatisticsEnabled() { + return statistics; + } + + public long getMaximumSize() { + return cacheSize; + } + + public boolean isArraySizeEnabled() { + return arraySize; + } + + /** + * Sets the initial size for the cache. + * + * @param capacity + * the initial capacity + * @return the cache configuration + */ + public CacheConfiguration setInitialCapacity(final int capacity) { + initialCapacity = capacity; + return this; + } + + public int getInitialCapacity() { + return initialCapacity; + } +} diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/CacheManager.java b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/CacheManager.java similarity index 66% rename from com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/CacheManager.java rename to com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/CacheManager.java index f86b31484..736bf0fd1 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/CacheManager.java +++ b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/CacheManager.java @@ -1,312 +1,257 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.caching; - -import java.lang.ref.WeakReference; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeSet; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.eclipse.emf.ecore.resource.Resource; - -import com.avaloq.tools.ddk.xtext.naming.QualifiedNameLookup; -import com.avaloq.tools.ddk.xtext.naming.QualifiedNameSegmentTreeLookup; -import com.google.common.cache.CacheLoader; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Maps; -import com.google.common.util.concurrent.ThreadFactoryBuilder; - - -/** - * Instantiates and keeps track of Caches, allowing statistics to be collected and reported. - */ -public final class CacheManager { - private static final Logger LOGGER = LogManager.getLogger(CacheManager.class); - - private static final class SingletonHolder { - private static CacheManager instance = new CacheManager(); - - public static CacheManager get() { - return instance; - } - } - - private static final int CLEANUP_DELAY = 5; - private static final int REPORT_DELAY = 10; - - private static final int PERCENT = 100; - - private static final String KEY_SEPARATOR = "§"; //$NON-NLS-1$ - - private final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().setDaemon(true).build()); - private final ArrayListMultimap>> caches = ArrayListMultimap.create(); - private final boolean monitoringEnabled; - - private CacheManager() { - monitoringEnabled = Boolean.getBoolean("com.avaloq.tools.ddk.caching.EnableMonitor"); //$NON-NLS-1$ - if (monitoringEnabled) { - threadPool.scheduleWithFixedDelay(referenceCleaner, CLEANUP_DELAY, CLEANUP_DELAY, TimeUnit.SECONDS); - threadPool.scheduleWithFixedDelay(reportPrinter, REPORT_DELAY, REPORT_DELAY, TimeUnit.SECONDS); - } - } - - public static CacheManager getInstance() { - return SingletonHolder.get(); - } - - /** - * Creates a new cache with the default configuration. - * - * @param - * the key type - * @param - * the value type - * @param name - * the name of the cache, must not be {@code null} - * @return a new Cache instance, never {@code null} - */ - @SuppressWarnings("PMD.LooseCoupling") - public MapCache createMapCache(final String name) { - return createMapCache(name, new CacheConfiguration()); - } - - /** - * Creates a new cache with the given configuration. - * - * @param - * the key type - * @param - * the value type - * @param name - * the name of the cache, must not be {@code null} - * @param configuration - * the configuration of the cache instance to be created, must not be {@code null} - * @return a new cache instance, never {@code null} - */ - @SuppressWarnings("PMD.LooseCoupling") - public MapCache createMapCache(final String name, final CacheConfiguration configuration) { - if (monitoringEnabled) { - configuration.enableStatistics(); - } - - MapCache cache = new MapCache(name, configuration); - if (monitoringEnabled) { - synchronized (caches) { - caches.put(name, new WeakReference>(cache)); - } - } - return cache; - } - - /** - * Creates a new cache with the given configuration. - * - * @param - * the key type - * @param - * the value type - * @param name - * the name of the cache, must not be {@code null} - * @param configuration - * the configuration of the cache instance to be created, must not be {@code null} - * @param loader - * the cache loader used to obtain new values - * @return a new cache instance, never {@code null} - */ - @SuppressWarnings("PMD.LooseCoupling") - public MapCache createMapCache(final String name, final CacheConfiguration configuration, final CacheLoader loader) { - if (monitoringEnabled) { - configuration.enableStatistics(); - } - - MapCache cache = new MapCache(name, configuration, loader); - if (monitoringEnabled) { - synchronized (caches) { - caches.put(name, new WeakReference>(cache)); - } - } - return cache; - } - - /** - * Creates a new cache or retrieves an existing one associated with the given resource. - * - * @param - * the key type - * @param - * the value type - * @param name - * the name of the cache, must not be {@code null} - * @param resource - * the resource to associate the cache with, must not be {@code null} - * @return an existing or a new resource cache instance, never {@code null} - */ - @SuppressWarnings("unchecked") - public ResourceCache getOrCreateResourceCache(final String name, final Resource resource) { - if (!monitoringEnabled) { - return new ResourceCache(resource, false); - } - - // Encode the resource object hash into the multimap key, so that caches with the same name coming from different resources - // are much less likely to collide (since the hash is not guaranteed to be unique per object, collisions are still possible) - final String key = name + KEY_SEPARATOR + Integer.toHexString(resource.hashCode()); - synchronized (caches) { - for (WeakReference> matchReference : caches.get(key)) { - ICache match = matchReference.get(); - if ((match instanceof ResourceCache) && ((ResourceCache) match).handles(resource)) { - return (ResourceCache) match; - } - } - ResourceCache cache = new ResourceCache(resource, true); - caches.put(key, new WeakReference>(cache)); - return cache; - } - } - - /** - * Creates a new cache to lookup qualified names. - * - * @param - * the key type - * @param - * the value type - * @param name - * the name of the cache, must not be {@code null} - * @param clazz - * the value class - * @param shareValues - * whether the value array of a node should be shared with its parent if they're equal - * @return the qualified name lookup, never {@code null} - */ - public QualifiedNameLookup createNameLookupCache(final String name, final Class clazz, final boolean shareValues) { - QualifiedNameLookup cache = new QualifiedNameSegmentTreeLookup(clazz, shareValues); - if (monitoringEnabled) { - synchronized (caches) { - caches.put(name, new WeakReference>(cache)); - } - } - return cache; - } - - /** - * Returns the current statistics for the cache with the given name. - * - * @param name - * name of the cache, must not be {@code null} - * @return statistics, never {@code null} - */ - public CacheStatistics getStatistics(final String name) { - CacheStatistics result = new MultiCacheStatistics(); - if (monitoringEnabled) { - synchronized (caches) { - for (WeakReference> reference : caches.get(name)) { - ICache value = reference.get(); - if (value != null) { - result.aggregate(value.getStatistics()); - } - } - } - } - return result; - } - - // Task to print the a cache usage report - @SuppressWarnings("nls") - private final Runnable reportPrinter = new Runnable() { - @Override - public void run() { - Map allStatistics = Maps.newLinkedHashMap(); - synchronized (caches) { - for (String key : new TreeSet(caches.keySet())) { - String name = getCacheNameFromKey(key); - if (!allStatistics.containsKey(name)) { - allStatistics.put(name, new MultiCacheStatistics()); - } - CacheStatistics statistics = allStatistics.get(name); - for (WeakReference> reference : caches.get(key)) { - ICache value = reference.get(); - if (value != null) { - statistics.aggregate(value.getStatistics()); - } - } - } - } - printStatistics(allStatistics); - } - - /** - * Extract the cache name from a (possibly composite) key. - * - * @param key - * the key - * @return the cache name - */ - private String getCacheNameFromKey(final String key) { - int endIndex = key.indexOf(KEY_SEPARATOR); - if (endIndex == -1) { - return key; - } - return key.substring(0, endIndex); - } - - private void printStatistics(final Map allStatistics) { - StringBuilder builder = new StringBuilder("Active caches:\n"); - builder.append(String.format("%70s | %6s | %9s | %9s | %9s | %4s\n", "name", "caches", "items", "hit", "miss", "rate")); - - for (Entry entry : allStatistics.entrySet()) { - final MultiCacheStatistics statistics = entry.getValue(); - builder.append(String.format("%70s | %,6d | %,9d | %,9d | %,9d | %3.0f%%\n", entry.getKey(), statistics.getCacheCounter(), statistics.getEntries(), statistics.getHits(), statistics.getMisses(), statistics.getRatio() - * PERCENT)); - } - - builder.append('\n'); - LOGGER.info(builder.toString()); - } - }; - - // Task to clean the weak references that have been garbage collected - private final Runnable referenceCleaner = new Runnable() { - @Override - public void run() { - synchronized (caches) { - for (Iterator>> iterator = caches.values().iterator(); iterator.hasNext();) { - WeakReference> reference = iterator.next(); - if (reference.get() == null) { - iterator.remove(); - } - } - } - } - }; - - /** - * {@link CacheStatistics} representing the statistics coming from multiple caches. - */ - private final class MultiCacheStatistics extends CacheStatistics { - private int counter; - - @Override - void aggregate(final CacheStatistics statistics) { - counter++; - super.aggregate(statistics); - } - - public int getCacheCounter() { - return counter; - } - } -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.caching; + +import java.lang.ref.WeakReference; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeSet; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.google.common.cache.CacheLoader; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Maps; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + + +/** + * Instantiates and keeps track of Caches, allowing statistics to be collected and reported. + */ +public class CacheManager { + private static final Logger LOGGER = LogManager.getLogger(CacheManager.class); + + private static final class SingletonHolder { + private static CacheManager instance = new CacheManager(); + + public static CacheManager get() { + return instance; + } + } + + private static final int CLEANUP_DELAY = 5; + private static final int REPORT_DELAY = 10; + + private static final int PERCENT = 100; + + public static final String KEY_SEPARATOR = "§"; //$NON-NLS-1$ + + private final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().setDaemon(true).build()); + private final ArrayListMultimap>> caches = ArrayListMultimap.create(); + private final boolean monitoringEnabled; + + protected CacheManager() { + monitoringEnabled = Boolean.getBoolean("com.avaloq.tools.ddk.caching.EnableMonitor"); //$NON-NLS-1$ + if (isMonitoringEnabled()) { + threadPool.scheduleWithFixedDelay(referenceCleaner, CLEANUP_DELAY, CLEANUP_DELAY, TimeUnit.SECONDS); + threadPool.scheduleWithFixedDelay(reportPrinter, REPORT_DELAY, REPORT_DELAY, TimeUnit.SECONDS); + } + } + + public static CacheManager getInstance() { + return SingletonHolder.get(); + } + + /** + * Creates a new cache with the default configuration. + * + * @param + * the key type + * @param + * the value type + * @param name + * the name of the cache, must not be {@code null} + * @return a new Cache instance, never {@code null} + */ + @SuppressWarnings("PMD.LooseCoupling") + public MapCache createMapCache(final String name) { + return createMapCache(name, new CacheConfiguration()); + } + + /** + * Creates a new cache with the given configuration. + * + * @param + * the key type + * @param + * the value type + * @param name + * the name of the cache, must not be {@code null} + * @param configuration + * the configuration of the cache instance to be created, must not be {@code null} + * @return a new cache instance, never {@code null} + */ + @SuppressWarnings("PMD.LooseCoupling") + public MapCache createMapCache(final String name, final CacheConfiguration configuration) { + if (isMonitoringEnabled()) { + configuration.enableStatistics(); + } + + MapCache cache = new MapCache(name, configuration); + if (isMonitoringEnabled()) { + synchronized (getCaches()) { + getCaches().put(name, new WeakReference>(cache)); + } + } + return cache; + } + + /** + * Creates a new cache with the given configuration. + * + * @param + * the key type + * @param + * the value type + * @param name + * the name of the cache, must not be {@code null} + * @param configuration + * the configuration of the cache instance to be created, must not be {@code null} + * @param loader + * the cache loader used to obtain new values + * @return a new cache instance, never {@code null} + */ + @SuppressWarnings("PMD.LooseCoupling") + public MapCache createMapCache(final String name, final CacheConfiguration configuration, final CacheLoader loader) { + if (isMonitoringEnabled()) { + configuration.enableStatistics(); + } + + MapCache cache = new MapCache(name, configuration, loader); + if (isMonitoringEnabled()) { + synchronized (getCaches()) { + getCaches().put(name, new WeakReference>(cache)); + } + } + return cache; + } + + /** + * Returns the current statistics for the cache with the given name. + * + * @param name + * name of the cache, must not be {@code null} + * @return statistics, never {@code null} + */ + public CacheStatistics getStatistics(final String name) { + CacheStatistics result = new MultiCacheStatistics(); + if (isMonitoringEnabled()) { + synchronized (getCaches()) { + for (WeakReference> reference : getCaches().get(name)) { + ICache value = reference.get(); + if (value != null) { + result.aggregate(value.getStatistics()); + } + } + } + } + return result; + } + + public boolean isMonitoringEnabled() { + return monitoringEnabled; + } + + public ArrayListMultimap>> getCaches() { + return caches; + } + + // Task to print the a cache usage report + @SuppressWarnings("nls") + private final Runnable reportPrinter = new Runnable() { + @Override + public void run() { + Map allStatistics = Maps.newLinkedHashMap(); + synchronized (getCaches()) { + for (String key : new TreeSet(getCaches().keySet())) { + String name = getCacheNameFromKey(key); + if (!allStatistics.containsKey(name)) { + allStatistics.put(name, new MultiCacheStatistics()); + } + CacheStatistics statistics = allStatistics.get(name); + for (WeakReference> reference : getCaches().get(key)) { + ICache value = reference.get(); + if (value != null) { + statistics.aggregate(value.getStatistics()); + } + } + } + } + printStatistics(allStatistics); + } + + /** + * Extract the cache name from a (possibly composite) key. + * + * @param key + * the key + * @return the cache name + */ + private String getCacheNameFromKey(final String key) { + int endIndex = key.indexOf(KEY_SEPARATOR); + if (endIndex == -1) { + return key; + } + return key.substring(0, endIndex); + } + + private void printStatistics(final Map allStatistics) { + StringBuilder builder = new StringBuilder("Active caches:\n"); + builder.append(String.format("%70s | %6s | %9s | %9s | %9s | %4s\n", "name", "caches", "items", "hit", "miss", "rate")); + + for (Entry entry : allStatistics.entrySet()) { + final MultiCacheStatistics statistics = entry.getValue(); + builder.append(String.format("%70s | %,6d | %,9d | %,9d | %,9d | %3.0f%%\n", entry.getKey(), statistics.getCacheCounter(), statistics.getEntries(), statistics.getHits(), statistics.getMisses(), statistics.getRatio() + * PERCENT)); + } + + builder.append('\n'); + LOGGER.info(builder.toString()); + } + }; + + // Task to clean the weak references that have been garbage collected + private final Runnable referenceCleaner = new Runnable() { + @Override + public void run() { + synchronized (getCaches()) { + for (Iterator>> iterator = getCaches().values().iterator(); iterator.hasNext();) { + WeakReference> reference = iterator.next(); + if (reference.get() == null) { + iterator.remove(); + } + } + } + } + }; + + /** + * {@link CacheStatistics} representing the statistics coming from multiple caches. + */ + private final class MultiCacheStatistics extends CacheStatistics { + private int counter; + + @Override + void aggregate(final CacheStatistics statistics) { + counter++; + super.aggregate(statistics); + } + + public int getCacheCounter() { + return counter; + } + } +} diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/CacheStatistics.java b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/CacheStatistics.java similarity index 96% rename from com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/CacheStatistics.java rename to com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/CacheStatistics.java index 9a81fc6f8..001e2c002 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/CacheStatistics.java +++ b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/CacheStatistics.java @@ -1,67 +1,67 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.caching; - -/** - * Represents useful statistics of a cache. - */ -public class CacheStatistics { - private long entries; - private long hits; - private long misses; - - public CacheStatistics() { - // Start with empty statistics - } - - public CacheStatistics(final long entries, final long hits, final long misses) { - this.entries = entries; - this.hits = hits; - this.misses = misses; - } - - public long getEntries() { - return entries; - } - - public long getHits() { - return hits; - } - - public long getMisses() { - return misses; - } - - /** - * Returns the hit ratio of the cache. - * - * @return the hit ratio, or zero if no hits or misses were reported. - */ - public double getRatio() { - double total = misses + hits; - if (total == 0) { - return 0; - } - return hits / total; - } - - /** - * Aggregates the given statistics into the current instance. - * - * @param statistics - * the other statistics, must not be {@code null} - */ - void aggregate(final CacheStatistics statistics) { - this.entries += statistics.entries; - this.hits += statistics.hits; - this.misses += statistics.misses; - } -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.caching; + +/** + * Represents useful statistics of a cache. + */ +public class CacheStatistics { + private long entries; + private long hits; + private long misses; + + public CacheStatistics() { + // Start with empty statistics + } + + public CacheStatistics(final long entries, final long hits, final long misses) { + this.entries = entries; + this.hits = hits; + this.misses = misses; + } + + public long getEntries() { + return entries; + } + + public long getHits() { + return hits; + } + + public long getMisses() { + return misses; + } + + /** + * Returns the hit ratio of the cache. + * + * @return the hit ratio, or zero if no hits or misses were reported. + */ + public double getRatio() { + double total = misses + hits; + if (total == 0) { + return 0; + } + return hits / total; + } + + /** + * Aggregates the given statistics into the current instance. + * + * @param statistics + * the other statistics, must not be {@code null} + */ + void aggregate(final CacheStatistics statistics) { + this.entries += statistics.entries; + this.hits += statistics.hits; + this.misses += statistics.misses; + } +} diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/ICache.java b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/ICache.java similarity index 97% rename from com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/ICache.java rename to com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/ICache.java index a62d25581..a0425f5fb 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/ICache.java +++ b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/ICache.java @@ -1,32 +1,32 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.caching; - -/** - * A basic cache capable of providing usage statistics. - * - * @param - * the key type - * @param - * the value type - */ -public interface ICache { - - /** - * Returns the statistics of this cache's usage. - *

- * Note: may not return any useful results if statistics were not enabled in the {@link CacheConfiguration} when the cache was created. - *

- * - * @return the statistics - */ - CacheStatistics getStatistics(); -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.caching; + +/** + * A basic cache capable of providing usage statistics. + * + * @param + * the key type + * @param + * the value type + */ +public interface ICache { + + /** + * Returns the statistics of this cache's usage. + *

+ * Note: may not return any useful results if statistics were not enabled in the {@link CacheConfiguration} when the cache was created. + *

+ * + * @return the statistics + */ + CacheStatistics getStatistics(); +} diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/MapCache.java b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/MapCache.java similarity index 96% rename from com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/MapCache.java rename to com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/MapCache.java index 96fb3cae7..262aaef30 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/caching/MapCache.java +++ b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/MapCache.java @@ -1,159 +1,159 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.caching; - -import java.util.Collection; -import java.util.Map; -import java.util.Set; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.CacheStats; -import com.google.common.cache.Weigher; - - -/** - * Represents a simple map-like cache. - *

- * Note: new instances should be created through {@link CacheManager} - *

- * - * @param - * the key type - * @param - * the value type - */ -public class MapCache implements ICache, Map { - - private final Cache backend; - private final String name; - - MapCache(final String name, final CacheConfiguration config) { - this.name = name; - backend = configure(config).build(); - } - - MapCache(final String name, final CacheConfiguration config, final CacheLoader loader) { - this.name = name; - backend = configure(config).build(loader); - } - - private CacheBuilder configure(final CacheConfiguration config) { - CacheBuilder cacheBuilder = CacheBuilder.newBuilder(); - if (config.isStatisticsEnabled()) { - cacheBuilder.recordStats(); - } - if (config.isSoftValuesEnabled()) { - cacheBuilder.softValues(); - } - if (config.getInitialCapacity() >= 0) { - cacheBuilder.initialCapacity(config.getInitialCapacity()); - } - if (config.getMaximumSize() >= 0) { - if (config.isArraySizeEnabled()) { - cacheBuilder.maximumWeight(config.getMaximumSize()); - cacheBuilder.weigher(new Weigher() { - @Override - public int weigh(final K key, final V value) { - if (value instanceof byte[]) { - return ((byte[]) value).length; - } - throw new IllegalStateException("Using array size is only supported for byte arrays"); //$NON-NLS-1$ - } - }); - } else { - cacheBuilder.maximumSize(config.getMaximumSize()); - } - } - return cacheBuilder; - } - - public String getName() { - return name; - } - - @Override - public CacheStatistics getStatistics() { - CacheStats stats = backend.stats(); - return new CacheStatistics(backend.size(), stats.hitCount(), stats.missCount()); - } - - @Override - public void clear() { - backend.invalidateAll(); - } - - @Override - public V putIfAbsent(final K key, final V value) { - V oldValue = get(key); - if (oldValue == null) { - oldValue = put(key, value); - } - return oldValue; - } - - @Override - public Set keySet() { - return backend.asMap().keySet(); - } - - @Override - public Collection values() { - return backend.asMap().values(); - } - - @Override - public boolean isEmpty() { - return backend.size() == 0; - } - - @Override - public int size() { - return (int) backend.size(); - } - - @Override - public boolean containsKey(final Object key) { - return backend.getIfPresent(key) != null; - } - - @Override - public boolean containsValue(final Object value) { - return backend.asMap().containsValue(value); - } - - @Override - public V get(final Object key) { - return backend.getIfPresent(key); - } - - @Override - public V put(final K key, final V value) { - return backend.asMap().put(key, value); - } - - @Override - public V remove(final Object key) { - return backend.asMap().remove(key); - } - - @Override - public void putAll(final Map m) { - backend.putAll(m); - } - - @Override - public Set> entrySet() { - return backend.asMap().entrySet(); - } - -} +/******************************************************************************* + * Copyright (c) 2016 Avaloq Group AG 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.caching; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.CacheStats; +import com.google.common.cache.Weigher; + + +/** + * Represents a simple map-like cache. + *

+ * Note: new instances should be created through {@link CacheManager} + *

+ * + * @param + * the key type + * @param + * the value type + */ +public class MapCache implements ICache, Map { + + private final Cache backend; + private final String name; + + MapCache(final String name, final CacheConfiguration config) { + this.name = name; + backend = configure(config).build(); + } + + MapCache(final String name, final CacheConfiguration config, final CacheLoader loader) { + this.name = name; + backend = configure(config).build(loader); + } + + private CacheBuilder configure(final CacheConfiguration config) { + CacheBuilder cacheBuilder = CacheBuilder.newBuilder(); + if (config.isStatisticsEnabled()) { + cacheBuilder.recordStats(); + } + if (config.isSoftValuesEnabled()) { + cacheBuilder.softValues(); + } + if (config.getInitialCapacity() >= 0) { + cacheBuilder.initialCapacity(config.getInitialCapacity()); + } + if (config.getMaximumSize() >= 0) { + if (config.isArraySizeEnabled()) { + cacheBuilder.maximumWeight(config.getMaximumSize()); + cacheBuilder.weigher(new Weigher() { + @Override + public int weigh(final K key, final V value) { + if (value instanceof byte[]) { + return ((byte[]) value).length; + } + throw new IllegalStateException("Using array size is only supported for byte arrays"); //$NON-NLS-1$ + } + }); + } else { + cacheBuilder.maximumSize(config.getMaximumSize()); + } + } + return cacheBuilder; + } + + public String getName() { + return name; + } + + @Override + public CacheStatistics getStatistics() { + CacheStats stats = backend.stats(); + return new CacheStatistics(backend.size(), stats.hitCount(), stats.missCount()); + } + + @Override + public void clear() { + backend.invalidateAll(); + } + + @Override + public V putIfAbsent(final K key, final V value) { + V oldValue = get(key); + if (oldValue == null) { + oldValue = put(key, value); + } + return oldValue; + } + + @Override + public Set keySet() { + return backend.asMap().keySet(); + } + + @Override + public Collection values() { + return backend.asMap().values(); + } + + @Override + public boolean isEmpty() { + return backend.size() == 0; + } + + @Override + public int size() { + return (int) backend.size(); + } + + @Override + public boolean containsKey(final Object key) { + return backend.getIfPresent(key) != null; + } + + @Override + public boolean containsValue(final Object value) { + return backend.asMap().containsValue(value); + } + + @Override + public V get(final Object key) { + return backend.getIfPresent(key); + } + + @Override + public V put(final K key, final V value) { + return backend.asMap().put(key, value); + } + + @Override + public V remove(final Object key) { + return backend.asMap().remove(key); + } + + @Override + public void putAll(final Map m) { + backend.putAll(m); + } + + @Override + public Set> entrySet() { + return backend.asMap().entrySet(); + } + +} diff --git a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/Regexps.java b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/Regexps.java similarity index 71% rename from com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/Regexps.java rename to com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/Regexps.java index e13b7e903..62620ae41 100644 --- a/com.avaloq.tools.ddk.xtext/src/com/avaloq/tools/ddk/xtext/util/Regexps.java +++ b/com.avaloq.tools.ddk/src/com/avaloq/tools/ddk/caching/Regexps.java @@ -8,20 +8,18 @@ * Contributors: * Avaloq Group AG - initial API and implementation *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.util; +package com.avaloq.tools.ddk.caching; +import java.util.concurrent.ConcurrentMap; import java.util.regex.Pattern; -import org.eclipse.xtext.util.Pair; -import org.eclipse.xtext.util.SimpleCache; -import org.eclipse.xtext.util.Tuples; - -import com.google.common.base.Function; +import com.google.common.collect.MapMaker; /** * Class containing utility functions for regular expressions. */ +@SuppressWarnings("nls") public final class Regexps { /** Our "glob"-expressions have two wildcard characters, signifying zero or more (*) or zero or one (?) occurrence(s) of any character. */ @@ -39,18 +37,11 @@ private Regexps() { // prevent instantiation } + private record Pair(String glob, Boolean ignoreCase) { + } + /** Cache of already translated glob patterns. */ - private static final SimpleCache, Pattern> GLOB_REGEXP_CACHE = new SimpleCache, Pattern>(new Function, Pattern>() { - @Override - @SuppressWarnings("nls") - public Pattern apply(final Pair from) { - // Escape any special regexp characters except our own WILDCARD characters '*' and '?' - String pattern = GLOB_ESCAPE_PATTERN.matcher(from.getFirst()).replaceAll("\\\\$1"); - pattern = pattern.replace(WILDCARD_ONE, '.'); - pattern = GLOB_WILDCARD_PATTERN.matcher(pattern).replaceAll(".*"); - return from.getSecond() ? Pattern.compile('^' + pattern + '$', Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : Pattern.compile('^' + pattern + '$'); - } - }); + private static final ConcurrentMap GLOB_REGEXP_CACHE = new MapMaker().weakKeys().makeMap(); /** * Returns a regular expression corresponding to the given glob pattern. Case insensitive. @@ -73,7 +64,13 @@ public static Pattern fromGlob(final String glob) { * @return regexp matching glob */ public static Pattern fromGlob(final String glob, final boolean ignoreCase) { - return GLOB_REGEXP_CACHE.get(Tuples.pair(glob, ignoreCase)); + return GLOB_REGEXP_CACHE.computeIfAbsent(new Pair(glob, ignoreCase), from -> { + // Escape any special regexp characters except our own WILDCARD characters '*' and '?' + String pattern = GLOB_ESCAPE_PATTERN.matcher(from.glob()).replaceAll("\\\\$1"); + pattern = pattern.replace(WILDCARD_ONE, '.'); + pattern = GLOB_WILDCARD_PATTERN.matcher(pattern).replaceAll(".*"); + return from.ignoreCase() ? Pattern.compile('^' + pattern + '$', Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : Pattern.compile('^' + pattern + '$'); + }); } } diff --git a/ddk-parent/pom.xml b/ddk-parent/pom.xml index 500f51981..09670739a 100644 --- a/ddk-parent/pom.xml +++ b/ddk-parent/pom.xml @@ -65,6 +65,7 @@ ../com.avaloq.tools.ddk.feature ../com.avaloq.tools.ddk.runtime.source.feature ../com.avaloq.tools.ddk.source.feature + ../com.avaloq.tools.ddk ../com.avaloq.tools.ddk.xtext ../com.avaloq.tools.ddk.xtext.builder ../com.avaloq.tools.ddk.xtext.builder.ui