gt: 			if (other.deviceModel != null)
context: /*-
   *******************************************************************************
   * Copyright (c) 2011, 2016 Diamond Light Source Ltd.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *    Matthew Gerring - initial API and implementation and/or initial documentation
   *******************************************************************************/
  package org.eclipse.scanning.api.event.scan;
  
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.LinkedHashSet;
  import java.util.Map;
  
  import org.eclipse.scanning.api.ModelValidationException;
  import org.eclipse.scanning.api.ValidationException;
  import org.eclipse.scanning.api.annotation.ui.DeviceType;
  import org.eclipse.scanning.api.device.IAttributableDevice;
  import org.eclipse.scanning.api.event.EventException;
  import org.eclipse.scanning.api.event.IdBean;
  import org.eclipse.scanning.api.malcolm.attributes.IDeviceAttribute;
  import org.eclipse.scanning.api.points.IPosition;
  
  /**
   *
   * Object used to query which devices are available from a given broker.
   * The solstice server for instance asks the IRunnableDeviceService what is available
   * and returns a list of devices and their configuration.
   *
   * Servlet may also be used to configure a given device and return the result, set its value
   * get its value. It can be used for Scannables and Detectors.
   *
   * <pre>
   * Usage:
   * 1. Set nothing, post returns list of DeviceInformation for all devices.
   * 2. Set the device name, post returns the device with this name.               IRunnableDeviceService.getRunnableDevice()
   * 3. Set name and model, named device is retrieved and configured.
   * 4. Set the device model and the configure boolean, get a new device created.  IRunnableDeviceService.createRunnableDevice()
   * 5. Set the device action and the device name to call specific methods.
   *
   * </pre>
   *
   * TODO The data in this class has become a little overloaded. We could have one class for scannables
   * and one for runnable devices (detectors) to simplify things. The reason that this refactor has not
   * been done is that it is not clear if we want Solstice to be delivering client-side services this
   * way in the future. The hand coding of post and response which this message is part of has advantages and
   * disadvantages. Current the design meets the requirement of server without an endpoint (multiple servers)
   * and allows any technology like python/stomp to interact with it. However the Java client design then
   * becomes a little inelegant because the services have these remote versions implemented.
   *
   * @author Matthew Gerring
   *
   */
  public class DeviceRequest extends IdBean {
  
  	private static final long serialVersionUID = 3497960665336985413L;
  
  	private DeviceType deviceType = DeviceType.RUNNABLE;
  
  	/**
  	 * List of all devices
  	 */
  	private Collection<DeviceInformation<?>> devices;
  
  	/**
  	 * The name of the device required or null if more than one device is required.
  	 */
  	private String deviceName;
  
  	/**
  	 * The device's model. Normally used to configure a device.
  	 * The Object must json through the marshaller.
  	 */
  	private Object deviceModel;
  
  	/**
  	 * The device's value, if any. For instance for a scannable it
  	 * would be it's scalar position, usually a Double.
  	 */
  	private Object deviceValue;
  
  	/**
  	 * Set wether a create call (one where the model is non-null)
  	 * should call configure on the device.
  	 */
  	private boolean configure = true;
  
  	/**
  	 * The action to call if a method should be called on the device.
  	 */
  	private DeviceAction deviceAction;
  
  	/**
  	 * The position to start at for a run call.
  	 */
  	private IPosition position;
  
  	/**
  	 * If this field is set to a value, and the device implements {@link IAttributableDevice},
  	 * the {@link DeviceInformation} for this device will include the value of this attribute.
  	 */
  	private String attributeName = null;
  
  	/**
  	 * If this field is set to <code>true</code>, and the device implements {@link IAttributableDevice},
  	 * the {@link DeviceInformation} for this device will include the values of all attributes for this device.
  	 */
  	private boolean getAllAttributes = false;
  
  	/**
  	 * The device attributes. This field is set by the server.
  	 */
  	private Map<String, IDeviceAttribute<?>> attributes = null;
  
  	/**
  	 * If there is an error in the request.
  	 */
  	private String errorMessage;
  
  	private String[] errorFieldNames;
  
  	/**
  	 * Set whether to get device information that is potentially held
  	 * the device itself from a device that is marked as not being alive.
  	 */
  	private boolean includeNonAlive = false;
  
  	@Override
  	public <A extends IdBean> void merge(A with) {
  		super.merge(with);
  		DeviceRequest dr = (DeviceRequest)with;
  		devices          = dr.devices;
  		deviceName       = dr.deviceName;
  		deviceModel      = dr.deviceModel;
  		deviceType       = dr.deviceType;
  		deviceAction     = dr.deviceAction;
  		deviceValue      = dr.deviceValue;
  		configure        = dr.configure;
  		position         = dr.position;
  		attributeName    = dr.attributeName;
  		getAllAttributes = dr.getAllAttributes;
  		errorMessage     = dr.errorMessage;
  		errorFieldNames  = dr.errorFieldNames;
  		attributes       = dr.attributes;
  		includeNonAlive  = dr.includeNonAlive;
  	}
  
  
  	public DeviceRequest() {
  
  	}
  
  	public DeviceRequest(DeviceType type) {
  		this.deviceType = type;
  	}
  
  	/**
  	 * For IRunnableDeviceService.getRunnableDevice()
  	 * @param name
  	 */
  	public DeviceRequest(String name) {
  		this.deviceName = name;
  	}
  
  	/**
  	 * For IRunnableDeviceService.getRunnableDevice()
  	 * @param name
  	 */
  	public DeviceRequest(String name, DeviceAction action) {
  		this.deviceName   = name;
  		this.deviceAction = action;
  	}
  
  	public DeviceRequest(String name, DeviceAction action, Object model) {
  		this.deviceName   = name;
  		this.deviceAction = action;
  		this.deviceModel  = model;
  	}
  
  	/**
  	 * For IRunnableDeviceService.createRunnableDevice()
  	 * @param name
  	 */
  	public DeviceRequest(Object model, boolean conf) {
  		this.deviceModel = model;
  		this.configure   = conf;
  	}
  
  	/**
  	 * For IRunnableDeviceService.getRunnableDevice(...)
  	 * then device.configure(...)
  	 * @param name
  	 */
  	public DeviceRequest(String name, Object model) {
  		this.deviceName  = name;
  		this.deviceModel = model;
  	}
  	/**
  	 * For IRunnableDeviceService.getRunnableDevice(...)
  	 * then device.configure(...)
  	 * @param name
  	 */
  	public DeviceRequest(String name, DeviceType type) {
  		this.deviceName  = name;
  		this.deviceType  = type;
  	}
  
  
  	public DeviceRequest(String name, DeviceType type, DeviceAction action, boolean activated) {
  		this(name, type);
  		this.deviceAction = action;
  		this.deviceValue  = activated;
  	}
  
  	public DeviceRequest(String name, DeviceType type, DeviceAction action, Object deviceValue) {
  		this(name, type);
  		this.deviceAction = action;
  		this.deviceValue  = deviceValue;
  	}
  
  	public Collection<DeviceInformation<?>> getDevices() {
  		return devices;
  	}
  
  	public void setDevices(Collection<DeviceInformation<?>> devices) {
  		this.devices = devices;
  	}
  
  	@Override
  	public int hashCode() {
  		final int prime = 31;
  		int result = super.hashCode();
  		result = prime * result + ((attributeName == null) ? 0 : attributeName.hashCode());
  		result = prime * result + (configure ? 1231 : 1237);
  		result = prime * result + ((deviceAction == null) ? 0 : deviceAction.hashCode());
  		result = prime * result + ((deviceModel == null) ? 0 : deviceModel.hashCode());
  		result = prime * result + ((deviceName == null) ? 0 : deviceName.hashCode());
  		result = prime * result + ((deviceType == null) ? 0 : deviceType.hashCode());
  		result = prime * result + ((deviceValue == null) ? 0 : deviceValue.hashCode());
  		result = prime * result + ((devices == null) ? 0 : devices.hashCode());
  		result = prime * result + Arrays.hashCode(errorFieldNames);
  		result = prime * result + ((errorMessage == null) ? 0 : errorMessage.hashCode());
  		result = prime * result + (getAllAttributes ? 1231 : 1237);
  		result = prime * result + (includeNonAlive ? 1231 : 1237);
  		result = prime * result + ((position == null) ? 0 : position.hashCode());
  		result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
  		return result;
  	}
  
  	@SuppressWarnings("squid:S3776")
  	@Override
  	public boolean equals(Object obj) {
  		if (this == obj)
  			return true;
  		if (!super.equals(obj))
  			return false;
  		if (getClass() != obj.getClass())
  			return false;
  		DeviceRequest other = (DeviceRequest) obj;
  		if (attributeName == null) {
  			if (other.attributeName != null)
  				return false;
  		} else if (!attributeName.equals(other.attributeName))
  			return false;
  		if (configure != other.configure)
  			return false;
  		if (deviceAction != other.deviceAction)
  			return false;
  		if (deviceModel == null) {
  