import static org.openhab.binding.logreader.internal.LogReaderBindingConstants.THING_READER;
-import java.util.Collections;
import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@NonNullByDefault
public class LogReaderHandlerFactory extends BaseThingHandlerFactory {
- private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
- .unmodifiableSet(Stream.of(THING_READER).collect(Collectors.toSet()));
+ private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_READER);
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
*/
package org.openhab.binding.logreader.internal.config;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
/**
* Configuration class for {@link LogReaderBinding} binding.
*
* @author Pauli Anttila - Initial contribution
*/
+@NonNullByDefault
public class LogReaderConfiguration {
- public String filePath;
- public int refreshRate;
- public String warningPatterns;
- public String warningBlacklistingPatterns;
- public String errorPatterns;
- public String errorBlacklistingPatterns;
- public String customPatterns;
- public String customBlacklistingPatterns;
+ public String filePath = "${OPENHAB_LOGDIR}/openhab.log";
+ public int refreshRate = 1000;
+ public String warningPatterns = "WARN+";
+ public @Nullable String warningBlacklistingPatterns;
+ public String errorPatterns = "ERROR+";
+ public @Nullable String errorBlacklistingPatterns;
+ public @Nullable String customPatterns;
+ public @Nullable String customBlacklistingPatterns;
@Override
public String toString() {
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.logreader.internal.filereader.api.FileReaderListener;
import org.openhab.binding.logreader.internal.filereader.api.LogFileReader;
import org.slf4j.Logger;
*
* @author Pauli Anttila - Initial contribution
*/
+@NonNullByDefault
public abstract class AbstractLogFileReader implements LogFileReader {
private final Logger logger = LoggerFactory.getLogger(AbstractLogFileReader.class);
import org.apache.commons.io.input.Tailer;
import org.apache.commons.io.input.TailerListener;
import org.apache.commons.io.input.TailerListenerAdapter;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.logreader.internal.filereader.api.FileReaderException;
import org.openhab.binding.logreader.internal.filereader.api.LogFileReader;
*
* @author Pauli Anttila - Initial contribution
*/
+@NonNullByDefault
public class FileTailer extends AbstractLogFileReader implements LogFileReader {
-
private final Logger logger = LoggerFactory.getLogger(FileTailer.class);
- private Tailer tailer;
- private ExecutorService executor;
+ private @Nullable Tailer tailer;
+ private @Nullable ExecutorService executor;
TailerListener logListener = new TailerListenerAdapter() {
@Override
public void handle(@Nullable String line) {
+ if (line == null) {
+ return;
+ }
+
sendLineToListeners(line);
}
@Override
public void handle(@Nullable Exception e) {
+ if (e == null) {
+ return;
+ }
+
sendExceptionToListeners(e);
}
@Override
public void start(String filePath, long refreshRate) throws FileReaderException {
- tailer = new Tailer(new File(filePath), logListener, refreshRate, true, false, true);
+ Tailer localTailer = new Tailer(new File(filePath), logListener, refreshRate, true, false, true);
executor = Executors.newSingleThreadExecutor();
try {
logger.debug("Start executor");
- executor.execute(tailer);
+ executor.execute(localTailer);
logger.debug("Executor started");
+ this.tailer = localTailer;
} catch (Exception e) {
throw new FileReaderException(e);
}
*/
package org.openhab.binding.logreader.internal.filereader.api;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
/**
* Exception for file reader errors.
*
* @author Pauli Anttila - Initial contribution
*/
+@NonNullByDefault
public class FileReaderException extends Exception {
private static final long serialVersionUID = 1272957002073978608L;
*/
package org.openhab.binding.logreader.internal.filereader.api;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
/**
* Interface for file reader listeners.
*
* @author Pauli Anttila - Initial contribution
*/
+@NonNullByDefault
public interface FileReaderListener {
/**
*
* @param line the line.
*/
- void handle(String line);
+ void handle(@Nullable String line);
/**
* This method is called when exception has occurred.
*
* @param ex the exception.
*/
- void handle(Exception ex);
+ void handle(@Nullable Exception ex);
}
*/
package org.openhab.binding.logreader.internal.filereader.api;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
/**
* Interface for log file readers.
*
* @author Pauli Anttila - Initial contribution
*/
+@NonNullByDefault
public interface LogFileReader {
/**
import java.time.ZonedDateTime;
import java.util.regex.PatternSyntaxException;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.logreader.internal.config.LogReaderConfiguration;
import org.openhab.binding.logreader.internal.filereader.api.FileReaderListener;
import org.openhab.binding.logreader.internal.filereader.api.LogFileReader;
* @author Miika Jukka - Initial contribution
* @author Pauli Anttila - Rewrite
*/
+@NonNullByDefault
public class LogHandler extends BaseThingHandler implements FileReaderListener {
private final Logger logger = LoggerFactory.getLogger(LogHandler.class);
- private LogReaderConfiguration configuration;
+ private final LogFileReader fileReader;
- private LogFileReader fileReader;
+ private @NonNullByDefault({}) LogReaderConfiguration configuration;
- private SearchEngine errorEngine;
- private SearchEngine warningEngine;
- private SearchEngine customEngine;
+ private @Nullable SearchEngine errorEngine;
+ private @Nullable SearchEngine warningEngine;
+ private @Nullable SearchEngine customEngine;
public LogHandler(Thing thing, LogFileReader fileReader) {
super(thing);
try {
warningEngine = new SearchEngine(configuration.warningPatterns, configuration.warningBlacklistingPatterns);
errorEngine = new SearchEngine(configuration.errorPatterns, configuration.errorBlacklistingPatterns);
- customEngine = new SearchEngine(configuration.customPatterns, configuration.customBlacklistingPatterns);
-
+ String customPatterns = configuration.customPatterns;
+ customEngine = new SearchEngine(customPatterns != null ? customPatterns : "",
+ configuration.customBlacklistingPatterns);
} catch (PatternSyntaxException e) {
logger.debug("Illegal search pattern syntax '{}'. ", e.getMessage(), e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, e.getMessage());
shutdown();
}
- private void updateChannel(ChannelUID channelUID, Command command, SearchEngine matcher) {
- if (command instanceof DecimalType) {
- matcher.setMatchCount(((DecimalType) command).longValue());
- } else if (command instanceof RefreshType) {
- updateState(channelUID.getId(), new DecimalType(matcher.getMatchCount()));
+ private void updateChannel(ChannelUID channelUID, Command command, @Nullable SearchEngine matcher) {
+ if (matcher != null) {
+ if (command instanceof DecimalType) {
+ matcher.setMatchCount(((DecimalType) command).longValue());
+ } else if (command instanceof RefreshType) {
+ updateState(channelUID.getId(), new DecimalType(matcher.getMatchCount()));
+ } else {
+ logger.debug("Unsupported command '{}' received for channel '{}'", command, channelUID);
+ }
} else {
- logger.debug("Unsupported command '{}' received for channel '{}'", command, channelUID);
+ logger.debug("Cannot update channel as SearchEngine is null.");
}
}
}
@Override
- public void handle(String line) {
+ public void handle(@Nullable String line) {
if (line == null) {
return;
}
updateStatus(ThingStatus.ONLINE);
}
- if (errorEngine.isMatching(line)) {
+ if (errorEngine != null && errorEngine.isMatching(line)) {
updateChannelIfLinked(CHANNEL_ERRORS, new DecimalType(errorEngine.getMatchCount()));
updateChannelIfLinked(CHANNEL_LASTERROR, new StringType(line));
triggerChannel(CHANNEL_NEWERROR, line);
}
- if (warningEngine.isMatching(line)) {
+ if (warningEngine != null && warningEngine.isMatching(line)) {
updateChannelIfLinked(CHANNEL_WARNINGS, new DecimalType(warningEngine.getMatchCount()));
updateChannelIfLinked(CHANNEL_LASTWARNING, new StringType(line));
triggerChannel(CHANNEL_NEWWARNING, line);
}
- if (customEngine.isMatching(line)) {
+ if (customEngine != null && customEngine.isMatching(line)) {
updateChannelIfLinked(CHANNEL_CUSTOMEVENTS, new DecimalType(customEngine.getMatchCount()));
updateChannelIfLinked(CHANNEL_LASTCUSTOMEVENT, new StringType(line));
triggerChannel(CHANNEL_NEWCUSTOM, line);
}
@Override
- public void handle(Exception ex) {
+ public void handle(@Nullable Exception ex) {
final String msg = ex != null ? ex.getMessage() : "";
logger.debug("Error while trying to read log file: {}. ", msg, ex);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, msg);
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
*
* @author Pauli Anttila - Initial contribution
*/
+@NonNullByDefault
public class SearchEngine {
private List<Pattern> matchers;
* @param blacklistingPatterns search patterns to bypass results which have found by the initial search patterns.
*
*/
- public SearchEngine(String patterns, String blacklistingPatterns) throws PatternSyntaxException {
+ public SearchEngine(String patterns, @Nullable String blacklistingPatterns) throws PatternSyntaxException {
matchers = compilePatterns(patterns);
blacklistingMatchers = compilePatterns(blacklistingPatterns);
}
*/
private List<Pattern> compilePatterns(@Nullable String patterns) throws PatternSyntaxException {
List<Pattern> patternsList = new ArrayList<>();
-
if (patterns != null && !patterns.isEmpty()) {
String list[] = patterns.split("\\|");
if (list.length > 0) {
<description>Path to log file. Empty will default to ${OPENHAB_LOGDIR}/openhab.log</description>
<default>${OPENHAB_LOGDIR}/openhab.log</default>
</parameter>
- <parameter name="refreshRate" type="integer" required="false">
+ <parameter name="refreshRate" type="integer" unit="ms">
<label>Refresh Rate</label>
<description>Refresh rate in milliseconds for reading logs</description>
<default>1000</default>
</parameter>
- <parameter name="errorPatterns" type="text" required="false">
+ <parameter name="errorPatterns" type="text">
<label>Error Patterns</label>
<description>Search patterns separated by | character for error events. Empty will default to ERROR+</description>
<default>ERROR+</default>
</parameter>
- <parameter name="errorBlacklistingPatterns" type="text" required="false">
+ <parameter name="errorBlacklistingPatterns" type="text">
<label>Error Blacklisting Patterns</label>
<description>Search patterns for blacklisting unwanted error events separated by | character. </description>
</parameter>
- <parameter name="warningPatterns" type="text" required="false">
+ <parameter name="warningPatterns" type="text">
<label>Warning Patterns</label>
<description>Search patterns separated by | character for warning events. Empty will default to WARN+</description>
<default>WARN+</default>
</parameter>
- <parameter name="warningBlacklistingPatterns" type="text" required="false">
+ <parameter name="warningBlacklistingPatterns" type="text">
<label>Warning Blacklisting Patterns</label>
<description>Search patterns for blacklisting unwanted warning events separated by | character.</description>
</parameter>
- <parameter name="customPatterns" type="text" required="false">
+ <parameter name="customPatterns" type="text">
<label>Custom Patterns</label>
<description>Search patterns separated by | character for custom events.</description>
</parameter>
- <parameter name="customBlacklistingPatterns" type="text" required="false">
+ <parameter name="customBlacklistingPatterns" type="text">
<label>Custom Blacklisting Patterns</label>
<description>Search patterns for blacklisting unwanted custom events separated by | character.</description>
</parameter>