/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.jmeter.save.converters;
import org.apache.jmeter.samplers.SampleSaveConfiguration;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
import com.thoughtworks.xstream.core.JVM;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.mapper.Mapper;
import com.thoughtworks.xstream.mapper.MapperWrapper;
/*
* Allow new fields to be added to the SampleSaveConfiguration without
* changing the output JMX file unless it is necessary.
*
* TODO work out how to make shouldSerializeMember() conditionally return true.
*/
public class SampleSaveConfigurationConverter extends ReflectionConverter {
private static final ReflectionProvider rp;
static {
ReflectionProvider tmp;
try {
tmp = new JVM().bestReflectionProvider();
} catch (NullPointerException e) {// Bug in above method
tmp = new PureJavaReflectionProvider();
}
rp = tmp;
}
private static final String TRUE = "true"; // $NON-NLS-1$
// N.B. These must agree with the new member names in SampleSaveConfiguration
private static final String NODE_FILENAME = "fileName"; // $NON-NLS-1$
private static final String NODE_HOSTNAME = "hostname"; // $NON-NLS-1$
private static final String NODE_URL = "url"; // $NON-NLS-1$
private static final String NODE_BYTES = "bytes"; // $NON-NLS-1$
private static final String NODE_THREAD_COUNT = "threadCounts"; // $NON-NLS-1$
private static final String NODE_SAMPLE_COUNT = "sampleCount"; // $NON-NLS-1$
// Additional member names which are currently not written out
private static final String NODE_DELIMITER = "delimiter"; // $NON-NLS-1$
private static final String NODE_PRINTMS = "printMilliseconds"; // $NON-NLS-1$
static class MyWrapper extends MapperWrapper{
public MyWrapper(Mapper wrapped) {
super(wrapped);
}
public boolean shouldSerializeMember(Class definedIn, String fieldName) {
if (SampleSaveConfiguration.class != definedIn) { return true; }
// These are new fields; not saved unless true
if (fieldName.equals(NODE_BYTES)) { return false; }
if (fieldName.equals(NODE_URL)) { return false; }
if (fieldName.equals(NODE_FILENAME)) { return false; }
if (fieldName.equals(NODE_HOSTNAME)) { return false; }
if (fieldName.equals(NODE_THREAD_COUNT)) { return false; }
if (fieldName.equals(NODE_SAMPLE_COUNT)) { return false; }
// These fields are not currently saved or restored
if (fieldName.equals(NODE_DELIMITER)) { return false; }
if (fieldName.equals(NODE_PRINTMS)) { return false; }
return true;
}
}
public SampleSaveConfigurationConverter(Mapper arg0) {
super(new MyWrapper(arg0),rp);
}
/**
* Returns the converter version; used to check for possible
* incompatibilities
*/
public static String getVersion() {
return "$Revision: 646636 $"; // $NON-NLS-1$
}
/*
* (non-Javadoc)
*
* @see com.thoughtworks.xstream.converters.Converter#canConvert(java.lang.Class)
*/
public boolean canConvert(Class arg0) {
return arg0.equals(SampleSaveConfiguration.class);
}
/*
* (non-Javadoc)
*
* @see com.thoughtworks.xstream.converters.Converter#marshal(java.lang.Object,
* com.thoughtworks.xstream.io.HierarchicalStreamWriter,
* com.thoughtworks.xstream.converters.MarshallingContext)
*/
public void marshal(Object obj, HierarchicalStreamWriter writer, MarshallingContext context) {
super.marshal(obj, writer, context); // Save most things
SampleSaveConfiguration prop = (SampleSaveConfiguration) obj;
// Save the new fields - but only if they are not the default
createNode(writer,prop.saveBytes(),NODE_BYTES);
createNode(writer,prop.saveUrl(),NODE_URL);
createNode(writer,prop.saveFileName(),NODE_FILENAME);
createNode(writer,prop.saveHostname(),NODE_HOSTNAME);
createNode(writer,prop.saveThreadCounts(),NODE_THREAD_COUNT);
createNode(writer,prop.saveSampleCount(),NODE_SAMPLE_COUNT);
}
// Helper method to simplify marshall routine
private void createNode(HierarchicalStreamWriter writer, boolean save, String node) {
if (!save) {
return;
}
writer.startNode(node);
writer.setValue(TRUE);
writer.endNode();
}
/*
*
*/
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
final Class thisClass = SampleSaveConfiguration.class;
final Class requiredType = context.getRequiredType();
if (requiredType != thisClass) {
throw new IllegalArgumentException("Unexpected class: "+requiredType.getName());
}
SampleSaveConfiguration result = new SampleSaveConfiguration();
result.setBytes(false); // Maintain backward compatibility (bytes was not in the JMX file)
while (reader.hasMoreChildren()) {
reader.moveDown();
String nn = reader.getNodeName();
if (!"formatter".equals(nn)){// Skip formatter (if present) bug 42674 $NON-NLS-1$
String fieldName = mapper.realMember(thisClass, nn);
java.lang.reflect.Field field = reflectionProvider.getField(thisClass,fieldName);
Class type = field.getType();
Object value = unmarshallField(context, result, type, field);
reflectionProvider.writeField(result, nn, value, thisClass);
}
reader.moveUp();
}
return result;
}
}