/* ==================================================================
* SerialDeviceSupport.java - 25/10/2014 7:25:24 AM
*
* Copyright 2007-2014 SolarNetwork.net Dev Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
* ==================================================================
*/
package net.solarnetwork.node.io.serial;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import net.solarnetwork.util.OptionalService;
import net.solarnetwork.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A base helper class to support {@link SerialNetwork} based services.
*
* <p>
* The configurable properties of this class are:
* </p>
*
* <dl class="class-properties">
* <dt>serialNetwork</dt>
* <dd>The {@link SerialNetwork} to use.</dd>
*
* <dt>uid</dt>
* <dd>A service name to use.</dd>
*
* <dt>groupUID</dt>
* <dd>A service group to use.</dd>
* </dl>
*
* @author matt
* @version 1.0
*/
public abstract class SerialDeviceSupport {
/** Key for the device name, as a String. */
public static final String INFO_KEY_DEVICE_NAME = "Name";
/** Key for the device model, as a String. */
public static final String INFO_KEY_DEVICE_MODEL = "Model";
/** Key for the device serial number, as a Long. */
public static final String INFO_KEY_DEVICE_SERIAL_NUMBER = "Serial Number";
/** Key for the device manufacturer, as a String. */
public static final String INFO_KEY_DEVICE_MANUFACTURER = "Manufacturer";
/**
* Key for the device manufacture date, as a
* {@link org.joda.time.ReadablePartial}.
*/
public static final String INFO_KEY_DEVICE_MANUFACTURE_DATE = "Manufacture Date";
private Map<String, Object> deviceInfo;
private String uid;
private String groupUID;
private OptionalService<SerialNetwork> serialNetwork;
/** A class-level logger. */
protected final Logger log = LoggerFactory.getLogger(getClass());
/**
* Get the {@link SerialNetwork} from the configured {@code serialNetwork}
* service, or <em>null</em> if not available or not configured.
*
* @return SerialNetwork
*/
protected final SerialNetwork serialNetwork() {
return (serialNetwork == null ? null : serialNetwork.service());
}
/**
* Read general device info and return a map of the results. See the various
* {@code INFO_KEY_*} constants for information on the values returned in
* the result map.
*
* @param conn
* the connection to use
* @return a map with general device information populated
* @throws IOException
* if any IO error occurrs
*/
protected abstract Map<String, Object> readDeviceInfo(SerialConnection conn) throws IOException;
/**
* Return an informational message composed of general device info. This
* method will call {@link #getDeviceInfo()} and return a {@code /} (forward
* slash) delimited string of the resulting values, or <em>null</em> if that
* method returns <em>null</em>.
*
* @return info message
*/
public String getDeviceInfoMessage() {
Map<String, ?> info = getDeviceInfo();
if ( info == null ) {
return null;
}
return StringUtils.delimitedStringFromCollection(info.values(), " / ");
}
/**
* Get the device info data as a Map. This method will call
* {@link #readMeterInfo(SerialConnection)}. The map is cached so subsequent
* calls will not attempt to read from the device. Note the returned map
* cannot be modified.
*
* @return the device info, or <em>null</em>
* @see #readDeviceInfo(SerialConnection)
*/
public Map<String, ?> getDeviceInfo() {
Map<String, Object> info = deviceInfo;
if ( info == null ) {
try {
info = performAction(new SerialConnectionAction<Map<String, Object>>() {
@Override
public Map<String, Object> doWithConnection(SerialConnection conn)
throws IOException {
return readDeviceInfo(conn);
}
});
deviceInfo = info;
} catch ( Exception e ) {
log.warn("Communcation problem with {}: {}", uid, e.getMessage());
}
}
return (info == null ? null : Collections.unmodifiableMap(info));
}
/**
* Perform some work with a Serial {@link SerialConnection}. This method
* attempts to obtain a {@link SerialNetwork} from the configured
* {@code serialNetwork} service, calling
* {@link SerialNetwork#performAction(SerialConnectionAction)} if one can be
* obtained.
*
* @param action
* the connection action
* @return the result of the callback, or <em>null</em> if the action is
* never invoked
*/
protected final <T> T performAction(final SerialConnectionAction<T> action) throws IOException {
T result = null;
SerialNetwork device = (serialNetwork == null ? null : serialNetwork.service());
if ( device != null ) {
result = device.performAction(action);
}
return result;
}
/**
* Get direct access to the device info data.
*
* @return the device info, or <em>null</em>
*/
protected Map<String, Object> getDeviceInfoMap() {
return deviceInfo;
}
/**
* Set the device info data. Setting the {@code deviceInfo} to <em>null</em>
* will force the next call to {@link #getDeviceInfo()} to read from the
* device to populate this data, and setting this to anything else will
* force all subsequent calls to {@link #getDeviceInfo()} to simply return
* that map.
*
* @param deviceInfo
* the device info map to set
*/
protected void setDeviceInfoMap(Map<String, Object> deviceInfo) {
this.deviceInfo = deviceInfo;
}
/**
* Get a UID value. Returns {@link #getUid()}.
*
* @return UID
*/
public String getUID() {
return getUid();
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getGroupUID() {
return groupUID;
}
public void setGroupUID(String groupUID) {
this.groupUID = groupUID;
}
public OptionalService<SerialNetwork> getSerialNetwork() {
return serialNetwork;
}
public void setSerialNetwork(OptionalService<SerialNetwork> serialDevice) {
this.serialNetwork = serialDevice;
}
}