, Unit>> normalizations = Maps.newConcurrentMap();
+diff -Naurp parfait-0.5.3.orig/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java parfait-0.5.3/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java
+--- parfait-0.5.3.orig/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java 2017-10-06 11:45:35.000000000 +1100
++++ parfait-0.5.3/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java 2017-10-06 11:56:57.571404704 +1100
+@@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHa
+ import com.google.common.cache.CacheBuilder;
+ import com.google.common.cache.CacheLoader;
+ import com.google.common.cache.LoadingCache;
+-import net.jcip.annotations.ThreadSafe;
++//import net.jcip.annotations.ThreadSafe;
+
+ /**
+ *
+@@ -45,7 +45,7 @@ import net.jcip.annotations.ThreadSafe;
+ *
+ * @author Cowan
+ */
+-@ThreadSafe
++//@ThreadSafe
+ public class ThreadContext {
+ private static final CacheLoader> NEW_CONTEXT_CREATOR = new CacheLoader>() {
+ @Override
+diff -Naurp parfait-0.5.3.orig/parfait-pcp/src/main/java/io/pcp/parfait/pcp/PcpMonitorBridge.java parfait-0.5.3/parfait-pcp/src/main/java/io/pcp/parfait/pcp/PcpMonitorBridge.java
+--- parfait-0.5.3.orig/parfait-pcp/src/main/java/io/pcp/parfait/pcp/PcpMonitorBridge.java 2017-10-06 11:45:35.000000000 +1100
++++ parfait-0.5.3/parfait-pcp/src/main/java/io/pcp/parfait/pcp/PcpMonitorBridge.java 2017-10-06 11:59:49.367827348 +1100
+@@ -25,7 +25,7 @@ import io.pcp.parfait.dxm.PcpWriter;
+ import io.pcp.parfait.dxm.semantics.Semantics;
+ import com.google.common.base.Preconditions;
+ import com.google.common.collect.ImmutableMap;
+-import net.jcip.annotations.NotThreadSafe;
++//import net.jcip.annotations.NotThreadSafe;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+@@ -45,7 +45,7 @@ import java.util.concurrent.ArrayBlockin
+ *
+ * @see io.pcp.parfait.QuiescentRegistryListener
+ */
+-@NotThreadSafe
++//@NotThreadSafe
+ public class PcpMonitorBridge implements MonitoringView {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PcpMonitorBridge.class);
+diff -Naurp parfait-0.5.3.orig/pom.xml parfait-0.5.3/pom.xml
+--- parfait-0.5.3.orig/pom.xml 2017-10-06 11:45:35.000000000 +1100
++++ parfait-0.5.3/pom.xml 2017-10-06 11:56:57.571404704 +1100
+@@ -340,11 +340,6 @@
+ 2.2.9
+
+
+- net.jcip
+- jcip-annotations
+- 1.0
+-
+-
+ commons-io
+ commons-io
+ 1.4
diff --git a/SOURCES/no-more-log4j.patch b/SOURCES/no-more-log4j.patch
new file mode 100644
index 0000000..88008ea
--- /dev/null
+++ b/SOURCES/no-more-log4j.patch
@@ -0,0 +1,283 @@
+diff -Naurp parfait-0.5.4.orig/parfait-agent/pom.xml parfait-0.5.4/parfait-agent/pom.xml
+--- parfait-0.5.4.orig/parfait-agent/pom.xml 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-agent/pom.xml 2021-12-16 14:46:17.702813590 +1100
+@@ -142,11 +142,6 @@
+ ${slf4j.version}
+
+
+- log4j
+- log4j
+- ${log4j.version}
+-
+-
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.8.8
+diff -Naurp parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/AgentMonitoringView.java parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/AgentMonitoringView.java
+--- parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/AgentMonitoringView.java 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/AgentMonitoringView.java 2021-12-16 14:46:17.702813590 +1100
+@@ -48,11 +48,12 @@ import javax.management.ReflectionExcept
+ import javax.management.openmbean.CompositeData;
+ import javax.measure.Unit;
+
+-import org.apache.log4j.Logger;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
+
+
+ class AgentMonitoringView {
+- private static final Logger logger = Logger.getLogger(ParfaitAgent.class);
++ private static final Logger logger = LoggerFactory.getLogger(ParfaitAgent.class);
+
+ private MonitorableRegistry registry = MonitorableRegistry.DEFAULT_REGISTRY;
+
+diff -Naurp parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/JmxUtilities.java parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/JmxUtilities.java
+--- parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/JmxUtilities.java 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/JmxUtilities.java 2021-12-16 14:46:17.703813573 +1100
+@@ -29,8 +29,6 @@ import javax.management.remote.JMXConnec
+ import javax.management.remote.JMXConnectorFactory;
+ import javax.management.remote.JMXServiceURL;
+
+-import org.apache.log4j.Logger;
+-
+ /**
+ * Convenience mechanisms for locating MBeanServer classes.
+ */
+diff -Naurp parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/ParfaitAgent.java parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/ParfaitAgent.java
+--- parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/ParfaitAgent.java 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/ParfaitAgent.java 2021-12-16 14:49:54.874103371 +1100
+@@ -42,10 +42,11 @@ import javax.management.IntrospectionExc
+ import javax.management.MBeanException;
+ import javax.management.MBeanServer;
+
+-import org.apache.log4j.Logger;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
+
+ public class ParfaitAgent {
+- private static final Logger logger = Logger.getLogger(ParfaitAgent.class);
++ private static final Logger logger = LoggerFactory.getLogger(ParfaitAgent.class);
+
+ private static final String RESOURCE = "/jvm.json";
+ private static final String PATHNAME = "/etc/parfait";
+diff -Naurp parfait-0.5.4.orig/parfait-core/src/main/java/io/pcp/parfait/QuiescentRegistryListener.java parfait-0.5.4/parfait-core/src/main/java/io/pcp/parfait/QuiescentRegistryListener.java
+--- parfait-0.5.4.orig/parfait-core/src/main/java/io/pcp/parfait/QuiescentRegistryListener.java 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-core/src/main/java/io/pcp/parfait/QuiescentRegistryListener.java 2021-12-16 14:46:17.703813573 +1100
+@@ -20,14 +20,15 @@ import java.util.Timer;
+ import java.util.TimerTask;
+
+ import com.google.common.base.Supplier;
+-import org.apache.log4j.Logger;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
+
+ /**
+ * Designed to run code after the MonitorableRegistry has become quiet, in terms of addition of new metrics
+ */
+ public class QuiescentRegistryListener implements MonitorableRegistryListener {
+
+- private static final Logger LOG = Logger.getLogger(QuiescentRegistryListener.class);
++ private static final Logger LOG = LoggerFactory.getLogger(QuiescentRegistryListener.class);
+
+ private final Scheduler quiescentScheduler;
+ private volatile long lastTimeMonitorableAdded = 0;
+diff -Naurp parfait-0.5.4.orig/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java parfait-0.5.4/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java
+--- parfait-0.5.4.orig/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java 2021-12-16 14:45:29.312640302 +1100
++++ parfait-0.5.4/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java 2021-12-16 14:46:17.703813573 +1100
+@@ -95,11 +95,6 @@ public class ThreadContext {
+ * Clears all values for the current thread.
+ */
+ public void clear() {
+-
+- /**
+- * Unfortunately log4j's MDC historically never had a mechanism to block remove keys,
+- * so we're forced to do this one by one.
+- */
+ for (String key : allKeys()) {
+ mdcBridge.remove(key);
+ }
+@@ -127,21 +122,18 @@ public class ThreadContext {
+ }
+
+ /**
+- * Factory method that creates a new ThreadContext initialized to also update Log4j's MDC.
++ * Factory methods that create a new ThreadContext initialised to also update SLF4J's MDC
+ */
+ public static ThreadContext newMDCEnabledContext() {
+- return new ThreadContext(new Log4jMdcBridge());
++ return newSLF4JEnabledContext();
+ }
+
+- /**
+- * Factory method that creates a new ThreadContext initialised to also update SLF4J's MDC
+- */
+ public static ThreadContext newSLF4JEnabledContext() {
+ return new ThreadContext(new Slf4jMDCBridge());
+ }
+
+ public interface MdcBridge {
+- void put(String key, Object object);
++ void put(String key, Object object);
+
+ void remove(String key);
+ }
+@@ -158,18 +150,6 @@ public class ThreadContext {
+ }
+ }
+
+- public static class Log4jMdcBridge implements MdcBridge {
+- @Override
+- public void put(String key, Object object) {
+- org.apache.log4j.MDC.put(key, object);
+- }
+-
+- @Override
+- public void remove(String key) {
+- org.apache.log4j.MDC.remove(key);
+- }
+- }
+-
+ public static class Slf4jMDCBridge implements MdcBridge {
+ @Override
+ public void put(String key, Object object) {
+diff -Naurp parfait-0.5.4.orig/parfait-core/src/test/java/io/pcp/parfait/timing/ThreadContextTest.java parfait-0.5.4/parfait-core/src/test/java/io/pcp/parfait/timing/ThreadContextTest.java
+--- parfait-0.5.4.orig/parfait-core/src/test/java/io/pcp/parfait/timing/ThreadContextTest.java 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-core/src/test/java/io/pcp/parfait/timing/ThreadContextTest.java 2021-12-16 14:46:17.703813573 +1100
+@@ -20,7 +20,7 @@ import java.util.Hashtable;
+ import java.util.Map;
+ import java.util.concurrent.CountDownLatch;
+
+-import org.apache.log4j.MDC;
++import org.slf4j.MDC;
+
+ import junit.framework.TestCase;
+
+@@ -29,11 +29,7 @@ public class ThreadContextTest extends T
+
+ public void setUp() {
+ context = new ThreadContext();
+-
+- Hashtable hashtable = MDC.getContext();
+- if (hashtable != null) {
+- hashtable.clear();
+- }
++ MDC.clear();
+ }
+
+
+@@ -86,15 +82,16 @@ public class ThreadContextTest extends T
+ assertNull("get() after clear should return null", context.get(testKey));
+ }
+
++/* -- Slf4j provides no MDC context API --
+ public void testClearRemovesMDCValue() {
+
+- ThreadContext log4jThreadContext = ThreadContext.newMDCEnabledContext();
++ ThreadContext logThreadContext = ThreadContext.newMDCEnabledContext();
+
+ Hashtable mdcContext = MDC.getContext();
+ assertTrue(mdcContext == null || mdcContext.isEmpty());
+
+ final String testKey = "painter";
+- log4jThreadContext.put(testKey, 7);
++ logThreadContext.put(testKey, 7);
+
+ mdcContext = MDC.getContext();
+ assertEquals(1, mdcContext.size());
+@@ -102,7 +99,8 @@ public class ThreadContextTest extends T
+ mdcContext.clear();
+ assertEquals(0, mdcContext.size());
+
+- log4jThreadContext.clear();
+- assertNull("get() after clear should return null", log4jThreadContext.get(testKey));
++ logThreadContext.clear();
++ assertNull("get() after clear should return null", logThreadContext.get(testKey));
+ }
++*/
+ }
+diff -Naurp parfait-0.5.4.orig/pom.xml parfait-0.5.4/pom.xml
+--- parfait-0.5.4.orig/pom.xml 2021-12-16 14:45:29.313640285 +1100
++++ parfait-0.5.4/pom.xml 2021-12-16 14:50:31.701474201 +1100
+@@ -95,7 +95,6 @@
+ UTF-8
+ 4.2.5.RELEASE
+ 1.6.1
+- 1.2.14
+ 1.8
+ ${jdk.version}
+ ${jdk.version}
+@@ -323,11 +322,6 @@
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+-
+-
+- log4j
+- log4j
+- ${log4j.version}
+
+
+ com.google.guava
+@@ -385,11 +379,6 @@
+ slf4j-api
+
+
+- log4j
+- log4j
+- true
+-
+-
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.8.8
+diff -Naurp parfait-0.5.4.orig/parfait-agent/src/main/resources/log4j2.xml parfait-0.5.4/parfait-agent/src/main/resources/log4j2.xml
+--- parfait-0.5.4.orig/parfait-agent/src/main/resources/log4j2.xml 2022-01-10 17:09:09.794017829 +0100
++++ parfait-0.5.4/parfait-agent/src/main/resources/log4j2.xml 1970-01-01 01:00:00.000000000 +0100
+@@ -1,36 +0,0 @@
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+diff -Naurp parfait-0.5.4.orig/parfait-agent/src/main/resources/log4j.properties parfait-0.5.4/parfait-agent/src/main/resources/log4j.properties
+--- parfait-0.5.4.orig/parfait-agent/src/main/resources/log4j.properties 2022-01-10 17:09:09.794017829 +0100
++++ parfait-0.5.4/parfait-agent/src/main/resources/log4j.properties 1970-01-01 01:00:00.000000000 +0100
+@@ -1,7 +0,0 @@
+-# Set root logger level to ERROR and its only appender to A1.
+-log4j.rootLogger=warn, A1
+-
+-log4j.appender.A1=org.apache.log4j.ConsoleAppender
+-log4j.appender.A1.Threshold=warn
+-log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+-log4j.appender.A1.layout.ConversionPattern=[%t] %-5p %c %x - %m%n
diff --git a/SOURCES/no-more-objects.patch b/SOURCES/no-more-objects.patch
new file mode 100644
index 0000000..f7fbe20
--- /dev/null
+++ b/SOURCES/no-more-objects.patch
@@ -0,0 +1,322 @@
+diff -Naurp parfait-0.5.3.orig/parfait-core/src/main/java/io/pcp/parfait/PollingMonitoredValue.java parfait-0.5.3/parfait-core/src/main/java/io/pcp/parfait/PollingMonitoredValue.java
+--- parfait-0.5.3.orig/parfait-core/src/main/java/io/pcp/parfait/PollingMonitoredValue.java 2017-10-03 11:38:15.000000000 +1100
++++ parfait-0.5.3/parfait-core/src/main/java/io/pcp/parfait/PollingMonitoredValue.java 2017-10-06 13:35:06.169481799 +1100
+@@ -29,7 +29,7 @@ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+ import com.google.common.annotations.VisibleForTesting;
+-import com.google.common.base.MoreObjects;
++//import com.google.common.base.MoreObjects;
+ import com.google.common.base.Preconditions;
+ import com.google.common.base.Supplier;
+
+@@ -104,10 +104,10 @@ public class PollingMonitoredValue ex
+ scheduler.schedule(new PollerTask(), updateInterval);
+ }
+
+- @Override
+- public String toString() {
+- return MoreObjects.toStringHelper(this).add("name", getName()).add("description", getDescription()).add("poller", poller).toString();
+- }
++// @Override
++// public String toString() {
++// return MoreObjects.toStringHelper(this).add("name", getName()).add("description", getDescription()).add("poller", poller).toString();
++// }
+
+
+ private class PollerTask extends TimerTask {
+diff -Naurp parfait-0.5.3.orig/parfait-jmx/src/main/java/io/pcp/parfait/jmx/JmxView.java parfait-0.5.3/parfait-jmx/src/main/java/io/pcp/parfait/jmx/JmxView.java
+--- parfait-0.5.3.orig/parfait-jmx/src/main/java/io/pcp/parfait/jmx/JmxView.java 2017-10-03 11:44:14.000000000 +1100
++++ parfait-0.5.3/parfait-jmx/src/main/java/io/pcp/parfait/jmx/JmxView.java 1970-01-01 10:00:00.000000000 +1000
+@@ -1,150 +0,0 @@
+-/*
+- * Copyright 2009-2017 Aconex
+- *
+- * 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 io.pcp.parfait.jmx;
+-
+-import io.pcp.parfait.Monitor;
+-import io.pcp.parfait.Monitorable;
+-import io.pcp.parfait.MonitoringView;
+-import com.google.common.base.MoreObjects;
+-import org.springframework.jmx.export.annotation.ManagedAttribute;
+-import org.springframework.jmx.export.annotation.ManagedResource;
+-
+-import javax.management.openmbean.CompositeData;
+-import javax.management.openmbean.CompositeDataSupport;
+-import javax.management.openmbean.CompositeType;
+-import javax.management.openmbean.OpenDataException;
+-import javax.management.openmbean.OpenType;
+-import javax.management.openmbean.SimpleType;
+-import java.util.Collection;
+-import java.util.HashMap;
+-import java.util.Map;
+-import java.util.concurrent.atomic.AtomicInteger;
+-import java.util.concurrent.atomic.AtomicLong;
+-
+-@ManagedResource
+-public class JmxView implements MonitoringView {
+- private String[] jmxMonitoredNames;
+- private Object[] jmxMonitoredValues;
+- private Map jmxArrayIndexMap;
+- private CompositeType monitoredType;
+-
+- private final Monitor monitor = new JmxUpdatingMonitor();
+- private volatile boolean started;
+-
+-
+- @Override
+- public void startMonitoring(Collection> monitorables) {
+- setupJmxValues(monitorables);
+- for (Monitorable> monitorable : monitorables) {
+- updateData(monitorable);
+- monitorable.attachMonitor(monitor);
+- }
+- this.started = true;
+- }
+-
+- @Override
+- public void stopMonitoring(Collection> monitorables) {
+- for (Monitorable> monitorable : monitorables) {
+- monitorable.removeMonitor(monitor);
+- }
+- this.started = false;
+- }
+-
+- @Override
+- public boolean isRunning() {
+- return started;
+- }
+-
+- private void setupJmxValues(Collection> monitorables) {
+- if (monitorables.isEmpty()) {
+- return;
+- }
+- try {
+- jmxMonitoredNames = new String[monitorables.size()];
+- String[] descriptions = new String[monitorables.size()];
+- jmxMonitoredValues = new Object[monitorables.size()];
+- OpenType>[] types = new OpenType>[monitorables.size()];
+- jmxArrayIndexMap = new HashMap(monitorables.size());
+- int index = 0;
+-
+- for (Monitorable> monitorable : monitorables) {
+- jmxMonitoredNames[index] = monitorable.getName();
+- descriptions[index] = MoreObjects.firstNonNull(monitorable.getDescription(),
+- "(unknown)");
+- types[index] = getJmxType(monitorable.getType());
+- jmxArrayIndexMap.put(monitorable.getName(), index);
+- index++;
+- }
+-
+- monitoredType = new CompositeType("Exposed PCP metrics",
+- "Details of all exposed PCP metrics", jmxMonitoredNames, descriptions, types);
+- } catch (OpenDataException e) {
+- throw new UnsupportedOperationException("Unable to configure JMX types", e);
+- }
+- }
+-
+- private OpenType> getJmxType(Class> type) {
+- if (type == Boolean.class) {
+- return SimpleType.BOOLEAN;
+- } else if (type == Integer.class || type == AtomicInteger.class) {
+- return SimpleType.INTEGER;
+- } else if (type == Long.class || type == AtomicLong.class) {
+- return SimpleType.LONG;
+- } else if (type == Double.class) {
+- return SimpleType.DOUBLE;
+- } else if (type == String.class) {
+- return SimpleType.STRING;
+- } else {
+- throw new UnsupportedOperationException(
+- "Don't know how to process Monitorable of type [" + type + "]");
+- }
+- }
+-
+- @ManagedAttribute(description = "All exposed parfait metrics")
+- public CompositeData getExposedMetrics() {
+- try {
+- return new CompositeDataSupport(monitoredType, jmxMonitoredNames, jmxMonitoredValues);
+- } catch (OpenDataException e) {
+- throw new RuntimeException(e);
+- }
+- }
+-
+- private void updateData(Monitorable> monitorable) {
+- Class> type = monitorable.getType();
+- Object jmxValue;
+-
+- if (type == Boolean.class || type == Integer.class || type == Long.class
+- || type == Double.class || type == String.class) {
+- jmxValue = monitorable.get();
+- } else if (type == AtomicInteger.class) {
+- jmxValue = ((AtomicInteger) monitorable.get()).intValue();
+- } else if (type == AtomicLong.class) {
+- jmxValue = ((AtomicLong) monitorable.get()).longValue();
+- } else {
+- throw new UnsupportedOperationException(
+- "Don't know how to process Monitorable of type [" + type + "]");
+- }
+-
+- jmxMonitoredValues[jmxArrayIndexMap.get(monitorable.getName())] = jmxValue;
+- }
+-
+- public class JmxUpdatingMonitor implements Monitor {
+- public void valueChanged(Monitorable> monitorable) {
+- updateData(monitorable);
+- }
+- }
+-}
+diff -Naurp parfait-0.5.3.orig/parfait-jmx/src/test/java/io/pcp/parfait/jmx/JmxViewTest.java parfait-0.5.3/parfait-jmx/src/test/java/io/pcp/parfait/jmx/JmxViewTest.java
+--- parfait-0.5.3.orig/parfait-jmx/src/test/java/io/pcp/parfait/jmx/JmxViewTest.java 2017-10-03 11:44:14.000000000 +1100
++++ parfait-0.5.3/parfait-jmx/src/test/java/io/pcp/parfait/jmx/JmxViewTest.java 1970-01-01 10:00:00.000000000 +1000
+@@ -1,137 +0,0 @@
+-/*
+- * Copyright 2009-2017 Aconex
+- *
+- * 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 io.pcp.parfait.jmx;
+-
+-import io.pcp.parfait.MonitorableRegistry;
+-import io.pcp.parfait.MonitoredValue;
+-import junit.framework.TestCase;
+-
+-import javax.management.openmbean.CompositeData;
+-import java.io.IOException;
+-
+-public class JmxViewTest extends TestCase {
+- private MonitoredValue booleanValue = null;
+-
+- private MonitoredValue intValue = null;
+-
+- private MonitoredValue longValue = null;
+- private MonitoredValue doubleValue = null;
+- private MonitoredValue stringValue = null;
+-
+- private MonitorableRegistry registry = new MonitorableRegistry();
+-
+- private JmxView jmx = null;
+-
+- public JmxViewTest() {
+- }
+-
+- public void setUp() {
+- booleanValue = new MonitoredValue("boolean.value", "boolean.value.desc", registry, true);
+- intValue = new MonitoredValue("int.value", "int.value.desc", registry, 1);
+- longValue = new MonitoredValue("long.value", "long.value.desc", registry, 1l);
+- doubleValue = new MonitoredValue("double.value", "double.value.desc", registry, 1d);
+- stringValue = new MonitoredValue("string.value", "string.value.desc", registry, "!");
+-
+- jmx = new JmxView();
+- }
+-
+- public void tearDown() {
+- jmx.stopMonitoring(registry.getMonitorables());
+- }
+-
+- public void testSupportsAllTypes() throws IOException, InterruptedException {
+- jmx.startMonitoring(registry.getMonitorables());
+-
+- checkDataValues();
+-
+- booleanValue.set(false);
+- checkDataValues();
+-
+- booleanValue.set(true);
+- checkDataValues();
+-
+- intValue.set(0);
+- checkDataValues();
+-
+- intValue.set(Integer.MAX_VALUE);
+- checkDataValues();
+-
+- intValue.set(Integer.MIN_VALUE);
+- checkDataValues();
+-
+- intValue.set(1234567890);
+- checkDataValues();
+-
+- longValue.set(0l);
+- checkDataValues();
+-
+- longValue.set(Long.MAX_VALUE);
+- checkDataValues();
+-
+- longValue.set(Long.MIN_VALUE);
+- checkDataValues();
+-
+- longValue.set(1234567891012345679l);
+- checkDataValues();
+-
+- doubleValue.set(0d);
+- checkDataValues();
+-
+- doubleValue.set(Double.MAX_VALUE);
+- checkDataValues();
+-
+- doubleValue.set(Double.MIN_VALUE);
+- checkDataValues();
+-
+- doubleValue.set(Double.NEGATIVE_INFINITY);
+- checkDataValues();
+-
+- doubleValue.set(Double.POSITIVE_INFINITY);
+- checkDataValues();
+-
+- doubleValue.set(Double.NaN);
+- checkDataValues();
+-
+- doubleValue.set(1234567891.012345679d);
+- checkDataValues();
+-
+- stringValue.set("");
+- checkDataValues();
+-
+- stringValue.set(createString(500));
+- checkDataValues();
+- }
+-
+- private String createString(int length) {
+- StringBuilder sb = new StringBuilder();
+- for (int i = 0; i < length; i++) {
+- sb.append(Math.max(1, i & 255));
+- }
+- return sb.toString();
+- }
+-
+- private void checkDataValues() {
+-
+- CompositeData data = jmx.getExposedMetrics();
+-
+- assertEquals(booleanValue.get(), data.get("boolean.value"));
+- assertEquals(doubleValue.get(), data.get("double.value"));
+- assertEquals((int) intValue.get(), data.get("int.value"));
+- assertEquals((long) longValue.get(), data.get("long.value"));
+- assertEquals(stringValue.get(), data.get("string.value"));
+- }
+-}
diff --git a/SPECS/parfait.spec b/SPECS/parfait.spec
new file mode 100644
index 0000000..31336c9
--- /dev/null
+++ b/SPECS/parfait.spec
@@ -0,0 +1,225 @@
+Name: parfait
+Version: 0.5.4
+Release: 3%{?dist}
+Summary: Java libraries for Performance Co-Pilot (PCP)
+License: ASL 2.0
+URL: https://github.com/performancecopilot/parfait
+Source0: https://github.com/performancecopilot/parfait/archive/%{version}/%{name}-%{version}.tar.gz
+
+Patch1: no-jcip-annotations.patch
+Patch2: no-more-objects.patch
+Patch3: no-more-log4j.patch
+
+%bcond_with metrics
+
+BuildRequires: javapackages-tools
+BuildRequires: junit
+BuildRequires: testng
+BuildRequires: maven-local
+%if 0%{?rhel} == 0
+BuildRequires: maven-license-plugin
+BuildRequires: maven-failsafe-plugin
+%endif
+BuildRequires: maven-source-plugin
+BuildRequires: maven-assembly-plugin
+BuildRequires: maven-plugin-bundle
+BuildRequires: maven-jar-plugin
+BuildRequires: maven-shade-plugin
+BuildRequires: maven-install-plugin
+BuildRequires: maven-surefire-plugin
+BuildRequires: maven-surefire-provider-testng
+BuildRequires: maven-surefire-provider-junit
+BuildRequires: maven-dependency-plugin
+BuildRequires: maven-verifier-plugin
+
+BuildRequires: maven-wagon-ftp
+%if 0%{?rhel} == 0
+BuildRequires: mvn(net.jcip:jcip-annotations)
+BuildRequires: mvn(org.apache.maven.wagon:wagon-ftp)
+BuildRequires: mvn(org.aspectj:aspectjweaver)
+BuildRequires: mvn(org.hsqldb:hsqldb)
+BuildRequires: mvn(org.mockito:mockito-core)
+BuildRequires: mvn(org.springframework:spring-jdbc)
+BuildRequires: mvn(org.springframework:spring-core)
+BuildRequires: mvn(org.springframework:spring-beans)
+BuildRequires: mvn(org.springframework:spring-context)
+BuildRequires: mvn(org.springframework:spring-test)
+%endif
+%if %{with metrics}
+BuildRequires: mvn(com.codahale.metrics:metrics-core)
+%endif
+BuildRequires: mvn(com.fasterxml.jackson.core:jackson-core)
+BuildRequires: mvn(com.fasterxml.jackson.core:jackson-annotations)
+BuildRequires: mvn(com.fasterxml.jackson.core:jackson-databind)
+BuildRequires: mvn(systems.uom:systems-unicode-java8)
+BuildRequires: mvn(javax.measure:unit-api)
+BuildRequires: mvn(tec.uom:uom-se)
+
+BuildArch: noarch
+
+%description
+Parfait is a Java performance monitoring library that exposes and
+collects metrics through a variety of outputs. It provides APIs
+for extracting performance metrics from the JVM and other sources.
+It interfaces to Performance Co-Pilot (PCP) using the Memory Mapped
+Value (MMV) machinery for extremely lightweight instrumentation.
+
+%package javadoc
+BuildArch: noarch
+Summary: Javadoc for Parfait
+
+%description javadoc
+This package contains the API documentation for Parfait.
+
+%package -n pcp-parfait-agent
+BuildArch: noarch
+Summary: Parfait Java Agent for Performance Co-Pilot (PCP)
+
+%description -n pcp-parfait-agent
+This package contains the Parfait Agent for instrumenting Java
+applications. The agent can extract live performance metrics
+from the JVM and other sources, in unmodified applications (via
+the -java-agent java command line option). It interfaces to
+Performance Co-Pilot (PCP) using the Memory Mapped Value (MMV)
+machinery for extremely lightweight instrumentation.
+
+%package examples
+BuildArch: noarch
+Summary: Parfait Java demonstration programs
+
+%description examples
+Sample standalone Java programs showing use of Parfait modules
+for instrumenting applications.
+
+%prep
+%setup -q
+%if 0%{?rhel} != 0
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%endif
+
+# Remove license plugin in main pom.xml
+%pom_remove_plugin com.mycila:license-maven-plugin
+%pom_remove_plugin com.mycila:license-maven-plugin parfait-agent
+
+%pom_disable_module parfait-benchmark
+%pom_disable_module parfait-cxf
+%if %{without metrics}
+%pom_disable_module parfait-dropwizard
+%endif
+%pom_disable_module parfait-jdbc
+%if 0%{?rhel} != 0
+%pom_disable_module parfait-jmx
+%pom_disable_module parfait-spring
+%endif
+%pom_remove_plugin org.apache.maven.plugins:maven-failsafe-plugin
+%pom_remove_plugin org.apache.maven.plugins:maven-jxr-plugin
+%pom_remove_plugin org.apache.maven.plugins:maven-pmd-plugin
+%pom_remove_plugin :maven-javadoc-plugin
+%pom_remove_plugin :maven-site-plugin
+%pom_remove_plugin :maven-source-plugin
+
+%build
+# skip tests for now, missing org.unitils:unitils-core:jar
+%mvn_build -f
+# re-instate not-shaded, not-with-all-dependencies agent jar
+pushd parfait-agent/target
+mv original-parfait-agent.jar parfait-agent.jar
+popd
+
+%install
+%mvn_install
+# install the parfait-agent extra bits (config, script, man page)
+install -m 755 -d %{buildroot}%{_sysconfdir}/%{name}
+install -m 644 parfait-agent/target/classes/jvm.json %{buildroot}%{_sysconfdir}/%{name}
+install -m 755 -d %{buildroot}%{_bindir}
+install -m 755 bin/%{name}.sh %{buildroot}%{_bindir}/%{name}
+install -m 755 -d %{buildroot}%{_mandir}/man1
+install -m 644 man/%{name}.1 %{buildroot}%{_mandir}/man1
+# special install of shaded, with-all-dependencies agent jar
+pushd parfait-agent/target
+install -m 644 parfait-agent-jar-with-dependencies.jar \
+ %{buildroot}%{_javadir}/%{name}/%{name}.jar
+popd
+# special install of with-all-dependencies sample jar files
+for example in acme sleep counter
+do
+ pushd examples/${example}/target
+ install -m 644 example-${example}-jar-with-dependencies.jar \
+ %{buildroot}%{_javadir}/%{name}/${example}.jar
+ popd
+done
+
+%files -f .mfiles
+%doc README.md
+%license LICENSE.md
+
+%files javadoc -f .mfiles-javadoc
+%license LICENSE.md
+
+%files examples
+%dir %{_javadir}/parfait
+%{_javadir}/%{name}/acme.jar
+%{_javadir}/%{name}/sleep.jar
+%{_javadir}/%{name}/counter.jar
+%doc README.md
+%license LICENSE.md
+
+%files -n pcp-parfait-agent
+%dir %{_javadir}/%{name}
+%{_javadir}/%{name}/%{name}.jar
+%doc %{_mandir}/man1/%{name}.1*
+%{_bindir}/%{name}
+%doc README.md
+%license LICENSE.md
+%dir %{_sysconfdir}/%{name}
+%config(noreplace)%{_sysconfdir}/%{name}/jvm.json
+
+%changelog
+* Thu Dec 16 2021 Nathan Scott - 0.5.4-3
+- Drop all code explicitly using Log4J (BZ 2031674)
+
+* Wed Nov 01 2017 Nathan Scott - 0.5.4-2
+- Install a default configuration file for base JVM metrics.
+
+* Fri Oct 06 2017 Nathan Scott - 0.5.4-1
+- Update to latest upstream sources.
+- Support (patched) RHEL7 builds.
+
+* Tue Sep 05 2017 Lukas Berk - 0.5.3-1
+- Update to upstream release
+
+* Tue Aug 15 2017 Lukas Berk - 0.5.1-4
+- Incorprate feedback from fedora-review tool
+
+* Thu Mar 23 2017 Nathan Scott - 0.5.1-3
+- Incorprate feedback from gil cattaneo for package review.
+
+* Mon Mar 06 2017 Nathan Scott - 0.5.1-1
+- Update to latest upstream sources.
+
+* Tue Feb 28 2017 Nathan Scott - 0.5.0-2
+- Resolve lintian errors - source, license, documentation.
+
+* Fri Feb 24 2017 Nathan Scott - 0.5.0-1
+- Update to upstream release, dropping java8 patch.
+
+* Thu Feb 16 2017 Nathan Scott - 0.4.0-5
+- Use RPM macros to ease dropwizard metrics enablement.
+- Correct the dependency on systems.uom:systems-unicode-java8
+
+* Fri Nov 25 2016 Nathan Scott - 0.4.0-4
+- Switch to uom-se and conditional use of dropwizard metrics.
+
+* Fri Oct 28 2016 Nathan Scott - 0.4.0-3
+- Add in parfait wrapper shell script and man page.
+- Rename the agent package to pcp-parfait-agent.
+- Add in demo applications jars and parfait-examples package.
+
+* Thu Oct 20 2016 Nathan Scott - 0.4.0-2
+- Addition of the standalone parfait-agent package.
+- Add in proxy mode from upstream parfait code too.
+
+* Wed Oct 12 2016 Nathan Scott - 0.4.0-1
+- Initial version.