pax_global_header00006660000000000000000000000064126056046700014520gustar00rootroot0000000000000052 comment=ca67479168e8312d0a021cb76f435a1ee6bbd615 jboss-logmanager-2.0.3.Final/000077500000000000000000000000001260560467000160045ustar00rootroot00000000000000jboss-logmanager-2.0.3.Final/.gitignore000066400000000000000000000001151260560467000177710ustar00rootroot00000000000000*.ipr *.iws *.iml .idea target /test-output /.settings /.project /.classpath jboss-logmanager-2.0.3.Final/LICENSE.txt000066400000000000000000000261351260560467000176360ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.jboss-logmanager-2.0.3.Final/pom.xml000066400000000000000000000132111260560467000173170ustar00rootroot00000000000000 4.0.0 JBoss Log Manager An implementation of java.util.logging.LogManager org.jboss.logmanager jboss-logmanager jar 2.0.3.Final org.jboss jboss-parent 16 Apache License Version 2.0 http://repository.jboss.org/licenses/apache-2.0.txt repo 1.7 1.7 org.jboss.modules jboss-modules 1.3.1.Final provided true junit junit 4.11 test maven-compiler-plugin maven-source-plugin maven-surefire-plugin **/*Tests.java **/SyslogTest.java org.jboss.logmanager.LogManager ${project.build.directory}${file.separator}logs${file.separator} maven-enforcer-plugin maven-jar-plugin ${project.build.outputDirectory}/META-INF/MANIFEST.MF org.apache.felix maven-bundle-plugin 2.1.0 true ${project.groupId}.*;version=${project.version};-split-package:=error bundle-manifest process-classes manifest maven-javadoc-plugin net.gleamynode.apiviz.APIviz org.jboss.apiviz apiviz 1.3.2.GA JBoss LogManager ${project.version}
JBoss LogManager ${project.version}
JBoss LogManager ${project.version}
Copyright © 2015 JBoss, a division of Red Hat, Inc.]]> http://java.sun.com/javase/7/docs/api/
jboss-logmanager-2.0.3.Final/src/000077500000000000000000000000001260560467000165735ustar00rootroot00000000000000jboss-logmanager-2.0.3.Final/src/main/000077500000000000000000000000001260560467000175175ustar00rootroot00000000000000jboss-logmanager-2.0.3.Final/src/main/java/000077500000000000000000000000001260560467000204405ustar00rootroot00000000000000jboss-logmanager-2.0.3.Final/src/main/java/org/000077500000000000000000000000001260560467000212275ustar00rootroot00000000000000jboss-logmanager-2.0.3.Final/src/main/java/org/jboss/000077500000000000000000000000001260560467000223475ustar00rootroot00000000000000jboss-logmanager-2.0.3.Final/src/main/java/org/jboss/logmanager/000077500000000000000000000000001260560467000244635ustar00rootroot00000000000000jboss-logmanager-2.0.3.Final/src/main/java/org/jboss/logmanager/AtomicArray.java000066400000000000000000000353371260560467000275540ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2014 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.logmanager; import java.lang.reflect.Array; import java.util.Arrays; import java.util.Comparator; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.logging.Handler; /** * Utility for snapshot/copy-on-write arrays. To use these methods, two things are required: an immutable array * stored on a volatile field, and an instance of * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater AtomicReferenceFieldUpdater} * which corresponds to that field. Some of these methods perform multi-step operations; if the array field value is * changed in the middle of such an operation, the operation is retried. To avoid spinning, in some situations it * may be advisable to hold a write lock to prevent multiple concurrent updates. * * @param the type which contains the target field * @param the array value type */ final class AtomicArray { private final AtomicReferenceFieldUpdater updater; private final Class componentType; private final V[] emptyArray; /** * Construct an instance. * * @param updater the field updater * @param componentType the component class */ public AtomicArray(AtomicReferenceFieldUpdater updater, Class componentType) { this.updater = updater; this.componentType = componentType; emptyArray = newInstance(componentType, 0); } /** * Convenience method to create an instance. * * @param updater the field updater * @param componentType the component class * @param the type which contains the target field * @param the array value type * @return the new instance */ public static AtomicArray create(AtomicReferenceFieldUpdater updater, Class componentType) { return new AtomicArray(updater, componentType); } /** * Convenience method to set the field value to the empty array. Empty array instances are shared. * * @param instance the instance holding the field */ public void clear(T instance) { updater.set(instance, emptyArray); } /** * Update the value of this array. * * @param instance the instance holding the field * @param value the new value */ public void set(T instance, V[] value) { updater.set(instance, value); } /** * Atomically get and update the value of this array. * * @param instance the instance holding the field * @param value the new value */ public V[] getAndSet(T instance, V[] value) { return updater.getAndSet(instance, value); } @SuppressWarnings({ "unchecked" }) private static V[] copyOf(final Class componentType, V[] old, int newLen) { final V[] target = newInstance(componentType, newLen); System.arraycopy(old, 0, target, 0, Math.min(old.length, newLen)); return target; } /** * Atomically replace the array with a new array which is one element longer, and which includes the given value. * * @param instance the instance holding the field * @param value the updated value */ public void add(T instance, V value) { final AtomicReferenceFieldUpdater updater = this.updater; for (;;) { final V[] oldVal = updater.get(instance); final int oldLen = oldVal.length; final V[] newVal = copyOf(componentType, oldVal, oldLen + 1); newVal[oldLen] = value; if (updater.compareAndSet(instance, oldVal, newVal)) { return; } } } /** * Atomically replace the array with a new array which is one element longer, and which includes the given value, * if the value is not already present within the array. This method does a linear search for the target value. * * @param instance the instance holding the field * @param value the updated value * @param identity {@code true} if comparisons should be done using reference identity, or {@code false} to use the {@code equals()} method * @return {@code true} if the value was added, or {@code false} if it was already present */ public boolean addIfAbsent(T instance, V value, boolean identity) { final AtomicReferenceFieldUpdater updater = this.updater; for (;;) { final V[] oldVal = updater.get(instance); final int oldLen = oldVal.length; if (identity || value == null) { for (int i = 0; i < oldLen; i++) { if (oldVal[i] == value) { return false; } } } else { for (int i = 0; i < oldLen; i++) { if (value.equals(oldVal[i])) { return false; } } } final V[] newVal = copyOf(componentType, oldVal, oldLen + 1); newVal[oldLen] = value; if (updater.compareAndSet(instance, oldVal, newVal)) { return true; } } } /** * Atomically replace the array with a new array which does not include the first occurrance of the given value, if * the value is present in the array. * * @param instance the instance holding the field * @param value the updated value * @param identity {@code true} if comparisons should be done using reference identity, or {@code false} to use the {@code equals()} method * @return {@code true} if the value was removed, or {@code false} if it was not present */ public boolean remove(T instance, V value, boolean identity) { final AtomicReferenceFieldUpdater updater = this.updater; for (;;) { final V[] oldVal = updater.get(instance); final int oldLen = oldVal.length; if (oldLen == 0) { return false; } else { int index = -1; if (identity || value == null) { for (int i = 0; i < oldLen; i++) { if (oldVal[i] == value) { index = i; break; } } } else { for (int i = 0; i < oldLen; i++) { if (value.equals(oldVal[i])) { index = i; break; } } } if (index == -1) { return false; } final V[] newVal = newInstance(componentType, oldLen - 1); System.arraycopy(oldVal, 0, newVal, 0, index); System.arraycopy(oldVal, index + 1, newVal, index, oldLen - index - 1); if (updater.compareAndSet(instance, oldVal, newVal)) { return true; } } } } /** * Atomically replace the array with a new array which does not include any occurrances of the given value, if * the value is present in the array. * * @param instance the instance holding the field * @param value the updated value * @param identity {@code true} if comparisons should be done using reference identity, or {@code false} to use the {@code equals()} method * @return the number of values removed */ public int removeAll(T instance, V value, boolean identity) { final AtomicReferenceFieldUpdater updater = this.updater; for (;;) { final V[] oldVal = updater.get(instance); final int oldLen = oldVal.length; if (oldLen == 0) { return 0; } else { final boolean[] removeSlots = new boolean[oldLen]; int removeCount = 0; if (identity || value == null) { for (int i = 0; i < oldLen; i++) { if (oldVal[i] == value) { removeSlots[i] = true; removeCount++; } } } else { for (int i = 0; i < oldLen; i++) { if (value.equals(oldVal[i])) { removeSlots[i] = true; removeCount++; } } } if (removeCount == 0) { return 0; } final int newLen = oldLen - removeCount; final V[] newVal; if (newLen == 0) { newVal = emptyArray; } else { newVal = newInstance(componentType, newLen); for (int i = 0, j = 0; i < oldLen; i ++) { if (! removeSlots[i]) { newVal[j++] = oldVal[i]; } } } if (updater.compareAndSet(instance, oldVal, newVal)) { return removeCount; } } } } /** * Add a value to a sorted array. Does not check for duplicates. * * @param instance the instance holding the field * @param value the value to add * @param comparator a comparator, or {@code null} to use natural ordering */ public void add(T instance, V value, Comparator comparator) { final AtomicReferenceFieldUpdater updater = this.updater; for (;;) { final V[] oldVal = updater.get(instance); final int oldLen = oldVal.length; final int pos = insertionPoint(Arrays.binarySearch(oldVal, value, comparator)); final V[] newVal = newInstance(componentType, oldLen + 1); System.arraycopy(oldVal, 0, newVal, 0, pos); newVal[pos] = value; System.arraycopy(oldVal, pos, newVal, pos + 1, oldLen - pos); if (updater.compareAndSet(instance, oldVal, newVal)) { return; } } } /** * Add a value to a sorted array if it is not already present. Does not check for duplicates. * * @param instance the instance holding the field * @param value the value to add * @param comparator a comparator, or {@code null} to use natural ordering */ public boolean addIfAbsent(T instance, V value, Comparator comparator) { final AtomicReferenceFieldUpdater updater = this.updater; for (;;) { final V[] oldVal = updater.get(instance); final int oldLen = oldVal.length; final int pos = Arrays.binarySearch(oldVal, value, comparator); if (pos < 0) { return false; } final V[] newVal = newInstance(componentType, oldLen + 1); System.arraycopy(oldVal, 0, newVal, 0, pos); newVal[pos] = value; System.arraycopy(oldVal, pos, newVal, pos + 1, oldLen - pos); if (updater.compareAndSet(instance, oldVal, newVal)) { return true; } } } /** * Remove a value to a sorted array. Does not check for duplicates. If there are multiple occurrances of a value, * there is no guarantee as to which one is removed. * * @param instance the instance holding the field * @param value the value to remove * @param comparator a comparator, or {@code null} to use natural ordering */ public boolean remove(T instance, V value, Comparator comparator) { final AtomicReferenceFieldUpdater updater = this.updater; for (;;) { final V[] oldVal = updater.get(instance); final int oldLen = oldVal.length; if (oldLen == 0) { return false; } else { final int pos = Arrays.binarySearch(oldVal, value, comparator); if (pos < 0) { return false; } final V[] newVal = newInstance(componentType, oldLen - 1); System.arraycopy(oldVal, 0, newVal, 0, pos); System.arraycopy(oldVal, pos + 1, newVal, pos, oldLen - pos - 1); if (updater.compareAndSet(instance, oldVal, newVal)) { return true; } } } } /** * Sort an array. * * @param instance the instance holding the field * @param comparator a comparator, or {@code null} to use natural ordering */ public void sort(T instance, Comparator comparator) { final AtomicReferenceFieldUpdater updater = this.updater; for (;;) { final V[] oldVal = updater.get(instance); if (oldVal.length == 0) { return; } final V[] newVal = oldVal.clone(); Arrays.sort(newVal, comparator); if (updater.compareAndSet(instance, oldVal, newVal)) { return; } } } private static int insertionPoint(int searchResult) { return searchResult > 0 ? searchResult : - (searchResult + 1); } @SuppressWarnings({ "unchecked" }) private static V[] newInstance(Class componentType, int length) { if (componentType == Handler.class) { return (V[]) new Handler[length]; } else if (componentType == Object.class) { return (V[]) new Object[length]; } else { return (V[]) Array.newInstance(componentType, length); } } /** * Compare and set the array. * * @param instance the instance holding the field * @param expect the expected value * @param update the update value * @return {@code true} if the value was updated or {@code false} if the expected value did not match */ public boolean compareAndSet(final T instance, final V[] expect, final V[] update) { return updater.compareAndSet(instance, expect, update); } } jboss-logmanager-2.0.3.Final/src/main/java/org/jboss/logmanager/ClassLoaderLogContextSelector.java000066400000000000000000000205131260560467000332330ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2014 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.logmanager; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.Permission; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentMap; /** * A log context selector which chooses a log context based on the caller's classloader. */ public final class ClassLoaderLogContextSelector implements LogContextSelector { private static final Permission REGISTER_LOG_CONTEXT_PERMISSION = new RuntimePermission("registerLogContext", null); private static final Permission UNREGISTER_LOG_CONTEXT_PERMISSION = new RuntimePermission("unregisterLogContext", null); private static final Permission LOG_API_PERMISSION = new RuntimePermission("logApiPermission", null); /** * Construct a new instance. If no matching log context is found, the provided default selector is consulted. * * @param defaultSelector the selector to consult if no matching log context is found */ public ClassLoaderLogContextSelector(final LogContextSelector defaultSelector) { this(defaultSelector, false); } /** * Construct a new instance. If no matching log context is found, the provided default selector is consulted. *

* If the {@code checkParentClassLoaders} is set to {@code true} this selector recursively searches the class loader * parents until a match is found or a {@code null} parent is found. * * @param defaultSelector the selector to consult if no matching log context is found * @param checkParentClassLoaders {@code true} if the {@link org.jboss.logmanager.LogContext log context} could not * found for the class loader and the {@link ClassLoader#getParent() parent class * loader} should be checked */ public ClassLoaderLogContextSelector(final LogContextSelector defaultSelector, final boolean checkParentClassLoaders) { this.defaultSelector = defaultSelector; this.checkParentClassLoaders = checkParentClassLoaders; } /** * Construct a new instance. If no matching log context is found, the system context is used. */ public ClassLoaderLogContextSelector() { this(false); } /** * Construct a new instance. If no matching log context is found, the system context is used. *

* If the {@code checkParentClassLoaders} is set to {@code true} this selector recursively searches the class loader * parents until a match is found or a {@code null} parent is found. * * @param checkParentClassLoaders {@code true} if the {@link org.jboss.logmanager.LogContext log context} could not * found for the class loader and the {@link ClassLoader#getParent() parent class * loader} should be checked */ public ClassLoaderLogContextSelector(final boolean checkParentClassLoaders) { this(LogContext.DEFAULT_LOG_CONTEXT_SELECTOR, checkParentClassLoaders); } private static final class Gateway extends SecurityManager { protected Class[] getClassContext() { return super.getClassContext(); } } private static final Gateway GATEWAY; static { GATEWAY = AccessController.doPrivileged(new PrivilegedAction() { public Gateway run() { return new Gateway(); } }); } private final LogContextSelector defaultSelector; private final ConcurrentMap contextMap = new CopyOnWriteMap(); private final Set logApiClassLoaders = Collections.newSetFromMap(new CopyOnWriteMap()); private final boolean checkParentClassLoaders; private final PrivilegedAction logContextAction = new PrivilegedAction() { public LogContext run() { for (Class caller : GATEWAY.getClassContext()) { final ClassLoader classLoader = caller.getClassLoader(); final LogContext result = check(classLoader); if (result != null) { return result; } } return defaultSelector.getLogContext(); } private LogContext check(final ClassLoader classLoader) { if (classLoader != null && !logApiClassLoaders.contains(classLoader)) { final LogContext context = contextMap.get(classLoader); if (context != null) { return context; } if (checkParentClassLoaders) { return check(classLoader.getParent()); } } return null; } }; /** * {@inheritDoc} This instance will consult the call stack to see if any calling classloader is associated * with any log context. */ public LogContext getLogContext() { return AccessController.doPrivileged(logContextAction); } /** * Register a class loader which is a known log API, and thus should be skipped over when searching for the * log context to use for the caller class. * * @param apiClassLoader the API class loader * @return {@code true} if this class loader was previously unknown, or {@code false} if it was already registered */ public boolean addLogApiClassLoader(ClassLoader apiClassLoader) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOG_API_PERMISSION); } return logApiClassLoaders.add(apiClassLoader); } /** * Remove a class loader from the known log APIs set. * * @param apiClassLoader the API class loader * @return {@code true} if the class loader was removed, or {@code false} if it was not known to this selector */ public boolean removeLogApiClassLoader(ClassLoader apiClassLoader) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOG_API_PERMISSION); } return logApiClassLoaders.remove(apiClassLoader); } /** * Register a class loader with a log context. This method requires the {@code registerLogContext} {@link RuntimePermission}. * * @param classLoader the classloader * @param logContext the log context * @throws IllegalArgumentException if the classloader is already associated with a log context */ public void registerLogContext(ClassLoader classLoader, LogContext logContext) throws IllegalArgumentException { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(REGISTER_LOG_CONTEXT_PERMISSION); } if (contextMap.putIfAbsent(classLoader, logContext) != null) { throw new IllegalArgumentException("ClassLoader instance is already registered to a log context (" + classLoader + ")"); } } /** * Unregister a class loader/log context association. This method requires the {@code unregisterLogContext} {@link RuntimePermission}. * * @param classLoader the classloader * @param logContext the log context * @return {@code true} if the association exists and was removed, {@code false} otherwise */ public boolean unregisterLogContext(ClassLoader classLoader, LogContext logContext) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(UNREGISTER_LOG_CONTEXT_PERMISSION); } return contextMap.remove(classLoader, logContext); } } jboss-logmanager-2.0.3.Final/src/main/java/org/jboss/logmanager/ConcurrentReferenceHashMap.java000066400000000000000000001750271260560467000325450ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2014 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package org.jboss.logmanager; import java.io.IOException; import java.io.Serializable; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.EnumSet; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; /** * An advanced hash table supporting configurable garbage collection semantics * of keys and values, optional referential-equality, full concurrency of * retrievals, and adjustable expected concurrency for updates. * * This table is designed around specific advanced use-cases. If there is any * doubt whether this table is for you, you most likely should be using * {@link java.util.concurrent.ConcurrentHashMap} instead. * * This table supports strong, weak, and soft keys and values. By default keys * are weak, and values are strong. Such a configuration offers similar behavior * to {@link java.util.WeakHashMap}, entries of this table are periodically * removed once their corresponding keys are no longer referenced outside of * this table. In other words, this table will not prevent a key from being * discarded by the garbage collector. Once a key has been discarded by the * collector, the corresponding entry is no longer visible to this table; * however, the entry may occupy space until a future table operation decides to * reclaim it. For this reason, summary functions such as size and * isEmpty might return a value greater than the observed number of * entries. In order to support a high level of concurrency, stale entries are * only reclaimed during blocking (usually mutating) operations. * * Enabling soft keys allows entries in this table to remain until their space * is absolutely needed by the garbage collector. This is unlike weak keys which * can be reclaimed as soon as they are no longer referenced by a normal strong * reference. The primary use case for soft keys is a cache, which ideally * occupies memory that is not in use for as long as possible. * * By default, values are held using a normal strong reference. This provides * the commonly desired guarantee that a value will always have at least the * same life-span as it's key. For this reason, care should be taken to ensure * that a value never refers, either directly or indirectly, to its key, thereby * preventing reclamation. If this is unavoidable, then it is recommended to use * the same reference type in use for the key. However, it should be noted that * non-strong values may disappear before their corresponding key. * * While this table does allow the use of both strong keys and values, it is * recommended to use {@link java.util.concurrent.ConcurrentHashMap} for such a * configuration, since it is optimized for that case. * * Just like {@link java.util.concurrent.ConcurrentHashMap}, this class obeys * the same functional specification as {@link java.util.Hashtable}, and * includes versions of methods corresponding to each method of * Hashtable. However, even though all operations are thread-safe, * retrieval operations do not entail locking, and there is * not any support for locking the entire table in a way that * prevents all access. This class is fully interoperable with * Hashtable in programs that rely on its thread safety but not on * its synchronization details. * *

* Retrieval operations (including get) generally do not block, so * may overlap with update operations (including put and * remove). Retrievals reflect the results of the most recently * completed update operations holding upon their onset. For * aggregate operations such as putAll and clear, * concurrent retrievals may reflect insertion or removal of only some entries. * Similarly, Iterators and Enumerations return elements reflecting the state of * the hash table at some point at or since the creation of the * iterator/enumeration. They do not throw * {@link ConcurrentModificationException}. However, iterators are designed to * be used by only one thread at a time. * *

* The allowed concurrency among update operations is guided by the optional * concurrencyLevel constructor argument (default 16), * which is used as a hint for internal sizing. The table is internally * partitioned to try to permit the indicated number of concurrent updates * without contention. Because placement in hash tables is essentially random, * the actual concurrency will vary. Ideally, you should choose a value to * accommodate as many threads as will ever concurrently modify the table. Using * a significantly higher value than you need can waste space and time, and a * significantly lower value can lead to thread contention. But overestimates * and underestimates within an order of magnitude do not usually have much * noticeable impact. A value of one is appropriate when it is known that only * one thread will modify and all others will only read. Also, resizing this or * any other kind of hash table is a relatively slow operation, so, when * possible, it is a good idea to provide estimates of expected table sizes in * constructors. * *

* This class and its views and iterators implement all of the optional * methods of the {@link Map} and {@link Iterator} interfaces. * *

* Like {@link Hashtable} but unlike {@link HashMap}, this class does * not allow null to be used as a key or value. * *

* This class is a member of the * Java Collections Framework. * * @author Doug Lea * @author Jason T. Greene * @param the type of keys maintained by this map * @param the type of mapped values */ final class ConcurrentReferenceHashMap extends AbstractMap implements java.util.concurrent.ConcurrentMap, Serializable { private static final long serialVersionUID = 7249069246763182397L; /* * The basic strategy is to subdivide the table among Segments, * each of which itself is a concurrently readable hash table. */ /** * An option specifying which Java reference type should be used to refer * to a key and/or value. */ public static enum ReferenceType { /** Indicates a normal Java strong reference should be used */ STRONG, /** Indicates a {@link WeakReference} should be used */ WEAK, /** Indicates a {@link SoftReference} should be used */ SOFT }; public static enum Option { /** Indicates that referential-equality (== instead of .equals()) should * be used when locating keys. This offers similar behavior to {@link IdentityHashMap} */ IDENTITY_COMPARISONS }; /* ---------------- Constants -------------- */ static final ReferenceType DEFAULT_KEY_TYPE = ReferenceType.WEAK; static final ReferenceType DEFAULT_VALUE_TYPE = ReferenceType.STRONG; /** * The default initial capacity for this table, * used when not otherwise specified in a constructor. */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * The default load factor for this table, used when not * otherwise specified in a constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * The default concurrency level for this table, used when not * otherwise specified in a constructor. */ static final int DEFAULT_CONCURRENCY_LEVEL = 16; /** * The maximum capacity, used if a higher value is implicitly * specified by either of the constructors with arguments. MUST * be a power of two <= 1<<30 to ensure that entries are indexable * using ints. */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * The maximum number of segments to allow; used to bound * constructor arguments. */ static final int MAX_SEGMENTS = 1 << 16; // slightly conservative /** * Number of unsynchronized retries in size and containsValue * methods before resorting to locking. This is used to avoid * unbounded retries if tables undergo continuous modification * which would make it impossible to obtain an accurate result. */ static final int RETRIES_BEFORE_LOCK = 2; /* ---------------- Fields -------------- */ /** * Mask value for indexing into segments. The upper bits of a * key's hash code are used to choose the segment. */ final int segmentMask; /** * Shift value for indexing within segments. */ final int segmentShift; /** * The segments, each of which is a specialized hash table */ final Segment[] segments; boolean identityComparisons; transient Set keySet; transient Set> entrySet; transient Collection values; /* ---------------- Small Utilities -------------- */ /** * Applies a supplemental hash function to a given hashCode, which * defends against poor quality hash functions. This is critical * because ConcurrentReferenceHashMap uses power-of-two length hash tables, * that otherwise encounter collisions for hashCodes that do not * differ in lower or upper bits. */ private static int hash(int h) { // Spread bits to regularize both segment and index locations, // using variant of single-word Wang/Jenkins hash. h += (h << 15) ^ 0xffffcd7d; h ^= (h >>> 10); h += (h << 3); h ^= (h >>> 6); h += (h << 2) + (h << 14); return h ^ (h >>> 16); } /** * Returns the segment that should be used for key with given hash * @param hash the hash code for the key * @return the segment */ final Segment segmentFor(int hash) { return segments[(hash >>> segmentShift) & segmentMask]; } private int hashOf(Object key) { return hash(identityComparisons ? System.identityHashCode(key) : key.hashCode()); } /* ---------------- Inner Classes -------------- */ static interface KeyReference { int keyHash(); Object keyRef(); } /** * A weak-key reference which stores the key hash needed for reclamation. */ static final class WeakKeyReference extends WeakReference implements KeyReference { final int hash; WeakKeyReference(K key, int hash, ReferenceQueue refQueue) { super(key, refQueue); this.hash = hash; } public final int keyHash() { return hash; } public final Object keyRef() { return this; } } /** * A soft-key reference which stores the key hash needed for reclamation. */ static final class SoftKeyReference extends SoftReference implements KeyReference { final int hash; SoftKeyReference(K key, int hash, ReferenceQueue refQueue) { super(key, refQueue); this.hash = hash; } public final int keyHash() { return hash; } public final Object keyRef() { return this; } } static final class WeakValueReference extends WeakReference implements KeyReference { final Object keyRef; final int hash; WeakValueReference(V value, Object keyRef, int hash, ReferenceQueue refQueue) { super(value, refQueue); this.keyRef = keyRef; this.hash = hash; } public final int keyHash() { return hash; } public final Object keyRef() { return keyRef; } } static final class SoftValueReference extends SoftReference implements KeyReference { final Object keyRef; final int hash; SoftValueReference(V value, Object keyRef, int hash, ReferenceQueue refQueue) { super(value, refQueue); this.keyRef = keyRef; this.hash = hash; } public final int keyHash() { return hash; } public final Object keyRef() { return keyRef; } } /** * ConcurrentReferenceHashMap list entry. Note that this is never exported * out as a user-visible Map.Entry. * * Because the value field is volatile, not final, it is legal wrt * the Java Memory Model for an unsynchronized reader to see null * instead of initial value when read via a data race. Although a * reordering leading to this is not likely to ever actually * occur, the Segment.readValueUnderLock method is used as a * backup in case a null (pre-initialized) value is ever seen in * an unsynchronized access method. */ static final class HashEntry { final Object keyRef; final int hash; volatile Object valueRef; final HashEntry next; HashEntry(K key, int hash, HashEntry next, V value, ReferenceType keyType, ReferenceType valueType, ReferenceQueue refQueue) { this.hash = hash; this.next = next; this.keyRef = newKeyReference(key, keyType, refQueue); this.valueRef = newValueReference(value, valueType, refQueue); } final Object newKeyReference(K key, ReferenceType keyType, ReferenceQueue refQueue) { if (keyType == ReferenceType.WEAK) return new WeakKeyReference(key, hash, refQueue); if (keyType == ReferenceType.SOFT) return new SoftKeyReference(key, hash, refQueue); return key; } final Object newValueReference(V value, ReferenceType valueType, ReferenceQueue refQueue) { if (valueType == ReferenceType.WEAK) return new WeakValueReference(value, keyRef, hash, refQueue); if (valueType == ReferenceType.SOFT) return new SoftValueReference(value, keyRef, hash, refQueue); return value; } @SuppressWarnings("unchecked") final K key() { if (keyRef instanceof KeyReference) return ((Reference)keyRef).get(); return (K) keyRef; } final V value() { return dereferenceValue(valueRef); } @SuppressWarnings("unchecked") final V dereferenceValue(Object value) { if (value instanceof KeyReference) return ((Reference)value).get(); return (V) value; } final void setValue(V value, ReferenceType valueType, ReferenceQueue refQueue) { this.valueRef = newValueReference(value, valueType, refQueue); } @SuppressWarnings("unchecked") static final HashEntry[] newArray(int i) { return new HashEntry[i]; } } /** * Segments are specialized versions of hash tables. This * subclasses from ReentrantLock opportunistically, just to * simplify some locking and avoid separate construction. */ static final class Segment extends ReentrantLock implements Serializable { /* * Segments maintain a table of entry lists that are ALWAYS * kept in a consistent state, so can be read without locking. * Next fields of nodes are immutable (final). All list * additions are performed at the front of each bin. This * makes it easy to check changes, and also fast to traverse. * When nodes would otherwise be changed, new nodes are * created to replace them. This works well for hash tables * since the bin lists tend to be short. (The average length * is less than two for the default load factor threshold.) * * Read operations can thus proceed without locking, but rely * on selected uses of volatiles to ensure that completed * write operations performed by other threads are * noticed. For most purposes, the "count" field, tracking the * number of elements, serves as that volatile variable * ensuring visibility. This is convenient because this field * needs to be read in many read operations anyway: * * - All (unsynchronized) read operations must first read the * "count" field, and should not look at table entries if * it is 0. * * - All (synchronized) write operations should write to * the "count" field after structurally changing any bin. * The operations must not take any action that could even * momentarily cause a concurrent read operation to see * inconsistent data. This is made easier by the nature of * the read operations in Map. For example, no operation * can reveal that the table has grown but the threshold * has not yet been updated, so there are no atomicity * requirements for this with respect to reads. * * As a guide, all critical volatile reads and writes to the * count field are marked in code comments. */ private static final long serialVersionUID = 2249069246763182397L; /** * The number of elements in this segment's region. */ transient volatile int count; /** * Number of updates that alter the size of the table. This is * used during bulk-read methods to make sure they see a * consistent snapshot: If modCounts change during a traversal * of segments computing size or checking containsValue, then * we might have an inconsistent view of state so (usually) * must retry. */ transient int modCount; /** * The table is rehashed when its size exceeds this threshold. * (The value of this field is always (int)(capacity * * loadFactor).) */ transient int threshold; /** * The per-segment table. */ transient volatile HashEntry[] table; /** * The load factor for the hash table. Even though this value * is same for all segments, it is replicated to avoid needing * links to outer object. * @serial */ final float loadFactor; /** * The collected weak-key reference queue for this segment. * This should be (re)initialized whenever table is assigned, */ transient volatile ReferenceQueue refQueue; final ReferenceType keyType; final ReferenceType valueType; final boolean identityComparisons; Segment(int initialCapacity, float lf, ReferenceType keyType, ReferenceType valueType, boolean identityComparisons) { loadFactor = lf; this.keyType = keyType; this.valueType = valueType; this.identityComparisons = identityComparisons; setTable(HashEntry.newArray(initialCapacity)); } @SuppressWarnings("unchecked") static final Segment[] newArray(int i) { return new Segment[i]; } private boolean keyEq(Object src, Object dest) { return identityComparisons ? src == dest : src.equals(dest); } /** * Sets table to new HashEntry array. * Call only while holding lock or in constructor. */ void setTable(HashEntry[] newTable) { threshold = (int)(newTable.length * loadFactor); table = newTable; refQueue = new ReferenceQueue(); } /** * Returns properly casted first entry of bin for given hash. */ HashEntry getFirst(int hash) { HashEntry[] tab = table; return tab[hash & (tab.length - 1)]; } HashEntry newHashEntry(K key, int hash, HashEntry next, V value) { return new HashEntry(key, hash, next, value, keyType, valueType, refQueue); } /** * Reads value field of an entry under lock. Called if value * field ever appears to be null. This is possible only if a * compiler happens to reorder a HashEntry initialization with * its table assignment, which is legal under memory model * but is not known to ever occur. */ V readValueUnderLock(HashEntry e) { lock(); try { removeStale(); return e.value(); } finally { unlock(); } } /* Specialized implementations of map methods */ V get(Object key, int hash) { if (count != 0) { // read-volatile HashEntry e = getFirst(hash); while (e != null) { if (e.hash == hash && keyEq(key, e.key())) { Object opaque = e.valueRef; if (opaque != null) return e.dereferenceValue(opaque); return readValueUnderLock(e); // recheck } e = e.next; } } return null; } boolean containsKey(Object key, int hash) { if (count != 0) { // read-volatile HashEntry e = getFirst(hash); while (e != null) { if (e.hash == hash && keyEq(key, e.key())) return true; e = e.next; } } return false; } boolean containsValue(Object value) { if (count != 0) { // read-volatile HashEntry[] tab = table; int len = tab.length; for (int i = 0 ; i < len; i++) { for (HashEntry e = tab[i]; e != null; e = e.next) { Object opaque = e.valueRef; V v; if (opaque == null) v = readValueUnderLock(e); // recheck else v = e.dereferenceValue(opaque); if (value.equals(v)) return true; } } } return false; } boolean replace(K key, int hash, V oldValue, V newValue) { lock(); try { removeStale(); HashEntry e = getFirst(hash); while (e != null && (e.hash != hash || !keyEq(key, e.key()))) e = e.next; boolean replaced = false; if (e != null && oldValue.equals(e.value())) { replaced = true; e.setValue(newValue, valueType, refQueue); } return replaced; } finally { unlock(); } } V replace(K key, int hash, V newValue) { lock(); try { removeStale(); HashEntry e = getFirst(hash); while (e != null && (e.hash != hash || !keyEq(key, e.key()))) e = e.next; V oldValue = null; if (e != null) { oldValue = e.value(); e.setValue(newValue, valueType, refQueue); } return oldValue; } finally { unlock(); } } V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { removeStale(); int c = count; if (c++ > threshold) {// ensure capacity int reduced = rehash(); if (reduced > 0) // adjust from possible weak cleanups count = (c -= reduced) - 1; // write-volatile } HashEntry[] tab = table; int index = hash & (tab.length - 1); HashEntry first = tab[index]; HashEntry e = first; while (e != null && (e.hash != hash || !keyEq(key, e.key()))) e = e.next; V oldValue; if (e != null) { oldValue = e.value(); if (!onlyIfAbsent || oldValue == null) // null = gc AFTER stale removal e.setValue(value, valueType, refQueue); } else { oldValue = null; ++modCount; tab[index] = newHashEntry(key, hash, first, value); count = c; // write-volatile } return oldValue; } finally { unlock(); } } int rehash() { HashEntry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity >= MAXIMUM_CAPACITY) return 0; /* * Reclassify nodes in each list to new Map. Because we are * using power-of-two expansion, the elements from each bin * must either stay at same index, or move with a power of two * offset. We eliminate unnecessary node creation by catching * cases where old nodes can be reused because their next * fields won't change. Statistically, at the default * threshold, only about one-sixth of them need cloning when * a table doubles. The nodes they replace will be garbage * collectable as soon as they are no longer referenced by any * reader thread that may be in the midst of traversing table * right now. */ HashEntry[] newTable = HashEntry.newArray(oldCapacity<<1); threshold = (int)(newTable.length * loadFactor); int sizeMask = newTable.length - 1; int reduce = 0; for (int i = 0; i < oldCapacity ; i++) { // We need to guarantee that any existing reads of old Map can // proceed. So we cannot yet null out each bin. HashEntry e = oldTable[i]; if (e != null) { HashEntry next = e.next; int idx = e.hash & sizeMask; // Single node on list if (next == null) newTable[idx] = e; else { // Reuse trailing consecutive sequence at same slot HashEntry lastRun = e; int lastIdx = idx; for (HashEntry last = next; last != null; last = last.next) { int k = last.hash & sizeMask; if (k != lastIdx) { lastIdx = k; lastRun = last; } } newTable[lastIdx] = lastRun; // Clone all remaining nodes for (HashEntry p = e; p != lastRun; p = p.next) { // Skip GC'd weak refs K key = p.key(); if (key == null) { reduce++; continue; } int k = p.hash & sizeMask; HashEntry n = newTable[k]; newTable[k] = newHashEntry(key, p.hash, n, p.value()); } } } } table = newTable; return reduce; } /** * Remove; match on key only if value null, else match both. */ V remove(Object key, int hash, Object value, boolean refRemove) { lock(); try { if (!refRemove) removeStale(); int c = count - 1; HashEntry[] tab = table; int index = hash & (tab.length - 1); HashEntry first = tab[index]; HashEntry e = first; // a ref remove operation compares the Reference instance while (e != null && key != e.keyRef && (refRemove || hash != e.hash || !keyEq(key, e.key()))) e = e.next; V oldValue = null; if (e != null) { V v = e.value(); if (value == null || value.equals(v)) { oldValue = v; // All entries following removed node can stay // in list, but all preceding ones need to be // cloned. ++modCount; HashEntry newFirst = e.next; for (HashEntry p = first; p != e; p = p.next) { K pKey = p.key(); if (pKey == null) { // Skip GC'd keys c--; continue; } newFirst = newHashEntry(pKey, p.hash, newFirst, p.value()); } tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); } } final void removeStale() { KeyReference ref; while ((ref = (KeyReference) refQueue.poll()) != null) { remove(ref.keyRef(), ref.keyHash(), null, true); } } void clear() { if (count != 0) { lock(); try { HashEntry[] tab = table; for (int i = 0; i < tab.length ; i++) tab[i] = null; ++modCount; // replace the reference queue to avoid unnecessary stale cleanups refQueue = new ReferenceQueue(); count = 0; // write-volatile } finally { unlock(); } } } } /* ---------------- Public operations -------------- */ /** * Creates a new, empty map with the specified initial * capacity, reference types, load factor and concurrency level. * * Behavioral changing options such as {@link Option#IDENTITY_COMPARISONS} * can also be specified. * * @param initialCapacity the initial capacity. The implementation * performs internal sizing to accommodate this many elements. * @param loadFactor the load factor threshold, used to control resizing. * Resizing may be performed when the average number of elements per * bin exceeds this threshold. * @param concurrencyLevel the estimated number of concurrently * updating threads. The implementation performs internal sizing * to try to accommodate this many threads. * @param keyType the reference type to use for keys * @param valueType the reference type to use for values * @param options the behavioral options * @throws IllegalArgumentException if the initial capacity is * negative or the load factor or concurrencyLevel are * nonpositive. */ public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, ReferenceType keyType, ReferenceType valueType, EnumSet